diff options
186 files changed, 3480 insertions, 798 deletions
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh index f538a4081..296b14e56 100644 --- a/.ci/scripts/linux/docker.sh +++ b/.ci/scripts/linux/docker.sh | |||
| @@ -11,4 +11,5 @@ ninja | |||
| 11 | 11 | ||
| 12 | ccache -s | 12 | ccache -s |
| 13 | 13 | ||
| 14 | ctest -VV -C Release | 14 | # Ignore zlib's tests, since they aren't gated behind a CMake option. |
| 15 | ctest -VV -E "(example|example64)" -C Release | ||
diff --git a/.ci/scripts/merge/apply-patches-by-label-private.py b/.ci/scripts/merge/apply-patches-by-label-private.py new file mode 100644 index 000000000..fe0acd510 --- /dev/null +++ b/.ci/scripts/merge/apply-patches-by-label-private.py | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | # Download all pull requests as patches that match a specific label | ||
| 2 | # Usage: python download-patches-by-label.py <Label to Match> <Root Path Folder to DL to> | ||
| 3 | |||
| 4 | import requests, sys, json, shutil, subprocess, os, traceback | ||
| 5 | |||
| 6 | org = os.getenv("PRIVATEMERGEORG", "yuzu-emu") | ||
| 7 | repo = os.getenv("PRIVATEMERGEREPO", "yuzu-private") | ||
| 8 | tagline = sys.argv[3] | ||
| 9 | user = sys.argv[1] | ||
| 10 | |||
| 11 | dl_list = {} | ||
| 12 | |||
| 13 | TAG_NAME = sys.argv[2] | ||
| 14 | |||
| 15 | def check_individual(repo_id, pr_id): | ||
| 16 | url = 'https://%sdev.azure.com/%s/%s/_apis/git/repositories/%s/pullRequests/%s/labels?api-version=5.1-preview.1' % (user, org, repo, repo_id, pr_id) | ||
| 17 | response = requests.get(url) | ||
| 18 | if (response.ok): | ||
| 19 | try: | ||
| 20 | js = response.json() | ||
| 21 | return any(tag.get('name') == TAG_NAME for tag in js['value']) | ||
| 22 | except: | ||
| 23 | return False | ||
| 24 | return False | ||
| 25 | |||
| 26 | def merge_pr(pn, ref): | ||
| 27 | print("Matched PR# %s" % pn) | ||
| 28 | print(subprocess.check_output(["git", "fetch", "https://%sdev.azure.com/%s/_git/%s" % (user, org, repo), ref, "-f"])) | ||
| 29 | print(subprocess.check_output(["git", "merge", "--squash", 'origin/' + ref.replace('refs/heads/','')])) | ||
| 30 | print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)])) | ||
| 31 | |||
| 32 | def main(): | ||
| 33 | url = 'https://%sdev.azure.com/%s/%s/_apis/git/pullrequests?api-version=5.1' % (user, org, repo) | ||
| 34 | response = requests.get(url) | ||
| 35 | if (response.ok): | ||
| 36 | js = response.json() | ||
| 37 | tagged_prs = filter(lambda pr: check_individual(pr['repository']['id'], pr['pullRequestId']), js['value']) | ||
| 38 | map(lambda pr: merge_pr(pr['pullRequestId'], pr['sourceRefName']), tagged_prs) | ||
| 39 | |||
| 40 | if __name__ == '__main__': | ||
| 41 | try: | ||
| 42 | main() | ||
| 43 | except: | ||
| 44 | traceback.print_exc(file=sys.stdout) | ||
| 45 | sys.exit(-1) | ||
diff --git a/.ci/scripts/merge/apply-patches-by-label.py b/.ci/scripts/merge/apply-patches-by-label.py index b346001a5..43ed74d7f 100644 --- a/.ci/scripts/merge/apply-patches-by-label.py +++ b/.ci/scripts/merge/apply-patches-by-label.py | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | # Download all pull requests as patches that match a specific label | 1 | # Download all pull requests as patches that match a specific label |
| 2 | # Usage: python download-patches-by-label.py <Label to Match> <Root Path Folder to DL to> | 2 | # Usage: python download-patches-by-label.py <Label to Match> <Root Path Folder to DL to> |
| 3 | 3 | ||
| 4 | import requests, sys, json, urllib3.request, shutil, subprocess | 4 | import requests, sys, json, urllib3.request, shutil, subprocess, os |
| 5 | |||
| 6 | tagline = sys.argv[2] | ||
| 5 | 7 | ||
| 6 | http = urllib3.PoolManager() | 8 | http = urllib3.PoolManager() |
| 7 | dl_list = {} | 9 | dl_list = {} |
| @@ -12,17 +14,23 @@ def check_individual(labels): | |||
| 12 | return True | 14 | return True |
| 13 | return False | 15 | return False |
| 14 | 16 | ||
| 15 | try: | 17 | def do_page(page): |
| 16 | url = 'https://api.github.com/repos/yuzu-emu/yuzu/pulls' | 18 | url = 'https://api.github.com/repos/yuzu-emu/yuzu/pulls?page=%s' % page |
| 17 | response = requests.get(url) | 19 | response = requests.get(url) |
| 18 | if (response.ok): | 20 | if (response.ok): |
| 19 | j = json.loads(response.content) | 21 | j = json.loads(response.content) |
| 22 | if j == []: | ||
| 23 | return | ||
| 20 | for pr in j: | 24 | for pr in j: |
| 21 | if (check_individual(pr["labels"])): | 25 | if (check_individual(pr["labels"])): |
| 22 | pn = pr["number"] | 26 | pn = pr["number"] |
| 23 | print("Matched PR# %s" % pn) | 27 | print("Matched PR# %s" % pn) |
| 24 | print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", "pull/%s/head:pr-%s" % (pn, pn), "-f"])) | 28 | print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", "pull/%s/head:pr-%s" % (pn, pn), "-f"])) |
| 25 | print(subprocess.check_output(["git", "merge", "--squash", "pr-%s" % pn])) | 29 | print(subprocess.check_output(["git", "merge", "--squash", "pr-%s" % pn])) |
| 26 | print(subprocess.check_output(["git", "commit", "-m\"Merge PR %s\"" % pn])) | 30 | print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)])) |
| 31 | |||
| 32 | try: | ||
| 33 | for i in range(1,30): | ||
| 34 | do_page(i) | ||
| 27 | except: | 35 | except: |
| 28 | sys.exit(-1) | 36 | sys.exit(-1) |
diff --git a/.ci/scripts/windows/upload.ps1 b/.ci/scripts/windows/upload.ps1 new file mode 100644 index 000000000..de86e7390 --- /dev/null +++ b/.ci/scripts/windows/upload.ps1 | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | $GITDATE = $(git show -s --date=short --format='%ad') -replace "-","" | ||
| 2 | $GITREV = $(git show -s --format='%h') | ||
| 3 | $RELEASE_DIST = "yuzu-windows-msvc" | ||
| 4 | |||
| 5 | $MSVC_BUILD_ZIP = "yuzu-windows-msvc-$GITDATE-$GITREV.zip" -replace " ", "" | ||
| 6 | $MSVC_BUILD_PDB = "yuzu-windows-msvc-$GITDATE-$GITREV-debugsymbols.zip" -replace " ", "" | ||
| 7 | $MSVC_SEVENZIP = "yuzu-windows-msvc-$GITDATE-$GITREV.7z" -replace " ", "" | ||
| 8 | |||
| 9 | $env:BUILD_ZIP = $MSVC_BUILD_ZIP | ||
| 10 | $env:BUILD_SYMBOLS = $MSVC_BUILD_PDB | ||
| 11 | $env:BUILD_UPDATE = $MSVC_SEVENZIP | ||
| 12 | |||
| 13 | $BUILD_DIR = ".\build\bin\Release" | ||
| 14 | |||
| 15 | mkdir pdb | ||
| 16 | Get-ChildItem "$BUILD_DIR\" -Recurse -Filter "*.pdb" | Copy-Item -destination .\pdb | ||
| 17 | 7z a -tzip $MSVC_BUILD_PDB .\pdb\*.pdb | ||
| 18 | rm "$BUILD_DIR\*.pdb" | ||
| 19 | mkdir $RELEASE_DIST | ||
| 20 | mkdir "artifacts" | ||
| 21 | |||
| 22 | Copy-Item "$BUILD_DIR\*" -Destination $RELEASE_DIST -Recurse | ||
| 23 | rm "$RELEASE_DIST\*.exe" | ||
| 24 | Get-ChildItem "$BUILD_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST | ||
| 25 | Get-ChildItem "$BUILD_DIR" -Recurse -Filter "QtWebEngineProcess*.exe" | Copy-Item -destination $RELEASE_DIST | ||
| 26 | Copy-Item .\license.txt -Destination $RELEASE_DIST | ||
| 27 | Copy-Item .\README.md -Destination $RELEASE_DIST | ||
| 28 | 7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\* | ||
| 29 | 7z a $MSVC_SEVENZIP $RELEASE_DIST | ||
| 30 | |||
| 31 | Get-ChildItem . -Filter "*.zip" | Copy-Item -destination "artifacts" | ||
| 32 | Get-ChildItem . -Filter "*.7z" | Copy-Item -destination "artifacts" \ No newline at end of file | ||
diff --git a/.ci/templates/build-mock.yml b/.ci/templates/build-mock.yml new file mode 100644 index 000000000..e7aba93de --- /dev/null +++ b/.ci/templates/build-mock.yml | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | steps: | ||
| 2 | - script: mkdir artifacts || echo 'X' > artifacts/T1.txt | ||
| 3 | - publish: artifacts | ||
| 4 | artifact: 'yuzu-$(BuildName)-$(BuildSuffix)' | ||
| 5 | displayName: 'Upload Artifacts' \ No newline at end of file | ||
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml new file mode 100644 index 000000000..906afa382 --- /dev/null +++ b/.ci/templates/build-msvc.yml | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | parameters: | ||
| 2 | artifactSource: 'true' | ||
| 3 | cache: 'false' | ||
| 4 | |||
| 5 | steps: | ||
| 6 | - script: mkdir build && cd build && set DATE=`date '+%Y.%m.%d'` && set CI=true && set AZURE_REPO_NAME=yuzu-emu/yuzu-$(BuildName) && set AZURE_REPO_TAG=$(BuildName)-$DATE && cmake -G "Visual Studio 15 2017 Win64" --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. && cd .. | ||
| 7 | displayName: 'Configure CMake' | ||
| 8 | - task: MSBuild@1 | ||
| 9 | displayName: 'Build' | ||
| 10 | inputs: | ||
| 11 | solution: 'build/yuzu.sln' | ||
| 12 | maximumCpuCount: true | ||
| 13 | configuration: release | ||
| 14 | - task: PowerShell@2 | ||
| 15 | displayName: 'Package Artifacts' | ||
| 16 | inputs: | ||
| 17 | targetType: 'filePath' | ||
| 18 | filePath: './.ci/scripts/windows/upload.ps1' | ||
| 19 | - publish: artifacts | ||
| 20 | artifact: 'yuzu-$(BuildName)-windows-msvc' | ||
| 21 | displayName: 'Upload Artifacts' | ||
diff --git a/.ci/templates/build-single.yml b/.ci/templates/build-single.yml index 357731eb9..002f5d24f 100644 --- a/.ci/templates/build-single.yml +++ b/.ci/templates/build-single.yml | |||
| @@ -7,14 +7,13 @@ steps: | |||
| 7 | displayName: 'Prepare Environment' | 7 | displayName: 'Prepare Environment' |
| 8 | inputs: | 8 | inputs: |
| 9 | dockerVersion: '17.09.0-ce' | 9 | dockerVersion: '17.09.0-ce' |
| 10 | - ${{ if eq(parameters.cache, 'true') }}: | 10 | - task: CacheBeta@0 |
| 11 | - task: CacheBeta@0 | 11 | displayName: 'Cache Build System' |
| 12 | displayName: 'Cache Build System' | 12 | inputs: |
| 13 | inputs: | 13 | key: yuzu-v1-$(BuildName)-$(BuildSuffix)-$(CacheSuffix) |
| 14 | key: yuzu-v1-$(BuildName)-$(BuildSuffix)-$(CacheSuffix) | 14 | path: $(System.DefaultWorkingDirectory)/ccache |
| 15 | path: $(System.DefaultWorkingDirectory)/ccache | 15 | cacheHitVar: CACHE_RESTORED |
| 16 | cacheHitVar: CACHE_RESTORED | 16 | - script: export DATE=`date '+%Y.%m.%d'` && export CI=true && export AZURE_REPO_NAME=yuzu-emu/yuzu-$(BuildName) && export AZURE_REPO_TAG=$(BuildName)-$DATE && chmod a+x ./.ci/scripts/$(ScriptFolder)/exec.sh && ./.ci/scripts/$(ScriptFolder)/exec.sh |
| 17 | - script: chmod a+x ./.ci/scripts/$(ScriptFolder)/exec.sh && ./.ci/scripts/$(ScriptFolder)/exec.sh | ||
| 18 | displayName: 'Build' | 17 | displayName: 'Build' |
| 19 | - script: chmod a+x ./.ci/scripts/$(ScriptFolder)/upload.sh && RELEASE_NAME=$(BuildName) ./.ci/scripts/$(ScriptFolder)/upload.sh | 18 | - script: chmod a+x ./.ci/scripts/$(ScriptFolder)/upload.sh && RELEASE_NAME=$(BuildName) ./.ci/scripts/$(ScriptFolder)/upload.sh |
| 20 | displayName: 'Package Artifacts' | 19 | displayName: 'Package Artifacts' |
diff --git a/.ci/templates/merge-private.yml b/.ci/templates/merge-private.yml new file mode 100644 index 000000000..a640cfbde --- /dev/null +++ b/.ci/templates/merge-private.yml | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | jobs: | ||
| 2 | - job: merge | ||
| 3 | displayName: 'pull requests' | ||
| 4 | steps: | ||
| 5 | - checkout: self | ||
| 6 | submodules: recursive | ||
| 7 | - template: ./mergebot-private.yml | ||
| 8 | parameters: | ||
| 9 | matchLabel: '$(BuildName)-merge' | ||
| 10 | matchLabelPublic: '$(PublicBuildName)-merge' | ||
| 11 | - task: ArchiveFiles@2 | ||
| 12 | displayName: 'Package Source' | ||
| 13 | inputs: | ||
| 14 | rootFolderOrFile: '$(System.DefaultWorkingDirectory)' | ||
| 15 | includeRootFolder: false | ||
| 16 | archiveType: '7z' | ||
| 17 | archiveFile: '$(Build.ArtifactStagingDirectory)/yuzu-$(BuildName)-source.7z' | ||
| 18 | - task: PublishPipelineArtifact@1 | ||
| 19 | displayName: 'Upload Artifacts' | ||
| 20 | inputs: | ||
| 21 | targetPath: '$(Build.ArtifactStagingDirectory)/yuzu-$(BuildName)-source.7z' | ||
| 22 | artifact: 'yuzu-$(BuildName)-source' | ||
| 23 | replaceExistingArchive: true | ||
| 24 | - job: upload_source | ||
| 25 | displayName: 'upload' | ||
| 26 | dependsOn: merge | ||
| 27 | steps: | ||
| 28 | - template: ./sync-source.yml | ||
| 29 | parameters: | ||
| 30 | artifactSource: 'true' | ||
| 31 | needSubmodules: 'true' | ||
| 32 | - script: chmod a+x $(System.DefaultWorkingDirectory)/.ci/scripts/merge/yuzubot-git-config.sh && $(System.DefaultWorkingDirectory)/.ci/scripts/merge/yuzubot-git-config.sh | ||
| 33 | displayName: 'Apply Git Configuration' | ||
| 34 | - script: git tag -a $(BuildName)-$(Build.BuildId) -m "yuzu $(BuildName) $(Build.BuildNumber) $(Build.DefinitionName)" | ||
| 35 | displayName: 'Tag Source' | ||
| 36 | - script: git remote add other $(GitRepoPushChangesURL) | ||
| 37 | displayName: 'Register Repository' | ||
| 38 | - script: git push --follow-tags --force other HEAD:$(GitPushBranch) | ||
| 39 | displayName: 'Update Code' | ||
| 40 | - script: git rev-list -n 1 $(BuildName)-$(Build.BuildId) > $(Build.ArtifactStagingDirectory)/tag-commit.sha | ||
| 41 | displayName: 'Calculate Release Point' | ||
| 42 | - task: PublishPipelineArtifact@1 | ||
| 43 | displayName: 'Upload Release Point' | ||
| 44 | inputs: | ||
| 45 | targetPath: '$(Build.ArtifactStagingDirectory)/tag-commit.sha' | ||
| 46 | artifact: 'yuzu-$(BuildName)-release-point' | ||
| 47 | replaceExistingArchive: true \ No newline at end of file | ||
diff --git a/.ci/templates/mergebot-private.yml b/.ci/templates/mergebot-private.yml new file mode 100644 index 000000000..f9a40cf61 --- /dev/null +++ b/.ci/templates/mergebot-private.yml | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | parameters: | ||
| 2 | matchLabel: 'dummy-merge' | ||
| 3 | matchLabelPublic: 'dummy-merge' | ||
| 4 | |||
| 5 | steps: | ||
| 6 | - script: mkdir $(System.DefaultWorkingDirectory)/patches && pip install requests urllib3 | ||
| 7 | displayName: 'Prepare Environment' | ||
| 8 | - script: chmod a+x $(System.DefaultWorkingDirectory)/.ci/scripts/merge/yuzubot-git-config.sh && $(System.DefaultWorkingDirectory)/.ci/scripts/merge/yuzubot-git-config.sh | ||
| 9 | displayName: 'Apply Git Configuration' | ||
| 10 | - task: PythonScript@0 | ||
| 11 | displayName: 'Discover, Download, and Apply Patches (Mainline)' | ||
| 12 | inputs: | ||
| 13 | scriptSource: 'filePath' | ||
| 14 | scriptPath: '.ci/scripts/merge/apply-patches-by-label.py' | ||
| 15 | arguments: '${{ parameters.matchLabelPublic }} $(MergeTaglinePublic) patches-public' | ||
| 16 | workingDirectory: '$(System.DefaultWorkingDirectory)' | ||
| 17 | - task: PythonScript@0 | ||
| 18 | displayName: 'Discover, Download, and Apply Patches (Patreon Public)' | ||
| 19 | inputs: | ||
| 20 | scriptSource: 'filePath' | ||
| 21 | scriptPath: '.ci/scripts/merge/apply-patches-by-label.py' | ||
| 22 | arguments: '${{ parameters.matchLabel }} "$(MergeTaglinePrivate) Public" patches-mixed-public' | ||
| 23 | workingDirectory: '$(System.DefaultWorkingDirectory)' | ||
| 24 | - task: PythonScript@0 | ||
| 25 | displayName: 'Discover, Download, and Apply Patches (Patreon Private)' | ||
| 26 | inputs: | ||
| 27 | scriptSource: 'filePath' | ||
| 28 | scriptPath: '.ci/scripts/merge/apply-patches-by-label-private.py' | ||
| 29 | arguments: '$(PrivateMergeUser) ${{ parameters.matchLabel }} "$(MergeTaglinePrivate) Private" patches-private' | ||
| 30 | workingDirectory: '$(System.DefaultWorkingDirectory)' | ||
diff --git a/.ci/templates/mergebot.yml b/.ci/templates/mergebot.yml index 5211efcc6..a4c5c2a28 100644 --- a/.ci/templates/mergebot.yml +++ b/.ci/templates/mergebot.yml | |||
| @@ -11,5 +11,5 @@ steps: | |||
| 11 | inputs: | 11 | inputs: |
| 12 | scriptSource: 'filePath' | 12 | scriptSource: 'filePath' |
| 13 | scriptPath: '.ci/scripts/merge/apply-patches-by-label.py' | 13 | scriptPath: '.ci/scripts/merge/apply-patches-by-label.py' |
| 14 | arguments: '${{ parameters.matchLabel }} patches' | 14 | arguments: '${{ parameters.matchLabel }} Tagged patches' |
| 15 | workingDirectory: '$(System.DefaultWorkingDirectory)' | 15 | workingDirectory: '$(System.DefaultWorkingDirectory)' |
diff --git a/.ci/templates/release-download.yml b/.ci/templates/release-download.yml new file mode 100644 index 000000000..f7e30690f --- /dev/null +++ b/.ci/templates/release-download.yml | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | steps: | ||
| 2 | - task: DownloadPipelineArtifact@2 | ||
| 3 | displayName: 'Download Windows Release' | ||
| 4 | inputs: | ||
| 5 | artifactName: 'yuzu-$(BuildName)-windows-msvc' | ||
| 6 | buildType: 'current' | ||
| 7 | targetPath: '$(Build.ArtifactStagingDirectory)' | ||
| 8 | - task: DownloadPipelineArtifact@2 | ||
| 9 | displayName: 'Download Linux Release' | ||
| 10 | inputs: | ||
| 11 | artifactName: 'yuzu-$(BuildName)-linux' | ||
| 12 | buildType: 'current' | ||
| 13 | targetPath: '$(Build.ArtifactStagingDirectory)' \ No newline at end of file | ||
diff --git a/.ci/templates/release-github.yml b/.ci/templates/release-github.yml new file mode 100644 index 000000000..39fd47f1c --- /dev/null +++ b/.ci/templates/release-github.yml | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | steps: | ||
| 2 | - template: ./release-download.yml | ||
| 3 | - task: GitHubRelease@0 | ||
| 4 | inputs: | ||
| 5 | action: 'create' | ||
| 6 | title: 'yuzu $(BuildName) #$(Build.BuildId)' | ||
| 7 | assets: '$(Build.ArtifactStagingDirectory)/*' | ||
| 8 | gitHubConnection: $(GitHubReleaseConnectionName) | ||
| 9 | repositoryName: '$(Build.Repository.Name)' | ||
| 10 | target: '$(Build.SourceVersion)' | ||
| 11 | tagSource: 'auto' \ No newline at end of file | ||
diff --git a/.ci/templates/release-universal.yml b/.ci/templates/release-universal.yml new file mode 100644 index 000000000..707697007 --- /dev/null +++ b/.ci/templates/release-universal.yml | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | steps: | ||
| 2 | - template: ./release-download.yml | ||
| 3 | - task: UniversalPackages@0 | ||
| 4 | displayName: Publish Artifacts | ||
| 5 | inputs: | ||
| 6 | command: publish | ||
| 7 | publishDirectory: '$(Build.ArtifactStagingDirectory)' | ||
| 8 | vstsFeedPublish: 'yuzu-$(BuildName)' | ||
| 9 | vstsFeedPackagePublish: 'main' | ||
| 10 | packagePublishDescription: 'Yuzu Windows and Linux Executable Packages' \ No newline at end of file | ||
diff --git a/.ci/yuzu-mainline-step1.yml b/.ci/yuzu-mainline-step1.yml new file mode 100644 index 000000000..3fd33d75a --- /dev/null +++ b/.ci/yuzu-mainline-step1.yml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | trigger: | ||
| 2 | - master | ||
| 3 | |||
| 4 | stages: | ||
| 5 | - stage: merge | ||
| 6 | displayName: 'merge' | ||
| 7 | jobs: | ||
| 8 | - template: ./templates/merge.yml | ||
diff --git a/.ci/yuzu-mainline-step2.yml b/.ci/yuzu-mainline-step2.yml new file mode 100644 index 000000000..0c1af397b --- /dev/null +++ b/.ci/yuzu-mainline-step2.yml | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | trigger: | ||
| 2 | - master | ||
| 3 | |||
| 4 | stages: | ||
| 5 | - stage: format | ||
| 6 | displayName: 'format' | ||
| 7 | jobs: | ||
| 8 | - job: format | ||
| 9 | displayName: 'clang' | ||
| 10 | pool: | ||
| 11 | vmImage: ubuntu-latest | ||
| 12 | steps: | ||
| 13 | - template: ./templates/format-check.yml | ||
| 14 | - stage: build | ||
| 15 | dependsOn: format | ||
| 16 | displayName: 'build' | ||
| 17 | jobs: | ||
| 18 | - job: build | ||
| 19 | displayName: 'standard' | ||
| 20 | pool: | ||
| 21 | vmImage: ubuntu-latest | ||
| 22 | strategy: | ||
| 23 | maxParallel: 10 | ||
| 24 | matrix: | ||
| 25 | linux: | ||
| 26 | BuildSuffix: 'linux' | ||
| 27 | ScriptFolder: 'linux' | ||
| 28 | steps: | ||
| 29 | - template: ./templates/sync-source.yml | ||
| 30 | parameters: | ||
| 31 | artifactSource: $(parameters.artifactSource) | ||
| 32 | needSubmodules: 'true' | ||
| 33 | - template: ./templates/build-single.yml | ||
| 34 | parameters: | ||
| 35 | artifactSource: 'false' | ||
| 36 | cache: 'true' | ||
| 37 | - stage: build_win | ||
| 38 | dependsOn: format | ||
| 39 | displayName: 'build-windows' | ||
| 40 | jobs: | ||
| 41 | - job: build | ||
| 42 | displayName: 'msvc' | ||
| 43 | pool: | ||
| 44 | vmImage: vs2017-win2016 | ||
| 45 | steps: | ||
| 46 | - template: ./templates/sync-source.yml | ||
| 47 | parameters: | ||
| 48 | artifactSource: $(parameters.artifactSource) | ||
| 49 | needSubmodules: 'true' | ||
| 50 | - template: ./templates/build-msvc.yml | ||
| 51 | parameters: | ||
| 52 | artifactSource: 'false' | ||
| 53 | cache: 'true' | ||
| 54 | - stage: release | ||
| 55 | displayName: 'Release' | ||
| 56 | dependsOn: | ||
| 57 | - build | ||
| 58 | - build_win | ||
| 59 | jobs: | ||
| 60 | - job: github | ||
| 61 | displayName: 'GitHub Release' | ||
| 62 | steps: | ||
| 63 | - template: ./templates/release-github.yml \ No newline at end of file | ||
diff --git a/.ci/yuzu-mainline.yml b/.ci/yuzu-mainline.yml deleted file mode 100644 index 2930a8564..000000000 --- a/.ci/yuzu-mainline.yml +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | trigger: | ||
| 2 | - master | ||
| 3 | |||
| 4 | stages: | ||
| 5 | - stage: merge | ||
| 6 | displayName: 'merge' | ||
| 7 | jobs: | ||
| 8 | - template: ./templates/merge.yml | ||
| 9 | - stage: format | ||
| 10 | dependsOn: merge | ||
| 11 | displayName: 'format' | ||
| 12 | jobs: | ||
| 13 | - job: format | ||
| 14 | displayName: 'clang' | ||
| 15 | pool: | ||
| 16 | vmImage: ubuntu-latest | ||
| 17 | steps: | ||
| 18 | - template: ./templates/format-check.yml | ||
| 19 | - stage: build | ||
| 20 | displayName: 'build' | ||
| 21 | dependsOn: format | ||
| 22 | jobs: | ||
| 23 | - template: ./templates/build-standard.yml | ||
| 24 | parameters: | ||
| 25 | cache: 'true' | ||
diff --git a/.ci/yuzu-patreon-step1.yml b/.ci/yuzu-patreon-step1.yml new file mode 100644 index 000000000..cf30397cd --- /dev/null +++ b/.ci/yuzu-patreon-step1.yml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | trigger: | ||
| 2 | - master | ||
| 3 | |||
| 4 | stages: | ||
| 5 | - stage: merge | ||
| 6 | displayName: 'merge' | ||
| 7 | jobs: | ||
| 8 | - template: ./templates/merge-private.yml | ||
diff --git a/.ci/yuzu-patreon-step2.yml b/.ci/yuzu-patreon-step2.yml new file mode 100644 index 000000000..23e45d9dd --- /dev/null +++ b/.ci/yuzu-patreon-step2.yml | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | trigger: | ||
| 2 | - master | ||
| 3 | |||
| 4 | stages: | ||
| 5 | - stage: format | ||
| 6 | displayName: 'format' | ||
| 7 | jobs: | ||
| 8 | - job: format | ||
| 9 | displayName: 'clang' | ||
| 10 | pool: | ||
| 11 | vmImage: ubuntu-latest | ||
| 12 | steps: | ||
| 13 | - template: ./templates/format-check.yml | ||
| 14 | - stage: build | ||
| 15 | dependsOn: format | ||
| 16 | displayName: 'build' | ||
| 17 | jobs: | ||
| 18 | - job: build | ||
| 19 | displayName: 'windows-msvc' | ||
| 20 | pool: | ||
| 21 | vmImage: vs2017-win2016 | ||
| 22 | steps: | ||
| 23 | - template: ./templates/sync-source.yml | ||
| 24 | parameters: | ||
| 25 | artifactSource: $(parameters.artifactSource) | ||
| 26 | needSubmodules: 'true' | ||
| 27 | - template: ./templates/build-msvc.yml | ||
| 28 | parameters: | ||
| 29 | artifactSource: 'false' | ||
| 30 | cache: $(parameters.cache) | ||
diff --git a/.ci/yuzu-patreon.yml b/.ci/yuzu-patreon.yml deleted file mode 100644 index aa912913d..000000000 --- a/.ci/yuzu-patreon.yml +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | # Starter pipeline | ||
| 2 | # Start with a minimal pipeline that you can customize to build and deploy your code. | ||
| 3 | # Add steps that build, run tests, deploy, and more: | ||
| 4 | # https://aka.ms/yaml | ||
| 5 | |||
| 6 | trigger: | ||
| 7 | - master | ||
| 8 | |||
| 9 | pool: | ||
| 10 | vmImage: 'ubuntu-latest' | ||
| 11 | |||
| 12 | steps: | ||
| 13 | - script: echo Hello, world! | ||
| 14 | displayName: 'Run a one-line script' | ||
| 15 | |||
| 16 | - script: | | ||
| 17 | echo Add other tasks to build, test, and deploy your project. | ||
| 18 | echo See https://aka.ms/yaml | ||
| 19 | displayName: 'Run a multi-line script' | ||
diff --git a/.gitmodules b/.gitmodules index 3a49c4874..35e0d1240 100644 --- a/.gitmodules +++ b/.gitmodules | |||
| @@ -46,3 +46,9 @@ | |||
| 46 | [submodule "sirit"] | 46 | [submodule "sirit"] |
| 47 | path = externals/sirit | 47 | path = externals/sirit |
| 48 | url = https://github.com/ReinUsesLisp/sirit | 48 | url = https://github.com/ReinUsesLisp/sirit |
| 49 | [submodule "libzip"] | ||
| 50 | path = externals/libzip | ||
| 51 | url = https://github.com/DarkLordZach/libzip | ||
| 52 | [submodule "zlib"] | ||
| 53 | path = externals/zlib | ||
| 54 | url = https://github.com/madler/zlib | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index bfa104034..9b3b0d6d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -21,6 +21,8 @@ option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON) | |||
| 21 | 21 | ||
| 22 | option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) | 22 | option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) |
| 23 | 23 | ||
| 24 | option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON) | ||
| 25 | |||
| 24 | option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) | 26 | option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) |
| 25 | 27 | ||
| 26 | option(ENABLE_VULKAN "Enables Vulkan backend" ON) | 28 | option(ENABLE_VULKAN "Enables Vulkan backend" ON) |
| @@ -1,7 +1,6 @@ | |||
| 1 | yuzu emulator | 1 | yuzu emulator |
| 2 | ============= | 2 | ============= |
| 3 | [](https://travis-ci.org/yuzu-emu/yuzu) | 3 | [](https://travis-ci.org/yuzu-emu/yuzu) |
| 4 | [](https://ci.appveyor.com/project/bunnei/yuzu) | ||
| 5 | [](https://dev.azure.com/yuzu-emu/yuzu/) | 4 | [](https://dev.azure.com/yuzu-emu/yuzu/) |
| 6 | 5 | ||
| 7 | yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/). | 6 | yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/). |
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index e6fa11a03..3539828b8 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt | |||
| @@ -77,6 +77,12 @@ if (ENABLE_VULKAN) | |||
| 77 | add_subdirectory(sirit) | 77 | add_subdirectory(sirit) |
| 78 | endif() | 78 | endif() |
| 79 | 79 | ||
| 80 | # zlib | ||
| 81 | add_subdirectory(zlib EXCLUDE_FROM_ALL) | ||
| 82 | |||
| 83 | # libzip | ||
| 84 | add_subdirectory(libzip EXCLUDE_FROM_ALL) | ||
| 85 | |||
| 80 | if (ENABLE_WEB_SERVICE) | 86 | if (ENABLE_WEB_SERVICE) |
| 81 | # LibreSSL | 87 | # LibreSSL |
| 82 | set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "") | 88 | set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "") |
diff --git a/externals/fmt b/externals/fmt | |||
| Subproject 7512a55aa3ae309587ca89668ef9ec4074a51a1 | Subproject 4b8f8fac96a7819f28f4be523ca10a2d5d8aaaf | ||
diff --git a/externals/libzip b/externals/libzip new file mode 160000 | |||
| Subproject bd7a8103e96bc6d50164447f6b7b57bb786d8e2 | |||
diff --git a/externals/zlib b/externals/zlib new file mode 160000 | |||
| Subproject cacf7f1d4e3d44d871b605da3b647f07d718623 | |||
diff --git a/license.txt b/license.txt index 2b858f9a7..bf5aec0e6 100644 --- a/license.txt +++ b/license.txt | |||
| @@ -341,15 +341,24 @@ Public License instead of this License. | |||
| 341 | 341 | ||
| 342 | The icons used in this project have the following licenses: | 342 | The icons used in this project have the following licenses: |
| 343 | 343 | ||
| 344 | Icon Name | License | Origin/Author | 344 | Icon Name | License | Origin/Author |
| 345 | --- | --- | --- | 345 | --- | --- | --- |
| 346 | checked.png | Free for non-commercial use | 346 | checked.png | Free for non-commercial use |
| 347 | failed.png | Free for non-commercial use | 347 | failed.png | Free for non-commercial use |
| 348 | lock.png | CC BY-ND 3.0 | https://icons8.com | 348 | lock.png | CC BY-ND 3.0 | https://icons8.com |
| 349 | plus_folder.png | CC BY-ND 3.0 | https://icons8.com | 349 | plus_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com |
| 350 | bad_folder.png | CC BY-ND 3.0 | https://icons8.com | 350 | bad_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com |
| 351 | chip.png | CC BY-ND 3.0 | https://icons8.com | 351 | chip.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com |
| 352 | folder.png | CC BY-ND 3.0 | https://icons8.com | 352 | folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com |
| 353 | plus.png (Default, Dark) | CC0 1.0 | Designed by BreadFish64 from the Citra team | 353 | plus.png (Default, Dark) | CC0 1.0 | Designed by BreadFish64 from the Citra team |
| 354 | plus.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | 354 | sd_card.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com |
| 355 | sd_card.png | CC BY-ND 3.0 | https://icons8.com | 355 | plus_folder.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com |
| 356 | bad_folder.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | ||
| 357 | chip.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | ||
| 358 | folder.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | ||
| 359 | plus.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | ||
| 360 | sd_card.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com | ||
| 361 | |||
| 362 | Note: | ||
| 363 | Some icons are different in different themes, and they are separately listed | ||
| 364 | only when they have different licenses/origins. | ||
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index da50a0bbc..e6f38d600 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp | |||
| @@ -107,6 +107,11 @@ Stream::State AudioRenderer::GetStreamState() const { | |||
| 107 | return stream->GetState(); | 107 | return stream->GetState(); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static constexpr u32 VersionFromRevision(u32_le rev) { | ||
| 111 | // "REV7" -> 7 | ||
| 112 | return ((rev >> 24) & 0xff) - 0x30; | ||
| 113 | } | ||
| 114 | |||
| 110 | std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) { | 115 | std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) { |
| 111 | // Copy UpdateDataHeader struct | 116 | // Copy UpdateDataHeader struct |
| 112 | UpdateDataHeader config{}; | 117 | UpdateDataHeader config{}; |
| @@ -166,6 +171,11 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_ | |||
| 166 | // Copy output header | 171 | // Copy output header |
| 167 | UpdateDataHeader response_data{worker_params}; | 172 | UpdateDataHeader response_data{worker_params}; |
| 168 | std::vector<u8> output_params(response_data.total_size); | 173 | std::vector<u8> output_params(response_data.total_size); |
| 174 | const auto audren_revision = VersionFromRevision(config.revision); | ||
| 175 | if (audren_revision >= 5) { | ||
| 176 | response_data.frame_count = 0x10; | ||
| 177 | response_data.total_size += 0x10; | ||
| 178 | } | ||
| 169 | std::memcpy(output_params.data(), &response_data, sizeof(UpdateDataHeader)); | 179 | std::memcpy(output_params.data(), &response_data, sizeof(UpdateDataHeader)); |
| 170 | 180 | ||
| 171 | // Copy output memory pool entries | 181 | // Copy output memory pool entries |
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index 45afbe759..4f14b91cd 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h | |||
| @@ -194,21 +194,24 @@ struct UpdateDataHeader { | |||
| 194 | mixes_size = 0x0; | 194 | mixes_size = 0x0; |
| 195 | sinks_size = config.sink_count * 0x20; | 195 | sinks_size = config.sink_count * 0x20; |
| 196 | performance_manager_size = 0x10; | 196 | performance_manager_size = 0x10; |
| 197 | frame_count = 0; | ||
| 197 | total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size + voices_size + | 198 | total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size + voices_size + |
| 198 | effects_size + sinks_size + performance_manager_size; | 199 | effects_size + sinks_size + performance_manager_size; |
| 199 | } | 200 | } |
| 200 | 201 | ||
| 201 | u32_le revision; | 202 | u32_le revision{}; |
| 202 | u32_le behavior_size; | 203 | u32_le behavior_size{}; |
| 203 | u32_le memory_pools_size; | 204 | u32_le memory_pools_size{}; |
| 204 | u32_le voices_size; | 205 | u32_le voices_size{}; |
| 205 | u32_le voice_resource_size; | 206 | u32_le voice_resource_size{}; |
| 206 | u32_le effects_size; | 207 | u32_le effects_size{}; |
| 207 | u32_le mixes_size; | 208 | u32_le mixes_size{}; |
| 208 | u32_le sinks_size; | 209 | u32_le sinks_size{}; |
| 209 | u32_le performance_manager_size; | 210 | u32_le performance_manager_size{}; |
| 210 | INSERT_PADDING_WORDS(6); | 211 | INSERT_PADDING_WORDS(1); |
| 211 | u32_le total_size; | 212 | u32_le frame_count{}; |
| 213 | INSERT_PADDING_WORDS(4); | ||
| 214 | u32_le total_size{}; | ||
| 212 | }; | 215 | }; |
| 213 | static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size"); | 216 | static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size"); |
| 214 | 217 | ||
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 01abdb3bb..dfed8b51d 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -10,6 +10,9 @@ if (DEFINED ENV{CI}) | |||
| 10 | elseif(DEFINED ENV{APPVEYOR}) | 10 | elseif(DEFINED ENV{APPVEYOR}) |
| 11 | set(BUILD_REPOSITORY $ENV{APPVEYOR_REPO_NAME}) | 11 | set(BUILD_REPOSITORY $ENV{APPVEYOR_REPO_NAME}) |
| 12 | set(BUILD_TAG $ENV{APPVEYOR_REPO_TAG_NAME}) | 12 | set(BUILD_TAG $ENV{APPVEYOR_REPO_TAG_NAME}) |
| 13 | elseif(DEFINED ENV{AZURE}) | ||
| 14 | set(BUILD_REPOSITORY $ENV{AZURE_REPO_NAME}) | ||
| 15 | set(BUILD_TAG $ENV{AZURE_REPO_TAG}) | ||
| 13 | endif() | 16 | endif() |
| 14 | endif() | 17 | endif() |
| 15 | add_custom_command(OUTPUT scm_rev.cpp | 18 | add_custom_command(OUTPUT scm_rev.cpp |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a6b56c9c6..3416854db 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | if (YUZU_ENABLE_BOXCAT) | ||
| 2 | set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h) | ||
| 3 | else() | ||
| 4 | set(BCAT_BOXCAT_ADDITIONAL_SOURCES) | ||
| 5 | endif() | ||
| 6 | |||
| 1 | add_library(core STATIC | 7 | add_library(core STATIC |
| 2 | arm/arm_interface.h | 8 | arm/arm_interface.h |
| 3 | arm/arm_interface.cpp | 9 | arm/arm_interface.cpp |
| @@ -82,6 +88,8 @@ add_library(core STATIC | |||
| 82 | file_sys/vfs_concat.h | 88 | file_sys/vfs_concat.h |
| 83 | file_sys/vfs_layered.cpp | 89 | file_sys/vfs_layered.cpp |
| 84 | file_sys/vfs_layered.h | 90 | file_sys/vfs_layered.h |
| 91 | file_sys/vfs_libzip.cpp | ||
| 92 | file_sys/vfs_libzip.h | ||
| 85 | file_sys/vfs_offset.cpp | 93 | file_sys/vfs_offset.cpp |
| 86 | file_sys/vfs_offset.h | 94 | file_sys/vfs_offset.h |
| 87 | file_sys/vfs_real.cpp | 95 | file_sys/vfs_real.cpp |
| @@ -241,6 +249,9 @@ add_library(core STATIC | |||
| 241 | hle/service/audio/errors.h | 249 | hle/service/audio/errors.h |
| 242 | hle/service/audio/hwopus.cpp | 250 | hle/service/audio/hwopus.cpp |
| 243 | hle/service/audio/hwopus.h | 251 | hle/service/audio/hwopus.h |
| 252 | hle/service/bcat/backend/backend.cpp | ||
| 253 | hle/service/bcat/backend/backend.h | ||
| 254 | ${BCAT_BOXCAT_ADDITIONAL_SOURCES} | ||
| 244 | hle/service/bcat/bcat.cpp | 255 | hle/service/bcat/bcat.cpp |
| 245 | hle/service/bcat/bcat.h | 256 | hle/service/bcat/bcat.h |
| 246 | hle/service/bcat/module.cpp | 257 | hle/service/bcat/module.cpp |
| @@ -499,6 +510,15 @@ create_target_directory_groups(core) | |||
| 499 | 510 | ||
| 500 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) | 511 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) |
| 501 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives) | 512 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives) |
| 513 | |||
| 514 | if (YUZU_ENABLE_BOXCAT) | ||
| 515 | get_directory_property(OPENSSL_LIBS | ||
| 516 | DIRECTORY ${PROJECT_SOURCE_DIR}/externals/libressl | ||
| 517 | DEFINITION OPENSSL_LIBS) | ||
| 518 | target_compile_definitions(core PRIVATE -DCPPHTTPLIB_OPENSSL_SUPPORT -DYUZU_ENABLE_BOXCAT) | ||
| 519 | target_link_libraries(core PRIVATE httplib json-headers ${OPENSSL_LIBS} zip) | ||
| 520 | endif() | ||
| 521 | |||
| 502 | if (ENABLE_WEB_SERVICE) | 522 | if (ENABLE_WEB_SERVICE) |
| 503 | target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) | 523 | target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) |
| 504 | target_link_libraries(core PRIVATE web_service) | 524 | target_link_libraries(core PRIVATE web_service) |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 76bb2bae9..75a7ffb97 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -163,6 +163,7 @@ struct System::Impl { | |||
| 163 | gpu_core = VideoCore::CreateGPU(system); | 163 | gpu_core = VideoCore::CreateGPU(system); |
| 164 | 164 | ||
| 165 | is_powered_on = true; | 165 | is_powered_on = true; |
| 166 | exit_lock = false; | ||
| 166 | 167 | ||
| 167 | LOG_DEBUG(Core, "Initialized OK"); | 168 | LOG_DEBUG(Core, "Initialized OK"); |
| 168 | 169 | ||
| @@ -249,6 +250,7 @@ struct System::Impl { | |||
| 249 | perf_stats->GetMeanFrametime()); | 250 | perf_stats->GetMeanFrametime()); |
| 250 | 251 | ||
| 251 | is_powered_on = false; | 252 | is_powered_on = false; |
| 253 | exit_lock = false; | ||
| 252 | 254 | ||
| 253 | // Shutdown emulation session | 255 | // Shutdown emulation session |
| 254 | renderer.reset(); | 256 | renderer.reset(); |
| @@ -333,9 +335,11 @@ struct System::Impl { | |||
| 333 | std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager; | 335 | std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager; |
| 334 | CpuCoreManager cpu_core_manager; | 336 | CpuCoreManager cpu_core_manager; |
| 335 | bool is_powered_on = false; | 337 | bool is_powered_on = false; |
| 338 | bool exit_lock = false; | ||
| 336 | 339 | ||
| 337 | std::unique_ptr<Memory::CheatEngine> cheat_engine; | 340 | std::unique_ptr<Memory::CheatEngine> cheat_engine; |
| 338 | std::unique_ptr<Tools::Freezer> memory_freezer; | 341 | std::unique_ptr<Tools::Freezer> memory_freezer; |
| 342 | std::array<u8, 0x20> build_id{}; | ||
| 339 | 343 | ||
| 340 | /// Frontend applets | 344 | /// Frontend applets |
| 341 | Service::AM::Applets::AppletManager applet_manager; | 345 | Service::AM::Applets::AppletManager applet_manager; |
| @@ -629,6 +633,22 @@ const Service::APM::Controller& System::GetAPMController() const { | |||
| 629 | return impl->apm_controller; | 633 | return impl->apm_controller; |
| 630 | } | 634 | } |
| 631 | 635 | ||
| 636 | void System::SetExitLock(bool locked) { | ||
| 637 | impl->exit_lock = locked; | ||
| 638 | } | ||
| 639 | |||
| 640 | bool System::GetExitLock() const { | ||
| 641 | return impl->exit_lock; | ||
| 642 | } | ||
| 643 | |||
| 644 | void System::SetCurrentProcessBuildID(std::array<u8, 32> id) { | ||
| 645 | impl->build_id = id; | ||
| 646 | } | ||
| 647 | |||
| 648 | const std::array<u8, 32>& System::GetCurrentProcessBuildID() const { | ||
| 649 | return impl->build_id; | ||
| 650 | } | ||
| 651 | |||
| 632 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | 652 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { |
| 633 | return impl->Init(*this, emu_window); | 653 | return impl->Init(*this, emu_window); |
| 634 | } | 654 | } |
diff --git a/src/core/core.h b/src/core/core.h index d2a3c82d8..f49b7fbf9 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -326,6 +326,14 @@ public: | |||
| 326 | 326 | ||
| 327 | const Service::APM::Controller& GetAPMController() const; | 327 | const Service::APM::Controller& GetAPMController() const; |
| 328 | 328 | ||
| 329 | void SetExitLock(bool locked); | ||
| 330 | |||
| 331 | bool GetExitLock() const; | ||
| 332 | |||
| 333 | void SetCurrentProcessBuildID(std::array<u8, 0x20> id); | ||
| 334 | |||
| 335 | const std::array<u8, 0x20>& GetCurrentProcessBuildID() const; | ||
| 336 | |||
| 329 | private: | 337 | private: |
| 330 | System(); | 338 | System(); |
| 331 | 339 | ||
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 46aceec3d..222fc95ba 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -423,7 +423,7 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) { | |||
| 423 | std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, | 423 | std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, |
| 424 | const RSAKeyPair<2048>& key) { | 424 | const RSAKeyPair<2048>& key) { |
| 425 | const auto issuer = ticket.GetData().issuer; | 425 | const auto issuer = ticket.GetData().issuer; |
| 426 | if (issuer == std::array<u8, 0x40>{}) | 426 | if (IsAllZeroArray(issuer)) |
| 427 | return {}; | 427 | return {}; |
| 428 | if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { | 428 | if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { |
| 429 | LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority."); | 429 | LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority."); |
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 8f758d6d9..0af44f340 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp | |||
| @@ -136,4 +136,9 @@ u64 BISFactory::GetFullNANDTotalSpace() const { | |||
| 136 | return static_cast<u64>(Settings::values.nand_total_size); | 136 | return static_cast<u64>(Settings::values.nand_total_size); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const { | ||
| 140 | return GetOrCreateDirectoryRelative(nand_root, | ||
| 141 | fmt::format("/system/save/bcat/{:016X}", title_id)); | ||
| 142 | } | ||
| 143 | |||
| 139 | } // namespace FileSys | 144 | } // namespace FileSys |
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h index bdfe728c9..8f0451c98 100644 --- a/src/core/file_sys/bis_factory.h +++ b/src/core/file_sys/bis_factory.h | |||
| @@ -61,6 +61,8 @@ public: | |||
| 61 | u64 GetUserNANDTotalSpace() const; | 61 | u64 GetUserNANDTotalSpace() const; |
| 62 | u64 GetFullNANDTotalSpace() const; | 62 | u64 GetFullNANDTotalSpace() const; |
| 63 | 63 | ||
| 64 | VirtualDir GetBCATDirectory(u64 title_id) const; | ||
| 65 | |||
| 64 | private: | 66 | private: |
| 65 | VirtualDir nand_root; | 67 | VirtualDir nand_root; |
| 66 | VirtualDir load_root; | 68 | VirtualDir load_root; |
diff --git a/src/core/file_sys/vfs_libzip.cpp b/src/core/file_sys/vfs_libzip.cpp new file mode 100644 index 000000000..8bdaa7e4a --- /dev/null +++ b/src/core/file_sys/vfs_libzip.cpp | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <string> | ||
| 6 | #include <zip.h> | ||
| 7 | #include "common/logging/backend.h" | ||
| 8 | #include "core/file_sys/vfs.h" | ||
| 9 | #include "core/file_sys/vfs_libzip.h" | ||
| 10 | #include "core/file_sys/vfs_vector.h" | ||
| 11 | |||
| 12 | namespace FileSys { | ||
| 13 | |||
| 14 | VirtualDir ExtractZIP(VirtualFile file) { | ||
| 15 | zip_error_t error{}; | ||
| 16 | |||
| 17 | const auto data = file->ReadAllBytes(); | ||
| 18 | std::unique_ptr<zip_source_t, decltype(&zip_source_close)> src{ | ||
| 19 | zip_source_buffer_create(data.data(), data.size(), 0, &error), zip_source_close}; | ||
| 20 | if (src == nullptr) | ||
| 21 | return nullptr; | ||
| 22 | |||
| 23 | std::unique_ptr<zip_t, decltype(&zip_close)> zip{zip_open_from_source(src.get(), 0, &error), | ||
| 24 | zip_close}; | ||
| 25 | if (zip == nullptr) | ||
| 26 | return nullptr; | ||
| 27 | |||
| 28 | std::shared_ptr<VectorVfsDirectory> out = std::make_shared<VectorVfsDirectory>(); | ||
| 29 | |||
| 30 | const auto num_entries = zip_get_num_entries(zip.get(), 0); | ||
| 31 | |||
| 32 | zip_stat_t stat{}; | ||
| 33 | zip_stat_init(&stat); | ||
| 34 | |||
| 35 | for (std::size_t i = 0; i < num_entries; ++i) { | ||
| 36 | const auto stat_res = zip_stat_index(zip.get(), i, 0, &stat); | ||
| 37 | if (stat_res == -1) | ||
| 38 | return nullptr; | ||
| 39 | |||
| 40 | const std::string name(stat.name); | ||
| 41 | if (name.empty()) | ||
| 42 | continue; | ||
| 43 | |||
| 44 | if (name.back() != '/') { | ||
| 45 | std::unique_ptr<zip_file_t, decltype(&zip_fclose)> file{ | ||
| 46 | zip_fopen_index(zip.get(), i, 0), zip_fclose}; | ||
| 47 | |||
| 48 | std::vector<u8> buf(stat.size); | ||
| 49 | if (zip_fread(file.get(), buf.data(), buf.size()) != buf.size()) | ||
| 50 | return nullptr; | ||
| 51 | |||
| 52 | const auto parts = FileUtil::SplitPathComponents(stat.name); | ||
| 53 | const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back()); | ||
| 54 | |||
| 55 | std::shared_ptr<VectorVfsDirectory> dtrv = out; | ||
| 56 | for (std::size_t j = 0; j < parts.size() - 1; ++j) { | ||
| 57 | if (dtrv == nullptr) | ||
| 58 | return nullptr; | ||
| 59 | const auto subdir = dtrv->GetSubdirectory(parts[j]); | ||
| 60 | if (subdir == nullptr) { | ||
| 61 | const auto temp = std::make_shared<VectorVfsDirectory>( | ||
| 62 | std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parts[j]); | ||
| 63 | dtrv->AddDirectory(temp); | ||
| 64 | dtrv = temp; | ||
| 65 | } else { | ||
| 66 | dtrv = std::dynamic_pointer_cast<VectorVfsDirectory>(subdir); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | if (dtrv == nullptr) | ||
| 71 | return nullptr; | ||
| 72 | dtrv->AddFile(new_file); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | return out; | ||
| 77 | } | ||
| 78 | |||
| 79 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/vfs_libzip.h b/src/core/file_sys/vfs_libzip.h new file mode 100644 index 000000000..f68af576a --- /dev/null +++ b/src/core/file_sys/vfs_libzip.h | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/file_sys/vfs_types.h" | ||
| 8 | |||
| 9 | namespace FileSys { | ||
| 10 | |||
| 11 | VirtualDir ExtractZIP(VirtualFile zip); | ||
| 12 | |||
| 13 | } // namespace FileSys | ||
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index a7c55e116..0c0f7ed6e 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -70,7 +70,7 @@ public: | |||
| 70 | 70 | ||
| 71 | protected: | 71 | protected: |
| 72 | void Get(Kernel::HLERequestContext& ctx) { | 72 | void Get(Kernel::HLERequestContext& ctx) { |
| 73 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); | 73 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); |
| 74 | ProfileBase profile_base{}; | 74 | ProfileBase profile_base{}; |
| 75 | ProfileData data{}; | 75 | ProfileData data{}; |
| 76 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { | 76 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { |
| @@ -89,7 +89,7 @@ protected: | |||
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | void GetBase(Kernel::HLERequestContext& ctx) { | 91 | void GetBase(Kernel::HLERequestContext& ctx) { |
| 92 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); | 92 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); |
| 93 | ProfileBase profile_base{}; | 93 | ProfileBase profile_base{}; |
| 94 | if (profile_manager.GetProfileBase(user_id, profile_base)) { | 94 | if (profile_manager.GetProfileBase(user_id, profile_base)) { |
| 95 | IPC::ResponseBuilder rb{ctx, 16}; | 95 | IPC::ResponseBuilder rb{ctx, 16}; |
| @@ -263,7 +263,7 @@ private: | |||
| 263 | }; | 263 | }; |
| 264 | 264 | ||
| 265 | void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { | 265 | void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { |
| 266 | LOG_INFO(Service_ACC, "called"); | 266 | LOG_DEBUG(Service_ACC, "called"); |
| 267 | IPC::ResponseBuilder rb{ctx, 3}; | 267 | IPC::ResponseBuilder rb{ctx, 3}; |
| 268 | rb.Push(RESULT_SUCCESS); | 268 | rb.Push(RESULT_SUCCESS); |
| 269 | rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount())); | 269 | rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount())); |
| @@ -272,7 +272,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { | |||
| 272 | void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { | 272 | void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { |
| 273 | IPC::RequestParser rp{ctx}; | 273 | IPC::RequestParser rp{ctx}; |
| 274 | Common::UUID user_id = rp.PopRaw<Common::UUID>(); | 274 | Common::UUID user_id = rp.PopRaw<Common::UUID>(); |
| 275 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); | 275 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); |
| 276 | 276 | ||
| 277 | IPC::ResponseBuilder rb{ctx, 3}; | 277 | IPC::ResponseBuilder rb{ctx, 3}; |
| 278 | rb.Push(RESULT_SUCCESS); | 278 | rb.Push(RESULT_SUCCESS); |
| @@ -280,21 +280,21 @@ void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { | |||
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { | 282 | void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { |
| 283 | LOG_INFO(Service_ACC, "called"); | 283 | LOG_DEBUG(Service_ACC, "called"); |
| 284 | ctx.WriteBuffer(profile_manager->GetAllUsers()); | 284 | ctx.WriteBuffer(profile_manager->GetAllUsers()); |
| 285 | IPC::ResponseBuilder rb{ctx, 2}; | 285 | IPC::ResponseBuilder rb{ctx, 2}; |
| 286 | rb.Push(RESULT_SUCCESS); | 286 | rb.Push(RESULT_SUCCESS); |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) { | 289 | void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) { |
| 290 | LOG_INFO(Service_ACC, "called"); | 290 | LOG_DEBUG(Service_ACC, "called"); |
| 291 | ctx.WriteBuffer(profile_manager->GetOpenUsers()); | 291 | ctx.WriteBuffer(profile_manager->GetOpenUsers()); |
| 292 | IPC::ResponseBuilder rb{ctx, 2}; | 292 | IPC::ResponseBuilder rb{ctx, 2}; |
| 293 | rb.Push(RESULT_SUCCESS); | 293 | rb.Push(RESULT_SUCCESS); |
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { | 296 | void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { |
| 297 | LOG_INFO(Service_ACC, "called"); | 297 | LOG_DEBUG(Service_ACC, "called"); |
| 298 | IPC::ResponseBuilder rb{ctx, 6}; | 298 | IPC::ResponseBuilder rb{ctx, 6}; |
| 299 | rb.Push(RESULT_SUCCESS); | 299 | rb.Push(RESULT_SUCCESS); |
| 300 | rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser()); | 300 | rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser()); |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 6c594dcaf..34409e0c3 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include "core/hle/service/am/tcap.h" | 31 | #include "core/hle/service/am/tcap.h" |
| 32 | #include "core/hle/service/apm/controller.h" | 32 | #include "core/hle/service/apm/controller.h" |
| 33 | #include "core/hle/service/apm/interface.h" | 33 | #include "core/hle/service/apm/interface.h" |
| 34 | #include "core/hle/service/bcat/backend/backend.h" | ||
| 34 | #include "core/hle/service/filesystem/filesystem.h" | 35 | #include "core/hle/service/filesystem/filesystem.h" |
| 35 | #include "core/hle/service/ns/ns.h" | 36 | #include "core/hle/service/ns/ns.h" |
| 36 | #include "core/hle/service/nvflinger/nvflinger.h" | 37 | #include "core/hle/service/nvflinger/nvflinger.h" |
| @@ -46,15 +47,20 @@ constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; | |||
| 46 | constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; | 47 | constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; |
| 47 | constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; | 48 | constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; |
| 48 | 49 | ||
| 49 | constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; | 50 | enum class LaunchParameterKind : u32 { |
| 51 | ApplicationSpecific = 1, | ||
| 52 | AccountPreselectedUser = 2, | ||
| 53 | }; | ||
| 54 | |||
| 55 | constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; | ||
| 50 | 56 | ||
| 51 | struct LaunchParameters { | 57 | struct LaunchParameterAccountPreselectedUser { |
| 52 | u32_le magic; | 58 | u32_le magic; |
| 53 | u32_le is_account_selected; | 59 | u32_le is_account_selected; |
| 54 | u128 current_user; | 60 | u128 current_user; |
| 55 | INSERT_PADDING_BYTES(0x70); | 61 | INSERT_PADDING_BYTES(0x70); |
| 56 | }; | 62 | }; |
| 57 | static_assert(sizeof(LaunchParameters) == 0x88); | 63 | static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); |
| 58 | 64 | ||
| 59 | IWindowController::IWindowController(Core::System& system_) | 65 | IWindowController::IWindowController(Core::System& system_) |
| 60 | : ServiceFramework("IWindowController"), system{system_} { | 66 | : ServiceFramework("IWindowController"), system{system_} { |
| @@ -232,12 +238,12 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { | |||
| 232 | 238 | ||
| 233 | IDebugFunctions::~IDebugFunctions() = default; | 239 | IDebugFunctions::~IDebugFunctions() = default; |
| 234 | 240 | ||
| 235 | ISelfController::ISelfController(Core::System& system_, | 241 | ISelfController::ISelfController(Core::System& system, |
| 236 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger_) | 242 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger) |
| 237 | : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger_)) { | 243 | : ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) { |
| 238 | // clang-format off | 244 | // clang-format off |
| 239 | static const FunctionInfo functions[] = { | 245 | static const FunctionInfo functions[] = { |
| 240 | {0, nullptr, "Exit"}, | 246 | {0, &ISelfController::Exit, "Exit"}, |
| 241 | {1, &ISelfController::LockExit, "LockExit"}, | 247 | {1, &ISelfController::LockExit, "LockExit"}, |
| 242 | {2, &ISelfController::UnlockExit, "UnlockExit"}, | 248 | {2, &ISelfController::UnlockExit, "UnlockExit"}, |
| 243 | {3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, | 249 | {3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, |
| @@ -282,7 +288,7 @@ ISelfController::ISelfController(Core::System& system_, | |||
| 282 | 288 | ||
| 283 | RegisterHandlers(functions); | 289 | RegisterHandlers(functions); |
| 284 | 290 | ||
| 285 | auto& kernel = system_.Kernel(); | 291 | auto& kernel = system.Kernel(); |
| 286 | launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, | 292 | launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, |
| 287 | "ISelfController:LaunchableEvent"); | 293 | "ISelfController:LaunchableEvent"); |
| 288 | 294 | ||
| @@ -298,15 +304,28 @@ ISelfController::ISelfController(Core::System& system_, | |||
| 298 | 304 | ||
| 299 | ISelfController::~ISelfController() = default; | 305 | ISelfController::~ISelfController() = default; |
| 300 | 306 | ||
| 307 | void ISelfController::Exit(Kernel::HLERequestContext& ctx) { | ||
| 308 | LOG_DEBUG(Service_AM, "called"); | ||
| 309 | |||
| 310 | system.Shutdown(); | ||
| 311 | |||
| 312 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 313 | rb.Push(RESULT_SUCCESS); | ||
| 314 | } | ||
| 315 | |||
| 301 | void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { | 316 | void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { |
| 302 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 317 | LOG_DEBUG(Service_AM, "called"); |
| 318 | |||
| 319 | system.SetExitLock(true); | ||
| 303 | 320 | ||
| 304 | IPC::ResponseBuilder rb{ctx, 2}; | 321 | IPC::ResponseBuilder rb{ctx, 2}; |
| 305 | rb.Push(RESULT_SUCCESS); | 322 | rb.Push(RESULT_SUCCESS); |
| 306 | } | 323 | } |
| 307 | 324 | ||
| 308 | void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { | 325 | void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { |
| 309 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 326 | LOG_DEBUG(Service_AM, "called"); |
| 327 | |||
| 328 | system.SetExitLock(false); | ||
| 310 | 329 | ||
| 311 | IPC::ResponseBuilder rb{ctx, 2}; | 330 | IPC::ResponseBuilder rb{ctx, 2}; |
| 312 | rb.Push(RESULT_SUCCESS); | 331 | rb.Push(RESULT_SUCCESS); |
| @@ -550,6 +569,10 @@ void AppletMessageQueue::OperationModeChanged() { | |||
| 550 | on_operation_mode_changed.writable->Signal(); | 569 | on_operation_mode_changed.writable->Signal(); |
| 551 | } | 570 | } |
| 552 | 571 | ||
| 572 | void AppletMessageQueue::RequestExit() { | ||
| 573 | PushMessage(AppletMessage::ExitRequested); | ||
| 574 | } | ||
| 575 | |||
| 553 | ICommonStateGetter::ICommonStateGetter(Core::System& system, | 576 | ICommonStateGetter::ICommonStateGetter(Core::System& system, |
| 554 | std::shared_ptr<AppletMessageQueue> msg_queue) | 577 | std::shared_ptr<AppletMessageQueue> msg_queue) |
| 555 | : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) { | 578 | : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) { |
| @@ -1066,7 +1089,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) | |||
| 1066 | 1089 | ||
| 1067 | RegisterHandlers(functions); | 1090 | RegisterHandlers(functions); |
| 1068 | 1091 | ||
| 1069 | auto& kernel = Core::System::GetInstance().Kernel(); | 1092 | auto& kernel = system.Kernel(); |
| 1070 | gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair( | 1093 | gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair( |
| 1071 | kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); | 1094 | kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); |
| 1072 | } | 1095 | } |
| @@ -1111,26 +1134,55 @@ void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx | |||
| 1111 | } | 1134 | } |
| 1112 | 1135 | ||
| 1113 | void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | 1136 | void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { |
| 1114 | LOG_DEBUG(Service_AM, "called"); | 1137 | IPC::RequestParser rp{ctx}; |
| 1138 | const auto kind = rp.PopEnum<LaunchParameterKind>(); | ||
| 1115 | 1139 | ||
| 1116 | LaunchParameters params{}; | 1140 | LOG_DEBUG(Service_AM, "called, kind={:08X}", static_cast<u8>(kind)); |
| 1117 | 1141 | ||
| 1118 | params.magic = POP_LAUNCH_PARAMETER_MAGIC; | 1142 | if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) { |
| 1119 | params.is_account_selected = 1; | 1143 | const auto backend = BCAT::CreateBackendFromSettings( |
| 1144 | [this](u64 tid) { return system.GetFileSystemController().GetBCATDirectory(tid); }); | ||
| 1145 | const auto build_id_full = Core::System::GetInstance().GetCurrentProcessBuildID(); | ||
| 1146 | u64 build_id{}; | ||
| 1147 | std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); | ||
| 1120 | 1148 | ||
| 1121 | Account::ProfileManager profile_manager{}; | 1149 | const auto data = |
| 1122 | const auto uuid = profile_manager.GetUser(Settings::values.current_user); | 1150 | backend->GetLaunchParameter({Core::CurrentProcess()->GetTitleID(), build_id}); |
| 1123 | ASSERT(uuid); | ||
| 1124 | params.current_user = uuid->uuid; | ||
| 1125 | 1151 | ||
| 1126 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1152 | if (data.has_value()) { |
| 1153 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 1154 | rb.Push(RESULT_SUCCESS); | ||
| 1155 | rb.PushIpcInterface<AM::IStorage>(*data); | ||
| 1156 | launch_popped_application_specific = true; | ||
| 1157 | return; | ||
| 1158 | } | ||
| 1159 | } else if (kind == LaunchParameterKind::AccountPreselectedUser && | ||
| 1160 | !launch_popped_account_preselect) { | ||
| 1161 | LaunchParameterAccountPreselectedUser params{}; | ||
| 1127 | 1162 | ||
| 1128 | rb.Push(RESULT_SUCCESS); | 1163 | params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; |
| 1164 | params.is_account_selected = 1; | ||
| 1165 | |||
| 1166 | Account::ProfileManager profile_manager{}; | ||
| 1167 | const auto uuid = profile_manager.GetUser(Settings::values.current_user); | ||
| 1168 | ASSERT(uuid); | ||
| 1169 | params.current_user = uuid->uuid; | ||
| 1129 | 1170 | ||
| 1130 | std::vector<u8> buffer(sizeof(LaunchParameters)); | 1171 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1131 | std::memcpy(buffer.data(), ¶ms, buffer.size()); | 1172 | |
| 1173 | rb.Push(RESULT_SUCCESS); | ||
| 1174 | |||
| 1175 | std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); | ||
| 1176 | std::memcpy(buffer.data(), ¶ms, buffer.size()); | ||
| 1132 | 1177 | ||
| 1133 | rb.PushIpcInterface<AM::IStorage>(buffer); | 1178 | rb.PushIpcInterface<AM::IStorage>(buffer); |
| 1179 | launch_popped_account_preselect = true; | ||
| 1180 | return; | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); | ||
| 1184 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1185 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | ||
| 1134 | } | 1186 | } |
| 1135 | 1187 | ||
| 1136 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( | 1188 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 28f870302..9169eb2bd 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -45,6 +45,7 @@ class AppletMessageQueue { | |||
| 45 | public: | 45 | public: |
| 46 | enum class AppletMessage : u32 { | 46 | enum class AppletMessage : u32 { |
| 47 | NoMessage = 0, | 47 | NoMessage = 0, |
| 48 | ExitRequested = 4, | ||
| 48 | FocusStateChanged = 15, | 49 | FocusStateChanged = 15, |
| 49 | OperationModeChanged = 30, | 50 | OperationModeChanged = 30, |
| 50 | PerformanceModeChanged = 31, | 51 | PerformanceModeChanged = 31, |
| @@ -59,6 +60,7 @@ public: | |||
| 59 | AppletMessage PopMessage(); | 60 | AppletMessage PopMessage(); |
| 60 | std::size_t GetMessageCount() const; | 61 | std::size_t GetMessageCount() const; |
| 61 | void OperationModeChanged(); | 62 | void OperationModeChanged(); |
| 63 | void RequestExit(); | ||
| 62 | 64 | ||
| 63 | private: | 65 | private: |
| 64 | std::queue<AppletMessage> messages; | 66 | std::queue<AppletMessage> messages; |
| @@ -123,6 +125,7 @@ public: | |||
| 123 | ~ISelfController() override; | 125 | ~ISelfController() override; |
| 124 | 126 | ||
| 125 | private: | 127 | private: |
| 128 | void Exit(Kernel::HLERequestContext& ctx); | ||
| 126 | void LockExit(Kernel::HLERequestContext& ctx); | 129 | void LockExit(Kernel::HLERequestContext& ctx); |
| 127 | void UnlockExit(Kernel::HLERequestContext& ctx); | 130 | void UnlockExit(Kernel::HLERequestContext& ctx); |
| 128 | void EnterFatalSection(Kernel::HLERequestContext& ctx); | 131 | void EnterFatalSection(Kernel::HLERequestContext& ctx); |
| @@ -151,6 +154,8 @@ private: | |||
| 151 | u32 idle_time_detection_extension = 0; | 154 | u32 idle_time_detection_extension = 0; |
| 152 | u64 num_fatal_sections_entered = 0; | 155 | u64 num_fatal_sections_entered = 0; |
| 153 | bool is_auto_sleep_disabled = false; | 156 | bool is_auto_sleep_disabled = false; |
| 157 | |||
| 158 | Core::System& system; | ||
| 154 | }; | 159 | }; |
| 155 | 160 | ||
| 156 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { | 161 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { |
| @@ -250,6 +255,8 @@ private: | |||
| 250 | void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); | 255 | void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); |
| 251 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); | 256 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); |
| 252 | 257 | ||
| 258 | bool launch_popped_application_specific = false; | ||
| 259 | bool launch_popped_account_preselect = false; | ||
| 253 | Kernel::EventPair gpu_error_detected_event; | 260 | Kernel::EventPair gpu_error_detected_event; |
| 254 | Core::System& system; | 261 | Core::System& system; |
| 255 | }; | 262 | }; |
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 0e0d10858..2e3e45915 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h | |||
| @@ -19,6 +19,8 @@ class NVFlinger; | |||
| 19 | 19 | ||
| 20 | namespace AM { | 20 | namespace AM { |
| 21 | 21 | ||
| 22 | class AppletMessageQueue; | ||
| 23 | |||
| 22 | class AppletAE final : public ServiceFramework<AppletAE> { | 24 | class AppletAE final : public ServiceFramework<AppletAE> { |
| 23 | public: | 25 | public: |
| 24 | explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 26 | explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, |
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 99a65e7b5..758da792d 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h | |||
| @@ -19,6 +19,8 @@ class NVFlinger; | |||
| 19 | 19 | ||
| 20 | namespace AM { | 20 | namespace AM { |
| 21 | 21 | ||
| 22 | class AppletMessageQueue; | ||
| 23 | |||
| 22 | class AppletOE final : public ServiceFramework<AppletOE> { | 24 | class AppletOE final : public ServiceFramework<AppletOE> { |
| 23 | public: | 25 | public: |
| 24 | explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 26 | explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, |
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index d2e35362f..720fe766f 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -157,6 +157,10 @@ AppletManager::AppletManager(Core::System& system_) : system{system_} {} | |||
| 157 | 157 | ||
| 158 | AppletManager::~AppletManager() = default; | 158 | AppletManager::~AppletManager() = default; |
| 159 | 159 | ||
| 160 | const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { | ||
| 161 | return frontend; | ||
| 162 | } | ||
| 163 | |||
| 160 | void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { | 164 | void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { |
| 161 | if (set.parental_controls != nullptr) | 165 | if (set.parental_controls != nullptr) |
| 162 | frontend.parental_controls = std::move(set.parental_controls); | 166 | frontend.parental_controls = std::move(set.parental_controls); |
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 764c3418c..226be88b1 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -190,6 +190,8 @@ public: | |||
| 190 | explicit AppletManager(Core::System& system_); | 190 | explicit AppletManager(Core::System& system_); |
| 191 | ~AppletManager(); | 191 | ~AppletManager(); |
| 192 | 192 | ||
| 193 | const AppletFrontendSet& GetAppletFrontendSet() const; | ||
| 194 | |||
| 193 | void SetAppletFrontendSet(AppletFrontendSet set); | 195 | void SetAppletFrontendSet(AppletFrontendSet set); |
| 194 | void SetDefaultAppletFrontendSet(); | 196 | void SetDefaultAppletFrontendSet(); |
| 195 | void SetDefaultAppletsIfMissing(); | 197 | void SetDefaultAppletsIfMissing(); |
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index d3e97776b..e9cf1e840 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp | |||
| @@ -29,9 +29,9 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) { | |||
| 29 | return (title_id & DLC_BASE_TITLE_ID_MASK) == base; | 29 | return (title_id & DLC_BASE_TITLE_ID_MASK) == base; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | static std::vector<u64> AccumulateAOCTitleIDs() { | 32 | static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) { |
| 33 | std::vector<u64> add_on_content; | 33 | std::vector<u64> add_on_content; |
| 34 | const auto& rcu = Core::System::GetInstance().GetContentProvider(); | 34 | const auto& rcu = system.GetContentProvider(); |
| 35 | const auto list = | 35 | const auto list = |
| 36 | rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); | 36 | rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); |
| 37 | std::transform(list.begin(), list.end(), std::back_inserter(add_on_content), | 37 | std::transform(list.begin(), list.end(), std::back_inserter(add_on_content), |
| @@ -47,7 +47,8 @@ static std::vector<u64> AccumulateAOCTitleIDs() { | |||
| 47 | return add_on_content; | 47 | return add_on_content; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs()) { | 50 | AOC_U::AOC_U(Core::System& system) |
| 51 | : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs(system)), system(system) { | ||
| 51 | // clang-format off | 52 | // clang-format off |
| 52 | static const FunctionInfo functions[] = { | 53 | static const FunctionInfo functions[] = { |
| 53 | {0, nullptr, "CountAddOnContentByApplicationId"}, | 54 | {0, nullptr, "CountAddOnContentByApplicationId"}, |
| @@ -65,7 +66,7 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs | |||
| 65 | 66 | ||
| 66 | RegisterHandlers(functions); | 67 | RegisterHandlers(functions); |
| 67 | 68 | ||
| 68 | auto& kernel = Core::System::GetInstance().Kernel(); | 69 | auto& kernel = system.Kernel(); |
| 69 | aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, | 70 | aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, |
| 70 | "GetAddOnContentListChanged:Event"); | 71 | "GetAddOnContentListChanged:Event"); |
| 71 | } | 72 | } |
| @@ -86,7 +87,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 86 | IPC::ResponseBuilder rb{ctx, 3}; | 87 | IPC::ResponseBuilder rb{ctx, 3}; |
| 87 | rb.Push(RESULT_SUCCESS); | 88 | rb.Push(RESULT_SUCCESS); |
| 88 | 89 | ||
| 89 | const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 90 | const auto current = system.CurrentProcess()->GetTitleID(); |
| 90 | 91 | ||
| 91 | const auto& disabled = Settings::values.disabled_addons[current]; | 92 | const auto& disabled = Settings::values.disabled_addons[current]; |
| 92 | if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) { | 93 | if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) { |
| @@ -113,7 +114,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 113 | LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count, | 114 | LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count, |
| 114 | process_id); | 115 | process_id); |
| 115 | 116 | ||
| 116 | const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 117 | const auto current = system.CurrentProcess()->GetTitleID(); |
| 117 | 118 | ||
| 118 | std::vector<u32> out; | 119 | std::vector<u32> out; |
| 119 | const auto& disabled = Settings::values.disabled_addons[current]; | 120 | const auto& disabled = Settings::values.disabled_addons[current]; |
| @@ -159,7 +160,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { | |||
| 159 | IPC::ResponseBuilder rb{ctx, 4}; | 160 | IPC::ResponseBuilder rb{ctx, 4}; |
| 160 | rb.Push(RESULT_SUCCESS); | 161 | rb.Push(RESULT_SUCCESS); |
| 161 | 162 | ||
| 162 | const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 163 | const auto title_id = system.CurrentProcess()->GetTitleID(); |
| 163 | FileSys::PatchManager pm{title_id}; | 164 | FileSys::PatchManager pm{title_id}; |
| 164 | 165 | ||
| 165 | const auto res = pm.GetControlMetadata(); | 166 | const auto res = pm.GetControlMetadata(); |
| @@ -196,8 +197,8 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) { | |||
| 196 | rb.PushCopyObjects(aoc_change_event.readable); | 197 | rb.PushCopyObjects(aoc_change_event.readable); |
| 197 | } | 198 | } |
| 198 | 199 | ||
| 199 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 200 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 200 | std::make_shared<AOC_U>()->InstallAsService(service_manager); | 201 | std::make_shared<AOC_U>(system)->InstallAsService(service_manager); |
| 201 | } | 202 | } |
| 202 | 203 | ||
| 203 | } // namespace Service::AOC | 204 | } // namespace Service::AOC |
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 5effea730..848b2f416 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h | |||
| @@ -14,7 +14,7 @@ namespace Service::AOC { | |||
| 14 | 14 | ||
| 15 | class AOC_U final : public ServiceFramework<AOC_U> { | 15 | class AOC_U final : public ServiceFramework<AOC_U> { |
| 16 | public: | 16 | public: |
| 17 | AOC_U(); | 17 | explicit AOC_U(Core::System& system); |
| 18 | ~AOC_U() override; | 18 | ~AOC_U() override; |
| 19 | 19 | ||
| 20 | private: | 20 | private: |
| @@ -26,9 +26,10 @@ private: | |||
| 26 | 26 | ||
| 27 | std::vector<u64> add_on_content; | 27 | std::vector<u64> add_on_content; |
| 28 | Kernel::EventPair aoc_change_event; | 28 | Kernel::EventPair aoc_change_event; |
| 29 | Core::System& system; | ||
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| 31 | /// Registers all AOC services with the specified service manager. | 32 | /// Registers all AOC services with the specified service manager. |
| 32 | void InstallInterfaces(SM::ServiceManager& service_manager); | 33 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 33 | 34 | ||
| 34 | } // namespace Service::AOC | 35 | } // namespace Service::AOC |
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp new file mode 100644 index 000000000..9b677debe --- /dev/null +++ b/src/core/hle/service/bcat/backend/backend.cpp | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/hex_util.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/hle/lock.h" | ||
| 9 | #include "core/hle/service/bcat/backend/backend.h" | ||
| 10 | |||
| 11 | namespace Service::BCAT { | ||
| 12 | |||
| 13 | ProgressServiceBackend::ProgressServiceBackend(std::string event_name) : impl{} { | ||
| 14 | auto& kernel{Core::System::GetInstance().Kernel()}; | ||
| 15 | event = Kernel::WritableEvent::CreateEventPair( | ||
| 16 | kernel, Kernel::ResetType::Automatic, "ProgressServiceBackend:UpdateEvent:" + event_name); | ||
| 17 | } | ||
| 18 | |||
| 19 | Kernel::SharedPtr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() { | ||
| 20 | return event.readable; | ||
| 21 | } | ||
| 22 | |||
| 23 | DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { | ||
| 24 | return impl; | ||
| 25 | } | ||
| 26 | |||
| 27 | void ProgressServiceBackend::SetNeedHLELock(bool need) { | ||
| 28 | need_hle_lock = need; | ||
| 29 | } | ||
| 30 | |||
| 31 | void ProgressServiceBackend::SetTotalSize(u64 size) { | ||
| 32 | impl.total_bytes = size; | ||
| 33 | SignalUpdate(); | ||
| 34 | } | ||
| 35 | |||
| 36 | void ProgressServiceBackend::StartConnecting() { | ||
| 37 | impl.status = DeliveryCacheProgressImpl::Status::Connecting; | ||
| 38 | SignalUpdate(); | ||
| 39 | } | ||
| 40 | |||
| 41 | void ProgressServiceBackend::StartProcessingDataList() { | ||
| 42 | impl.status = DeliveryCacheProgressImpl::Status::ProcessingDataList; | ||
| 43 | SignalUpdate(); | ||
| 44 | } | ||
| 45 | |||
| 46 | void ProgressServiceBackend::StartDownloadingFile(std::string_view dir_name, | ||
| 47 | std::string_view file_name, u64 file_size) { | ||
| 48 | impl.status = DeliveryCacheProgressImpl::Status::Downloading; | ||
| 49 | impl.current_downloaded_bytes = 0; | ||
| 50 | impl.current_total_bytes = file_size; | ||
| 51 | std::memcpy(impl.current_directory.data(), dir_name.data(), | ||
| 52 | std::min<u64>(dir_name.size(), 0x31ull)); | ||
| 53 | std::memcpy(impl.current_file.data(), file_name.data(), | ||
| 54 | std::min<u64>(file_name.size(), 0x31ull)); | ||
| 55 | SignalUpdate(); | ||
| 56 | } | ||
| 57 | |||
| 58 | void ProgressServiceBackend::UpdateFileProgress(u64 downloaded) { | ||
| 59 | impl.current_downloaded_bytes = downloaded; | ||
| 60 | SignalUpdate(); | ||
| 61 | } | ||
| 62 | |||
| 63 | void ProgressServiceBackend::FinishDownloadingFile() { | ||
| 64 | impl.total_downloaded_bytes += impl.current_total_bytes; | ||
| 65 | SignalUpdate(); | ||
| 66 | } | ||
| 67 | |||
| 68 | void ProgressServiceBackend::CommitDirectory(std::string_view dir_name) { | ||
| 69 | impl.status = DeliveryCacheProgressImpl::Status::Committing; | ||
| 70 | impl.current_file.fill(0); | ||
| 71 | impl.current_downloaded_bytes = 0; | ||
| 72 | impl.current_total_bytes = 0; | ||
| 73 | std::memcpy(impl.current_directory.data(), dir_name.data(), | ||
| 74 | std::min<u64>(dir_name.size(), 0x31ull)); | ||
| 75 | SignalUpdate(); | ||
| 76 | } | ||
| 77 | |||
| 78 | void ProgressServiceBackend::FinishDownload(ResultCode result) { | ||
| 79 | impl.total_downloaded_bytes = impl.total_bytes; | ||
| 80 | impl.status = DeliveryCacheProgressImpl::Status::Done; | ||
| 81 | impl.result = result; | ||
| 82 | SignalUpdate(); | ||
| 83 | } | ||
| 84 | |||
| 85 | void ProgressServiceBackend::SignalUpdate() const { | ||
| 86 | if (need_hle_lock) { | ||
| 87 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||
| 88 | event.writable->Signal(); | ||
| 89 | } else { | ||
| 90 | event.writable->Signal(); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {} | ||
| 95 | |||
| 96 | Backend::~Backend() = default; | ||
| 97 | |||
| 98 | NullBackend::NullBackend(const DirectoryGetter& getter) : Backend(std::move(getter)) {} | ||
| 99 | |||
| 100 | NullBackend::~NullBackend() = default; | ||
| 101 | |||
| 102 | bool NullBackend::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) { | ||
| 103 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id, | ||
| 104 | title.build_id); | ||
| 105 | |||
| 106 | progress.FinishDownload(RESULT_SUCCESS); | ||
| 107 | return true; | ||
| 108 | } | ||
| 109 | |||
| 110 | bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 111 | ProgressServiceBackend& progress) { | ||
| 112 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}, name={}", title.title_id, | ||
| 113 | title.build_id, name); | ||
| 114 | |||
| 115 | progress.FinishDownload(RESULT_SUCCESS); | ||
| 116 | return true; | ||
| 117 | } | ||
| 118 | |||
| 119 | bool NullBackend::Clear(u64 title_id) { | ||
| 120 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}"); | ||
| 121 | |||
| 122 | return true; | ||
| 123 | } | ||
| 124 | |||
| 125 | void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) { | ||
| 126 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase = {}", title_id, | ||
| 127 | Common::HexToString(passphrase)); | ||
| 128 | } | ||
| 129 | |||
| 130 | std::optional<std::vector<u8>> NullBackend::GetLaunchParameter(TitleIDVersion title) { | ||
| 131 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id, | ||
| 132 | title.build_id); | ||
| 133 | return std::nullopt; | ||
| 134 | } | ||
| 135 | |||
| 136 | } // namespace Service::BCAT | ||
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h new file mode 100644 index 000000000..3f5d8b5dd --- /dev/null +++ b/src/core/hle/service/bcat/backend/backend.h | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <functional> | ||
| 8 | #include <optional> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/file_sys/vfs_types.h" | ||
| 11 | #include "core/hle/kernel/readable_event.h" | ||
| 12 | #include "core/hle/kernel/writable_event.h" | ||
| 13 | #include "core/hle/result.h" | ||
| 14 | |||
| 15 | namespace Service::BCAT { | ||
| 16 | |||
| 17 | struct DeliveryCacheProgressImpl; | ||
| 18 | |||
| 19 | using DirectoryGetter = std::function<FileSys::VirtualDir(u64)>; | ||
| 20 | using Passphrase = std::array<u8, 0x20>; | ||
| 21 | |||
| 22 | struct TitleIDVersion { | ||
| 23 | u64 title_id; | ||
| 24 | u64 build_id; | ||
| 25 | }; | ||
| 26 | |||
| 27 | using DirectoryName = std::array<char, 0x20>; | ||
| 28 | using FileName = std::array<char, 0x20>; | ||
| 29 | |||
| 30 | struct DeliveryCacheProgressImpl { | ||
| 31 | enum class Status : s32 { | ||
| 32 | None = 0x0, | ||
| 33 | Queued = 0x1, | ||
| 34 | Connecting = 0x2, | ||
| 35 | ProcessingDataList = 0x3, | ||
| 36 | Downloading = 0x4, | ||
| 37 | Committing = 0x5, | ||
| 38 | Done = 0x9, | ||
| 39 | }; | ||
| 40 | |||
| 41 | Status status; | ||
| 42 | ResultCode result = RESULT_SUCCESS; | ||
| 43 | DirectoryName current_directory; | ||
| 44 | FileName current_file; | ||
| 45 | s64 current_downloaded_bytes; ///< Bytes downloaded on current file. | ||
| 46 | s64 current_total_bytes; ///< Bytes total on current file. | ||
| 47 | s64 total_downloaded_bytes; ///< Bytes downloaded on overall download. | ||
| 48 | s64 total_bytes; ///< Bytes total on overall download. | ||
| 49 | INSERT_PADDING_BYTES( | ||
| 50 | 0x198); ///< Appears to be unused in official code, possibly reserved for future use. | ||
| 51 | }; | ||
| 52 | static_assert(sizeof(DeliveryCacheProgressImpl) == 0x200, | ||
| 53 | "DeliveryCacheProgressImpl has incorrect size."); | ||
| 54 | |||
| 55 | // A class to manage the signalling to the game about BCAT download progress. | ||
| 56 | // Some of this class is implemented in module.cpp to avoid exposing the implementation structure. | ||
| 57 | class ProgressServiceBackend { | ||
| 58 | friend class IBcatService; | ||
| 59 | |||
| 60 | public: | ||
| 61 | // Clients should call this with true if any of the functions are going to be called from a | ||
| 62 | // non-HLE thread and this class need to lock the hle mutex. (default is false) | ||
| 63 | void SetNeedHLELock(bool need); | ||
| 64 | |||
| 65 | // Sets the number of bytes total in the entire download. | ||
| 66 | void SetTotalSize(u64 size); | ||
| 67 | |||
| 68 | // Notifies the application that the backend has started connecting to the server. | ||
| 69 | void StartConnecting(); | ||
| 70 | // Notifies the application that the backend has begun accumulating and processing metadata. | ||
| 71 | void StartProcessingDataList(); | ||
| 72 | |||
| 73 | // Notifies the application that a file is starting to be downloaded. | ||
| 74 | void StartDownloadingFile(std::string_view dir_name, std::string_view file_name, u64 file_size); | ||
| 75 | // Updates the progress of the current file to the size passed. | ||
| 76 | void UpdateFileProgress(u64 downloaded); | ||
| 77 | // Notifies the application that the current file has completed download. | ||
| 78 | void FinishDownloadingFile(); | ||
| 79 | |||
| 80 | // Notifies the application that all files in this directory have completed and are being | ||
| 81 | // finalized. | ||
| 82 | void CommitDirectory(std::string_view dir_name); | ||
| 83 | |||
| 84 | // Notifies the application that the operation completed with result code result. | ||
| 85 | void FinishDownload(ResultCode result); | ||
| 86 | |||
| 87 | private: | ||
| 88 | explicit ProgressServiceBackend(std::string event_name); | ||
| 89 | |||
| 90 | Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent(); | ||
| 91 | DeliveryCacheProgressImpl& GetImpl(); | ||
| 92 | |||
| 93 | void SignalUpdate() const; | ||
| 94 | |||
| 95 | DeliveryCacheProgressImpl impl; | ||
| 96 | Kernel::EventPair event; | ||
| 97 | bool need_hle_lock = false; | ||
| 98 | }; | ||
| 99 | |||
| 100 | // A class representing an abstract backend for BCAT functionality. | ||
| 101 | class Backend { | ||
| 102 | public: | ||
| 103 | explicit Backend(DirectoryGetter getter); | ||
| 104 | virtual ~Backend(); | ||
| 105 | |||
| 106 | // Called when the backend is needed to synchronize the data for the game with title ID and | ||
| 107 | // version in title. A ProgressServiceBackend object is provided to alert the application of | ||
| 108 | // status. | ||
| 109 | virtual bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) = 0; | ||
| 110 | // Very similar to Synchronize, but only for the directory provided. Backends should not alter | ||
| 111 | // the data for any other directories. | ||
| 112 | virtual bool SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 113 | ProgressServiceBackend& progress) = 0; | ||
| 114 | |||
| 115 | // Removes all cached data associated with title id provided. | ||
| 116 | virtual bool Clear(u64 title_id) = 0; | ||
| 117 | |||
| 118 | // Sets the BCAT Passphrase to be used with the associated title ID. | ||
| 119 | virtual void SetPassphrase(u64 title_id, const Passphrase& passphrase) = 0; | ||
| 120 | |||
| 121 | // Gets the launch parameter used by AM associated with the title ID and version provided. | ||
| 122 | virtual std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) = 0; | ||
| 123 | |||
| 124 | protected: | ||
| 125 | DirectoryGetter dir_getter; | ||
| 126 | }; | ||
| 127 | |||
| 128 | // A backend of BCAT that provides no operation. | ||
| 129 | class NullBackend : public Backend { | ||
| 130 | public: | ||
| 131 | explicit NullBackend(const DirectoryGetter& getter); | ||
| 132 | ~NullBackend() override; | ||
| 133 | |||
| 134 | bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override; | ||
| 135 | bool SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 136 | ProgressServiceBackend& progress) override; | ||
| 137 | |||
| 138 | bool Clear(u64 title_id) override; | ||
| 139 | |||
| 140 | void SetPassphrase(u64 title_id, const Passphrase& passphrase) override; | ||
| 141 | |||
| 142 | std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override; | ||
| 143 | }; | ||
| 144 | |||
| 145 | std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter); | ||
| 146 | |||
| 147 | } // namespace Service::BCAT | ||
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp new file mode 100644 index 000000000..e6ee0810b --- /dev/null +++ b/src/core/hle/service/bcat/backend/boxcat.cpp | |||
| @@ -0,0 +1,503 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <fmt/ostream.h> | ||
| 6 | #include <httplib.h> | ||
| 7 | #include <json.hpp> | ||
| 8 | #include <mbedtls/sha256.h> | ||
| 9 | #include "common/hex_util.h" | ||
| 10 | #include "common/logging/backend.h" | ||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "core/core.h" | ||
| 13 | #include "core/file_sys/vfs.h" | ||
| 14 | #include "core/file_sys/vfs_libzip.h" | ||
| 15 | #include "core/file_sys/vfs_vector.h" | ||
| 16 | #include "core/frontend/applets/error.h" | ||
| 17 | #include "core/hle/service/am/applets/applets.h" | ||
| 18 | #include "core/hle/service/bcat/backend/boxcat.h" | ||
| 19 | #include "core/settings.h" | ||
| 20 | |||
| 21 | namespace { | ||
| 22 | |||
| 23 | // Prevents conflicts with windows macro called CreateFile | ||
| 24 | FileSys::VirtualFile VfsCreateFileWrap(FileSys::VirtualDir dir, std::string_view name) { | ||
| 25 | return dir->CreateFile(name); | ||
| 26 | } | ||
| 27 | |||
| 28 | // Prevents conflicts with windows macro called DeleteFile | ||
| 29 | bool VfsDeleteFileWrap(FileSys::VirtualDir dir, std::string_view name) { | ||
| 30 | return dir->DeleteFile(name); | ||
| 31 | } | ||
| 32 | |||
| 33 | } // Anonymous namespace | ||
| 34 | |||
| 35 | namespace Service::BCAT { | ||
| 36 | |||
| 37 | constexpr ResultCode ERROR_GENERAL_BCAT_FAILURE{ErrorModule::BCAT, 1}; | ||
| 38 | |||
| 39 | constexpr char BOXCAT_HOSTNAME[] = "api.yuzu-emu.org"; | ||
| 40 | |||
| 41 | // Formatted using fmt with arg[0] = hex title id | ||
| 42 | constexpr char BOXCAT_PATHNAME_DATA[] = "/game-assets/{:016X}/boxcat"; | ||
| 43 | constexpr char BOXCAT_PATHNAME_LAUNCHPARAM[] = "/game-assets/{:016X}/launchparam"; | ||
| 44 | |||
| 45 | constexpr char BOXCAT_PATHNAME_EVENTS[] = "/game-assets/boxcat/events"; | ||
| 46 | |||
| 47 | constexpr char BOXCAT_API_VERSION[] = "1"; | ||
| 48 | constexpr char BOXCAT_CLIENT_TYPE[] = "yuzu"; | ||
| 49 | |||
| 50 | // HTTP status codes for Boxcat | ||
| 51 | enum class ResponseStatus { | ||
| 52 | Ok = 200, ///< Operation completed successfully. | ||
| 53 | BadClientVersion = 301, ///< The Boxcat-Client-Version doesn't match the server. | ||
| 54 | NoUpdate = 304, ///< The digest provided would match the new data, no need to update. | ||
| 55 | NoMatchTitleId = 404, ///< The title ID provided doesn't have a boxcat implementation. | ||
| 56 | NoMatchBuildId = 406, ///< The build ID provided is blacklisted (potentially because of format | ||
| 57 | ///< issues or whatnot) and has no data. | ||
| 58 | }; | ||
| 59 | |||
| 60 | enum class DownloadResult { | ||
| 61 | Success = 0, | ||
| 62 | NoResponse, | ||
| 63 | GeneralWebError, | ||
| 64 | NoMatchTitleId, | ||
| 65 | NoMatchBuildId, | ||
| 66 | InvalidContentType, | ||
| 67 | GeneralFSError, | ||
| 68 | BadClientVersion, | ||
| 69 | }; | ||
| 70 | |||
| 71 | constexpr std::array<const char*, 8> DOWNLOAD_RESULT_LOG_MESSAGES{ | ||
| 72 | "Success", | ||
| 73 | "There was no response from the server.", | ||
| 74 | "There was a general web error code returned from the server.", | ||
| 75 | "The title ID of the current game doesn't have a boxcat implementation. If you believe an " | ||
| 76 | "implementation should be added, contact yuzu support.", | ||
| 77 | "The build ID of the current version of the game is marked as incompatible with the current " | ||
| 78 | "BCAT distribution. Try upgrading or downgrading your game version or contacting yuzu support.", | ||
| 79 | "The content type of the web response was invalid.", | ||
| 80 | "There was a general filesystem error while saving the zip file.", | ||
| 81 | "The server is either too new or too old to serve the request. Try using the latest version of " | ||
| 82 | "an official release of yuzu.", | ||
| 83 | }; | ||
| 84 | |||
| 85 | std::ostream& operator<<(std::ostream& os, DownloadResult result) { | ||
| 86 | return os << DOWNLOAD_RESULT_LOG_MESSAGES.at(static_cast<std::size_t>(result)); | ||
| 87 | } | ||
| 88 | |||
| 89 | constexpr u32 PORT = 443; | ||
| 90 | constexpr u32 TIMEOUT_SECONDS = 30; | ||
| 91 | constexpr u64 VFS_COPY_BLOCK_SIZE = 1ull << 24; // 4MB | ||
| 92 | |||
| 93 | namespace { | ||
| 94 | |||
| 95 | std::string GetBINFilePath(u64 title_id) { | ||
| 96 | return fmt::format("{}bcat/{:016X}/launchparam.bin", | ||
| 97 | FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id); | ||
| 98 | } | ||
| 99 | |||
| 100 | std::string GetZIPFilePath(u64 title_id) { | ||
| 101 | return fmt::format("{}bcat/{:016X}/data.zip", | ||
| 102 | FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id); | ||
| 103 | } | ||
| 104 | |||
| 105 | // If the error is something the user should know about (build ID mismatch, bad client version), | ||
| 106 | // display an error. | ||
| 107 | void HandleDownloadDisplayResult(DownloadResult res) { | ||
| 108 | if (res == DownloadResult::Success || res == DownloadResult::NoResponse || | ||
| 109 | res == DownloadResult::GeneralWebError || res == DownloadResult::GeneralFSError || | ||
| 110 | res == DownloadResult::NoMatchTitleId || res == DownloadResult::InvalidContentType) { | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | |||
| 114 | const auto& frontend{Core::System::GetInstance().GetAppletManager().GetAppletFrontendSet()}; | ||
| 115 | frontend.error->ShowCustomErrorText( | ||
| 116 | ResultCode(-1), "There was an error while attempting to use Boxcat.", | ||
| 117 | DOWNLOAD_RESULT_LOG_MESSAGES[static_cast<std::size_t>(res)], [] {}); | ||
| 118 | } | ||
| 119 | |||
| 120 | bool VfsRawCopyProgress(FileSys::VirtualFile src, FileSys::VirtualFile dest, | ||
| 121 | std::string_view dir_name, ProgressServiceBackend& progress, | ||
| 122 | std::size_t block_size = 0x1000) { | ||
| 123 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 124 | return false; | ||
| 125 | if (!dest->Resize(src->GetSize())) | ||
| 126 | return false; | ||
| 127 | |||
| 128 | progress.StartDownloadingFile(dir_name, src->GetName(), src->GetSize()); | ||
| 129 | |||
| 130 | std::vector<u8> temp(std::min(block_size, src->GetSize())); | ||
| 131 | for (std::size_t i = 0; i < src->GetSize(); i += block_size) { | ||
| 132 | const auto read = std::min(block_size, src->GetSize() - i); | ||
| 133 | |||
| 134 | if (src->Read(temp.data(), read, i) != read) { | ||
| 135 | return false; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (dest->Write(temp.data(), read, i) != read) { | ||
| 139 | return false; | ||
| 140 | } | ||
| 141 | |||
| 142 | progress.UpdateFileProgress(i); | ||
| 143 | } | ||
| 144 | |||
| 145 | progress.FinishDownloadingFile(); | ||
| 146 | |||
| 147 | return true; | ||
| 148 | } | ||
| 149 | |||
| 150 | bool VfsRawCopyDProgressSingle(FileSys::VirtualDir src, FileSys::VirtualDir dest, | ||
| 151 | ProgressServiceBackend& progress, std::size_t block_size = 0x1000) { | ||
| 152 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 153 | return false; | ||
| 154 | |||
| 155 | for (const auto& file : src->GetFiles()) { | ||
| 156 | const auto out_file = VfsCreateFileWrap(dest, file->GetName()); | ||
| 157 | if (!VfsRawCopyProgress(file, out_file, src->GetName(), progress, block_size)) { | ||
| 158 | return false; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | progress.CommitDirectory(src->GetName()); | ||
| 162 | |||
| 163 | return true; | ||
| 164 | } | ||
| 165 | |||
| 166 | bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest, | ||
| 167 | ProgressServiceBackend& progress, std::size_t block_size = 0x1000) { | ||
| 168 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 169 | return false; | ||
| 170 | |||
| 171 | for (const auto& dir : src->GetSubdirectories()) { | ||
| 172 | const auto out = dest->CreateSubdirectory(dir->GetName()); | ||
| 173 | if (!VfsRawCopyDProgressSingle(dir, out, progress, block_size)) { | ||
| 174 | return false; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | return true; | ||
| 179 | } | ||
| 180 | |||
| 181 | } // Anonymous namespace | ||
| 182 | |||
| 183 | class Boxcat::Client { | ||
| 184 | public: | ||
| 185 | Client(std::string path, u64 title_id, u64 build_id) | ||
| 186 | : path(std::move(path)), title_id(title_id), build_id(build_id) {} | ||
| 187 | |||
| 188 | DownloadResult DownloadDataZip() { | ||
| 189 | return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS, | ||
| 190 | "application/zip"); | ||
| 191 | } | ||
| 192 | |||
| 193 | DownloadResult DownloadLaunchParam() { | ||
| 194 | return DownloadInternal(fmt::format(BOXCAT_PATHNAME_LAUNCHPARAM, title_id), | ||
| 195 | TIMEOUT_SECONDS / 3, "application/octet-stream"); | ||
| 196 | } | ||
| 197 | |||
| 198 | private: | ||
| 199 | DownloadResult DownloadInternal(const std::string& resolved_path, u32 timeout_seconds, | ||
| 200 | const std::string& content_type_name) { | ||
| 201 | if (client == nullptr) { | ||
| 202 | client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT, timeout_seconds); | ||
| 203 | } | ||
| 204 | |||
| 205 | httplib::Headers headers{ | ||
| 206 | {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, | ||
| 207 | {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, | ||
| 208 | {std::string("Game-Build-Id"), fmt::format("{:016X}", build_id)}, | ||
| 209 | }; | ||
| 210 | |||
| 211 | if (FileUtil::Exists(path)) { | ||
| 212 | FileUtil::IOFile file{path, "rb"}; | ||
| 213 | if (file.IsOpen()) { | ||
| 214 | std::vector<u8> bytes(file.GetSize()); | ||
| 215 | file.ReadBytes(bytes.data(), bytes.size()); | ||
| 216 | const auto digest = DigestFile(bytes); | ||
| 217 | headers.insert({std::string("If-None-Match"), Common::HexToString(digest, false)}); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | const auto response = client->Get(resolved_path.c_str(), headers); | ||
| 222 | if (response == nullptr) | ||
| 223 | return DownloadResult::NoResponse; | ||
| 224 | |||
| 225 | if (response->status == static_cast<int>(ResponseStatus::NoUpdate)) | ||
| 226 | return DownloadResult::Success; | ||
| 227 | if (response->status == static_cast<int>(ResponseStatus::BadClientVersion)) | ||
| 228 | return DownloadResult::BadClientVersion; | ||
| 229 | if (response->status == static_cast<int>(ResponseStatus::NoMatchTitleId)) | ||
| 230 | return DownloadResult::NoMatchTitleId; | ||
| 231 | if (response->status == static_cast<int>(ResponseStatus::NoMatchBuildId)) | ||
| 232 | return DownloadResult::NoMatchBuildId; | ||
| 233 | if (response->status != static_cast<int>(ResponseStatus::Ok)) | ||
| 234 | return DownloadResult::GeneralWebError; | ||
| 235 | |||
| 236 | const auto content_type = response->headers.find("content-type"); | ||
| 237 | if (content_type == response->headers.end() || | ||
| 238 | content_type->second.find(content_type_name) == std::string::npos) { | ||
| 239 | return DownloadResult::InvalidContentType; | ||
| 240 | } | ||
| 241 | |||
| 242 | FileUtil::CreateFullPath(path); | ||
| 243 | FileUtil::IOFile file{path, "wb"}; | ||
| 244 | if (!file.IsOpen()) | ||
| 245 | return DownloadResult::GeneralFSError; | ||
| 246 | if (!file.Resize(response->body.size())) | ||
| 247 | return DownloadResult::GeneralFSError; | ||
| 248 | if (file.WriteBytes(response->body.data(), response->body.size()) != response->body.size()) | ||
| 249 | return DownloadResult::GeneralFSError; | ||
| 250 | |||
| 251 | return DownloadResult::Success; | ||
| 252 | } | ||
| 253 | |||
| 254 | using Digest = std::array<u8, 0x20>; | ||
| 255 | static Digest DigestFile(std::vector<u8> bytes) { | ||
| 256 | Digest out{}; | ||
| 257 | mbedtls_sha256(bytes.data(), bytes.size(), out.data(), 0); | ||
| 258 | return out; | ||
| 259 | } | ||
| 260 | |||
| 261 | std::unique_ptr<httplib::Client> client; | ||
| 262 | std::string path; | ||
| 263 | u64 title_id; | ||
| 264 | u64 build_id; | ||
| 265 | }; | ||
| 266 | |||
| 267 | Boxcat::Boxcat(DirectoryGetter getter) : Backend(std::move(getter)) {} | ||
| 268 | |||
| 269 | Boxcat::~Boxcat() = default; | ||
| 270 | |||
| 271 | void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title, | ||
| 272 | ProgressServiceBackend& progress, | ||
| 273 | std::optional<std::string> dir_name = {}) { | ||
| 274 | progress.SetNeedHLELock(true); | ||
| 275 | |||
| 276 | if (Settings::values.bcat_boxcat_local) { | ||
| 277 | LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download."); | ||
| 278 | const auto dir = dir_getter(title.title_id); | ||
| 279 | if (dir) | ||
| 280 | progress.SetTotalSize(dir->GetSize()); | ||
| 281 | progress.FinishDownload(RESULT_SUCCESS); | ||
| 282 | return; | ||
| 283 | } | ||
| 284 | |||
| 285 | const auto zip_path{GetZIPFilePath(title.title_id)}; | ||
| 286 | Boxcat::Client client{zip_path, title.title_id, title.build_id}; | ||
| 287 | |||
| 288 | progress.StartConnecting(); | ||
| 289 | |||
| 290 | const auto res = client.DownloadDataZip(); | ||
| 291 | if (res != DownloadResult::Success) { | ||
| 292 | LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); | ||
| 293 | |||
| 294 | if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { | ||
| 295 | FileUtil::Delete(zip_path); | ||
| 296 | } | ||
| 297 | |||
| 298 | HandleDownloadDisplayResult(res); | ||
| 299 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 300 | return; | ||
| 301 | } | ||
| 302 | |||
| 303 | progress.StartProcessingDataList(); | ||
| 304 | |||
| 305 | FileUtil::IOFile zip{zip_path, "rb"}; | ||
| 306 | const auto size = zip.GetSize(); | ||
| 307 | std::vector<u8> bytes(size); | ||
| 308 | if (!zip.IsOpen() || size == 0 || zip.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { | ||
| 309 | LOG_ERROR(Service_BCAT, "Boxcat failed to read ZIP file at path '{}'!", zip_path); | ||
| 310 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | const auto extracted = FileSys::ExtractZIP(std::make_shared<FileSys::VectorVfsFile>(bytes)); | ||
| 315 | if (extracted == nullptr) { | ||
| 316 | LOG_ERROR(Service_BCAT, "Boxcat failed to extract ZIP file!"); | ||
| 317 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 318 | return; | ||
| 319 | } | ||
| 320 | |||
| 321 | if (dir_name == std::nullopt) { | ||
| 322 | progress.SetTotalSize(extracted->GetSize()); | ||
| 323 | |||
| 324 | const auto target_dir = dir_getter(title.title_id); | ||
| 325 | if (target_dir == nullptr || !VfsRawCopyDProgress(extracted, target_dir, progress)) { | ||
| 326 | LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!"); | ||
| 327 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 328 | return; | ||
| 329 | } | ||
| 330 | } else { | ||
| 331 | const auto target_dir = dir_getter(title.title_id); | ||
| 332 | if (target_dir == nullptr) { | ||
| 333 | LOG_ERROR(Service_BCAT, "Boxcat failed to get directory for title ID!"); | ||
| 334 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 335 | return; | ||
| 336 | } | ||
| 337 | |||
| 338 | const auto target_sub = target_dir->GetSubdirectory(*dir_name); | ||
| 339 | const auto source_sub = extracted->GetSubdirectory(*dir_name); | ||
| 340 | |||
| 341 | progress.SetTotalSize(source_sub->GetSize()); | ||
| 342 | |||
| 343 | std::vector<std::string> filenames; | ||
| 344 | { | ||
| 345 | const auto files = target_sub->GetFiles(); | ||
| 346 | std::transform(files.begin(), files.end(), std::back_inserter(filenames), | ||
| 347 | [](const auto& vfile) { return vfile->GetName(); }); | ||
| 348 | } | ||
| 349 | |||
| 350 | for (const auto& filename : filenames) { | ||
| 351 | VfsDeleteFileWrap(target_sub, filename); | ||
| 352 | } | ||
| 353 | |||
| 354 | if (target_sub == nullptr || source_sub == nullptr || | ||
| 355 | !VfsRawCopyDProgressSingle(source_sub, target_sub, progress)) { | ||
| 356 | LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!"); | ||
| 357 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 358 | return; | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | progress.FinishDownload(RESULT_SUCCESS); | ||
| 363 | } | ||
| 364 | |||
| 365 | bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) { | ||
| 366 | is_syncing.exchange(true); | ||
| 367 | std::thread([this, title, &progress] { SynchronizeInternal(dir_getter, title, progress); }) | ||
| 368 | .detach(); | ||
| 369 | return true; | ||
| 370 | } | ||
| 371 | |||
| 372 | bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 373 | ProgressServiceBackend& progress) { | ||
| 374 | is_syncing.exchange(true); | ||
| 375 | std::thread( | ||
| 376 | [this, title, name, &progress] { SynchronizeInternal(dir_getter, title, progress, name); }) | ||
| 377 | .detach(); | ||
| 378 | return true; | ||
| 379 | } | ||
| 380 | |||
| 381 | bool Boxcat::Clear(u64 title_id) { | ||
| 382 | if (Settings::values.bcat_boxcat_local) { | ||
| 383 | LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping clear."); | ||
| 384 | return true; | ||
| 385 | } | ||
| 386 | |||
| 387 | const auto dir = dir_getter(title_id); | ||
| 388 | |||
| 389 | std::vector<std::string> dirnames; | ||
| 390 | |||
| 391 | for (const auto& subdir : dir->GetSubdirectories()) | ||
| 392 | dirnames.push_back(subdir->GetName()); | ||
| 393 | |||
| 394 | for (const auto& subdir : dirnames) { | ||
| 395 | if (!dir->DeleteSubdirectoryRecursive(subdir)) | ||
| 396 | return false; | ||
| 397 | } | ||
| 398 | |||
| 399 | return true; | ||
| 400 | } | ||
| 401 | |||
| 402 | void Boxcat::SetPassphrase(u64 title_id, const Passphrase& passphrase) { | ||
| 403 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, | ||
| 404 | Common::HexToString(passphrase)); | ||
| 405 | } | ||
| 406 | |||
| 407 | std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) { | ||
| 408 | const auto path{GetBINFilePath(title.title_id)}; | ||
| 409 | |||
| 410 | if (Settings::values.bcat_boxcat_local) { | ||
| 411 | LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download."); | ||
| 412 | } else { | ||
| 413 | Boxcat::Client client{path, title.title_id, title.build_id}; | ||
| 414 | |||
| 415 | const auto res = client.DownloadLaunchParam(); | ||
| 416 | if (res != DownloadResult::Success) { | ||
| 417 | LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); | ||
| 418 | |||
| 419 | if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { | ||
| 420 | FileUtil::Delete(path); | ||
| 421 | } | ||
| 422 | |||
| 423 | HandleDownloadDisplayResult(res); | ||
| 424 | return std::nullopt; | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | FileUtil::IOFile bin{path, "rb"}; | ||
| 429 | const auto size = bin.GetSize(); | ||
| 430 | std::vector<u8> bytes(size); | ||
| 431 | if (!bin.IsOpen() || size == 0 || bin.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { | ||
| 432 | LOG_ERROR(Service_BCAT, "Boxcat failed to read launch parameter binary at path '{}'!", | ||
| 433 | path); | ||
| 434 | return std::nullopt; | ||
| 435 | } | ||
| 436 | |||
| 437 | return bytes; | ||
| 438 | } | ||
| 439 | |||
| 440 | Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global, | ||
| 441 | std::map<std::string, EventStatus>& games) { | ||
| 442 | httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT), | ||
| 443 | static_cast<int>(TIMEOUT_SECONDS)}; | ||
| 444 | |||
| 445 | httplib::Headers headers{ | ||
| 446 | {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, | ||
| 447 | {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, | ||
| 448 | }; | ||
| 449 | |||
| 450 | const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers); | ||
| 451 | if (response == nullptr) | ||
| 452 | return StatusResult::Offline; | ||
| 453 | |||
| 454 | if (response->status == static_cast<int>(ResponseStatus::BadClientVersion)) | ||
| 455 | return StatusResult::BadClientVersion; | ||
| 456 | |||
| 457 | try { | ||
| 458 | nlohmann::json json = nlohmann::json::parse(response->body); | ||
| 459 | |||
| 460 | if (!json["online"].get<bool>()) | ||
| 461 | return StatusResult::Offline; | ||
| 462 | |||
| 463 | if (json["global"].is_null()) | ||
| 464 | global = std::nullopt; | ||
| 465 | else | ||
| 466 | global = json["global"].get<std::string>(); | ||
| 467 | |||
| 468 | if (json["games"].is_array()) { | ||
| 469 | for (const auto object : json["games"]) { | ||
| 470 | if (object.is_object() && object.find("name") != object.end()) { | ||
| 471 | EventStatus detail{}; | ||
| 472 | if (object["header"].is_string()) { | ||
| 473 | detail.header = object["header"].get<std::string>(); | ||
| 474 | } else { | ||
| 475 | detail.header = std::nullopt; | ||
| 476 | } | ||
| 477 | |||
| 478 | if (object["footer"].is_string()) { | ||
| 479 | detail.footer = object["footer"].get<std::string>(); | ||
| 480 | } else { | ||
| 481 | detail.footer = std::nullopt; | ||
| 482 | } | ||
| 483 | |||
| 484 | if (object["events"].is_array()) { | ||
| 485 | for (const auto& event : object["events"]) { | ||
| 486 | if (!event.is_string()) | ||
| 487 | continue; | ||
| 488 | detail.events.push_back(event.get<std::string>()); | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | games.insert_or_assign(object["name"], std::move(detail)); | ||
| 493 | } | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | return StatusResult::Success; | ||
| 498 | } catch (const nlohmann::json::parse_error& e) { | ||
| 499 | return StatusResult::ParseError; | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | } // namespace Service::BCAT | ||
diff --git a/src/core/hle/service/bcat/backend/boxcat.h b/src/core/hle/service/bcat/backend/boxcat.h new file mode 100644 index 000000000..601151189 --- /dev/null +++ b/src/core/hle/service/bcat/backend/boxcat.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <map> | ||
| 9 | #include <optional> | ||
| 10 | #include "core/hle/service/bcat/backend/backend.h" | ||
| 11 | |||
| 12 | namespace Service::BCAT { | ||
| 13 | |||
| 14 | struct EventStatus { | ||
| 15 | std::optional<std::string> header; | ||
| 16 | std::optional<std::string> footer; | ||
| 17 | std::vector<std::string> events; | ||
| 18 | }; | ||
| 19 | |||
| 20 | /// Boxcat is yuzu's custom backend implementation of Nintendo's BCAT service. It is free to use and | ||
| 21 | /// doesn't require a switch or nintendo account. The content is controlled by the yuzu team. | ||
| 22 | class Boxcat final : public Backend { | ||
| 23 | friend void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title, | ||
| 24 | ProgressServiceBackend& progress, | ||
| 25 | std::optional<std::string> dir_name); | ||
| 26 | |||
| 27 | public: | ||
| 28 | explicit Boxcat(DirectoryGetter getter); | ||
| 29 | ~Boxcat() override; | ||
| 30 | |||
| 31 | bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override; | ||
| 32 | bool SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 33 | ProgressServiceBackend& progress) override; | ||
| 34 | |||
| 35 | bool Clear(u64 title_id) override; | ||
| 36 | |||
| 37 | void SetPassphrase(u64 title_id, const Passphrase& passphrase) override; | ||
| 38 | |||
| 39 | std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override; | ||
| 40 | |||
| 41 | enum class StatusResult { | ||
| 42 | Success, | ||
| 43 | Offline, | ||
| 44 | ParseError, | ||
| 45 | BadClientVersion, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static StatusResult GetStatus(std::optional<std::string>& global, | ||
| 49 | std::map<std::string, EventStatus>& games); | ||
| 50 | |||
| 51 | private: | ||
| 52 | std::atomic_bool is_syncing{false}; | ||
| 53 | |||
| 54 | class Client; | ||
| 55 | std::unique_ptr<Client> client; | ||
| 56 | }; | ||
| 57 | |||
| 58 | } // namespace Service::BCAT | ||
diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp index 179aa4949..c2f946424 100644 --- a/src/core/hle/service/bcat/bcat.cpp +++ b/src/core/hle/service/bcat/bcat.cpp | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::BCAT { | 7 | namespace Service::BCAT { |
| 8 | 8 | ||
| 9 | BCAT::BCAT(std::shared_ptr<Module> module, const char* name) | 9 | BCAT::BCAT(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc, const char* name) |
| 10 | : Module::Interface(std::move(module), name) { | 10 | : Module::Interface(std::move(module), fsc, name) { |
| 11 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 12 | {0, &BCAT::CreateBcatService, "CreateBcatService"}, | 13 | {0, &BCAT::CreateBcatService, "CreateBcatService"}, |
| 14 | {1, &BCAT::CreateDeliveryCacheStorageService, "CreateDeliveryCacheStorageService"}, | ||
| 15 | {2, &BCAT::CreateDeliveryCacheStorageServiceWithApplicationId, "CreateDeliveryCacheStorageServiceWithApplicationId"}, | ||
| 13 | }; | 16 | }; |
| 17 | // clang-format on | ||
| 14 | RegisterHandlers(functions); | 18 | RegisterHandlers(functions); |
| 15 | } | 19 | } |
| 16 | 20 | ||
diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h index 802bd689a..813073658 100644 --- a/src/core/hle/service/bcat/bcat.h +++ b/src/core/hle/service/bcat/bcat.h | |||
| @@ -10,7 +10,8 @@ namespace Service::BCAT { | |||
| 10 | 10 | ||
| 11 | class BCAT final : public Module::Interface { | 11 | class BCAT final : public Module::Interface { |
| 12 | public: | 12 | public: |
| 13 | explicit BCAT(std::shared_ptr<Module> module, const char* name); | 13 | explicit BCAT(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc, |
| 14 | const char* name); | ||
| 14 | ~BCAT() override; | 15 | ~BCAT() override; |
| 15 | }; | 16 | }; |
| 16 | 17 | ||
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index b7bd738fc..b3fed56c7 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp | |||
| @@ -2,34 +2,254 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cctype> | ||
| 6 | #include <mbedtls/md5.h> | ||
| 7 | #include "backend/boxcat.h" | ||
| 8 | #include "common/hex_util.h" | ||
| 5 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/string_util.h" | ||
| 11 | #include "core/file_sys/vfs.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | 12 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/process.h" | ||
| 14 | #include "core/hle/kernel/readable_event.h" | ||
| 15 | #include "core/hle/kernel/writable_event.h" | ||
| 16 | #include "core/hle/service/bcat/backend/backend.h" | ||
| 7 | #include "core/hle/service/bcat/bcat.h" | 17 | #include "core/hle/service/bcat/bcat.h" |
| 8 | #include "core/hle/service/bcat/module.h" | 18 | #include "core/hle/service/bcat/module.h" |
| 19 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 20 | #include "core/settings.h" | ||
| 9 | 21 | ||
| 10 | namespace Service::BCAT { | 22 | namespace Service::BCAT { |
| 11 | 23 | ||
| 24 | constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::BCAT, 1}; | ||
| 25 | constexpr ResultCode ERROR_FAILED_OPEN_ENTITY{ErrorModule::BCAT, 2}; | ||
| 26 | constexpr ResultCode ERROR_ENTITY_ALREADY_OPEN{ErrorModule::BCAT, 6}; | ||
| 27 | constexpr ResultCode ERROR_NO_OPEN_ENTITY{ErrorModule::BCAT, 7}; | ||
| 28 | |||
| 29 | // The command to clear the delivery cache just calls fs IFileSystem DeleteFile on all of the files | ||
| 30 | // and if any of them have a non-zero result it just forwards that result. This is the FS error code | ||
| 31 | // for permission denied, which is the closest approximation of this scenario. | ||
| 32 | constexpr ResultCode ERROR_FAILED_CLEAR_CACHE{ErrorModule::FS, 6400}; | ||
| 33 | |||
| 34 | using BCATDigest = std::array<u8, 0x10>; | ||
| 35 | |||
| 36 | namespace { | ||
| 37 | |||
| 38 | u64 GetCurrentBuildID() { | ||
| 39 | const auto& id = Core::System::GetInstance().GetCurrentProcessBuildID(); | ||
| 40 | u64 out{}; | ||
| 41 | std::memcpy(&out, id.data(), sizeof(u64)); | ||
| 42 | return out; | ||
| 43 | } | ||
| 44 | |||
| 45 | // The digest is only used to determine if a file is unique compared to others of the same name. | ||
| 46 | // Since the algorithm isn't ever checked in game, MD5 is safe. | ||
| 47 | BCATDigest DigestFile(const FileSys::VirtualFile& file) { | ||
| 48 | BCATDigest out{}; | ||
| 49 | const auto bytes = file->ReadAllBytes(); | ||
| 50 | mbedtls_md5(bytes.data(), bytes.size(), out.data()); | ||
| 51 | return out; | ||
| 52 | } | ||
| 53 | |||
| 54 | // For a name to be valid it must be non-empty, must have a null terminating character as the final | ||
| 55 | // char, can only contain numbers, letters, underscores and a hyphen if directory and a period if | ||
| 56 | // file. | ||
| 57 | bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array<char, 0x20> name, | ||
| 58 | char match_char) { | ||
| 59 | const auto null_chars = std::count(name.begin(), name.end(), 0); | ||
| 60 | const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) { | ||
| 61 | return !std::isalnum(static_cast<u8>(c)) && c != '_' && c != match_char && c != '\0'; | ||
| 62 | }); | ||
| 63 | if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') { | ||
| 64 | LOG_ERROR(Service_BCAT, "Name passed was invalid!"); | ||
| 65 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 66 | rb.Push(ERROR_INVALID_ARGUMENT); | ||
| 67 | return false; | ||
| 68 | } | ||
| 69 | |||
| 70 | return true; | ||
| 71 | } | ||
| 72 | |||
| 73 | bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, DirectoryName name) { | ||
| 74 | return VerifyNameValidInternal(ctx, name, '-'); | ||
| 75 | } | ||
| 76 | |||
| 77 | bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, FileName name) { | ||
| 78 | return VerifyNameValidInternal(ctx, name, '.'); | ||
| 79 | } | ||
| 80 | |||
| 81 | } // Anonymous namespace | ||
| 82 | |||
| 83 | struct DeliveryCacheDirectoryEntry { | ||
| 84 | FileName name; | ||
| 85 | u64 size; | ||
| 86 | BCATDigest digest; | ||
| 87 | }; | ||
| 88 | |||
| 89 | class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { | ||
| 90 | public: | ||
| 91 | IDeliveryCacheProgressService(Kernel::SharedPtr<Kernel::ReadableEvent> event, | ||
| 92 | const DeliveryCacheProgressImpl& impl) | ||
| 93 | : ServiceFramework{"IDeliveryCacheProgressService"}, event(std::move(event)), impl(impl) { | ||
| 94 | // clang-format off | ||
| 95 | static const FunctionInfo functions[] = { | ||
| 96 | {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, | ||
| 97 | {1, &IDeliveryCacheProgressService::GetImpl, "GetImpl"}, | ||
| 98 | }; | ||
| 99 | // clang-format on | ||
| 100 | |||
| 101 | RegisterHandlers(functions); | ||
| 102 | } | ||
| 103 | |||
| 104 | private: | ||
| 105 | void GetEvent(Kernel::HLERequestContext& ctx) { | ||
| 106 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 107 | |||
| 108 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 109 | rb.Push(RESULT_SUCCESS); | ||
| 110 | rb.PushCopyObjects(event); | ||
| 111 | } | ||
| 112 | |||
| 113 | void GetImpl(Kernel::HLERequestContext& ctx) { | ||
| 114 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 115 | |||
| 116 | ctx.WriteBuffer(&impl, sizeof(DeliveryCacheProgressImpl)); | ||
| 117 | |||
| 118 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 119 | rb.Push(RESULT_SUCCESS); | ||
| 120 | } | ||
| 121 | |||
| 122 | Kernel::SharedPtr<Kernel::ReadableEvent> event; | ||
| 123 | const DeliveryCacheProgressImpl& impl; | ||
| 124 | }; | ||
| 125 | |||
| 12 | class IBcatService final : public ServiceFramework<IBcatService> { | 126 | class IBcatService final : public ServiceFramework<IBcatService> { |
| 13 | public: | 127 | public: |
| 14 | IBcatService() : ServiceFramework("IBcatService") { | 128 | IBcatService(Backend& backend) : ServiceFramework("IBcatService"), backend(backend) { |
| 129 | // clang-format off | ||
| 15 | static const FunctionInfo functions[] = { | 130 | static const FunctionInfo functions[] = { |
| 16 | {10100, nullptr, "RequestSyncDeliveryCache"}, | 131 | {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"}, |
| 17 | {10101, nullptr, "RequestSyncDeliveryCacheWithDirectoryName"}, | 132 | {10101, &IBcatService::RequestSyncDeliveryCacheWithDirectoryName, "RequestSyncDeliveryCacheWithDirectoryName"}, |
| 18 | {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, | 133 | {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, |
| 19 | {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, | 134 | {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, |
| 20 | {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, | 135 | {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, |
| 21 | {30100, nullptr, "SetPassphrase"}, | 136 | {30100, &IBcatService::SetPassphrase, "SetPassphrase"}, |
| 22 | {30200, nullptr, "RegisterBackgroundDeliveryTask"}, | 137 | {30200, nullptr, "RegisterBackgroundDeliveryTask"}, |
| 23 | {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, | 138 | {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, |
| 24 | {30202, nullptr, "BlockDeliveryTask"}, | 139 | {30202, nullptr, "BlockDeliveryTask"}, |
| 25 | {30203, nullptr, "UnblockDeliveryTask"}, | 140 | {30203, nullptr, "UnblockDeliveryTask"}, |
| 26 | {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, | 141 | {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, |
| 27 | {90200, nullptr, "GetDeliveryList"}, | 142 | {90200, nullptr, "GetDeliveryList"}, |
| 28 | {90201, nullptr, "ClearDeliveryCacheStorage"}, | 143 | {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"}, |
| 29 | {90300, nullptr, "GetPushNotificationLog"}, | 144 | {90300, nullptr, "GetPushNotificationLog"}, |
| 30 | }; | 145 | }; |
| 146 | // clang-format on | ||
| 31 | RegisterHandlers(functions); | 147 | RegisterHandlers(functions); |
| 32 | } | 148 | } |
| 149 | |||
| 150 | private: | ||
| 151 | enum class SyncType { | ||
| 152 | Normal, | ||
| 153 | Directory, | ||
| 154 | Count, | ||
| 155 | }; | ||
| 156 | |||
| 157 | std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) { | ||
| 158 | auto& backend{progress.at(static_cast<std::size_t>(type))}; | ||
| 159 | return std::make_shared<IDeliveryCacheProgressService>(backend.GetEvent(), | ||
| 160 | backend.GetImpl()); | ||
| 161 | } | ||
| 162 | |||
| 163 | void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) { | ||
| 164 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 165 | |||
| 166 | backend.Synchronize({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()}, | ||
| 167 | progress.at(static_cast<std::size_t>(SyncType::Normal))); | ||
| 168 | |||
| 169 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 170 | rb.Push(RESULT_SUCCESS); | ||
| 171 | rb.PushIpcInterface(CreateProgressService(SyncType::Normal)); | ||
| 172 | } | ||
| 173 | |||
| 174 | void RequestSyncDeliveryCacheWithDirectoryName(Kernel::HLERequestContext& ctx) { | ||
| 175 | IPC::RequestParser rp{ctx}; | ||
| 176 | const auto name_raw = rp.PopRaw<DirectoryName>(); | ||
| 177 | const auto name = | ||
| 178 | Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); | ||
| 179 | |||
| 180 | LOG_DEBUG(Service_BCAT, "called, name={}", name); | ||
| 181 | |||
| 182 | backend.SynchronizeDirectory({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()}, | ||
| 183 | name, | ||
| 184 | progress.at(static_cast<std::size_t>(SyncType::Directory))); | ||
| 185 | |||
| 186 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 187 | rb.Push(RESULT_SUCCESS); | ||
| 188 | rb.PushIpcInterface(CreateProgressService(SyncType::Directory)); | ||
| 189 | } | ||
| 190 | |||
| 191 | void SetPassphrase(Kernel::HLERequestContext& ctx) { | ||
| 192 | IPC::RequestParser rp{ctx}; | ||
| 193 | const auto title_id = rp.PopRaw<u64>(); | ||
| 194 | |||
| 195 | const auto passphrase_raw = ctx.ReadBuffer(); | ||
| 196 | |||
| 197 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, | ||
| 198 | Common::HexToString(passphrase_raw)); | ||
| 199 | |||
| 200 | if (title_id == 0) { | ||
| 201 | LOG_ERROR(Service_BCAT, "Invalid title ID!"); | ||
| 202 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 203 | rb.Push(ERROR_INVALID_ARGUMENT); | ||
| 204 | } | ||
| 205 | |||
| 206 | if (passphrase_raw.size() > 0x40) { | ||
| 207 | LOG_ERROR(Service_BCAT, "Passphrase too large!"); | ||
| 208 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 209 | rb.Push(ERROR_INVALID_ARGUMENT); | ||
| 210 | return; | ||
| 211 | } | ||
| 212 | |||
| 213 | Passphrase passphrase{}; | ||
| 214 | std::memcpy(passphrase.data(), passphrase_raw.data(), | ||
| 215 | std::min(passphrase.size(), passphrase_raw.size())); | ||
| 216 | |||
| 217 | backend.SetPassphrase(title_id, passphrase); | ||
| 218 | |||
| 219 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 220 | rb.Push(RESULT_SUCCESS); | ||
| 221 | } | ||
| 222 | |||
| 223 | void ClearDeliveryCacheStorage(Kernel::HLERequestContext& ctx) { | ||
| 224 | IPC::RequestParser rp{ctx}; | ||
| 225 | const auto title_id = rp.PopRaw<u64>(); | ||
| 226 | |||
| 227 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); | ||
| 228 | |||
| 229 | if (title_id == 0) { | ||
| 230 | LOG_ERROR(Service_BCAT, "Invalid title ID!"); | ||
| 231 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 232 | rb.Push(ERROR_INVALID_ARGUMENT); | ||
| 233 | return; | ||
| 234 | } | ||
| 235 | |||
| 236 | if (!backend.Clear(title_id)) { | ||
| 237 | LOG_ERROR(Service_BCAT, "Could not clear the directory successfully!"); | ||
| 238 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 239 | rb.Push(ERROR_FAILED_CLEAR_CACHE); | ||
| 240 | return; | ||
| 241 | } | ||
| 242 | |||
| 243 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 244 | rb.Push(RESULT_SUCCESS); | ||
| 245 | } | ||
| 246 | |||
| 247 | Backend& backend; | ||
| 248 | |||
| 249 | std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress{ | ||
| 250 | ProgressServiceBackend{"Normal"}, | ||
| 251 | ProgressServiceBackend{"Directory"}, | ||
| 252 | }; | ||
| 33 | }; | 253 | }; |
| 34 | 254 | ||
| 35 | void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { | 255 | void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { |
| @@ -37,20 +257,331 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { | |||
| 37 | 257 | ||
| 38 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 258 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 39 | rb.Push(RESULT_SUCCESS); | 259 | rb.Push(RESULT_SUCCESS); |
| 40 | rb.PushIpcInterface<IBcatService>(); | 260 | rb.PushIpcInterface<IBcatService>(*backend); |
| 261 | } | ||
| 262 | |||
| 263 | class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> { | ||
| 264 | public: | ||
| 265 | IDeliveryCacheFileService(FileSys::VirtualDir root_) | ||
| 266 | : ServiceFramework{"IDeliveryCacheFileService"}, root(std::move(root_)) { | ||
| 267 | // clang-format off | ||
| 268 | static const FunctionInfo functions[] = { | ||
| 269 | {0, &IDeliveryCacheFileService::Open, "Open"}, | ||
| 270 | {1, &IDeliveryCacheFileService::Read, "Read"}, | ||
| 271 | {2, &IDeliveryCacheFileService::GetSize, "GetSize"}, | ||
| 272 | {3, &IDeliveryCacheFileService::GetDigest, "GetDigest"}, | ||
| 273 | }; | ||
| 274 | // clang-format on | ||
| 275 | |||
| 276 | RegisterHandlers(functions); | ||
| 277 | } | ||
| 278 | |||
| 279 | private: | ||
| 280 | void Open(Kernel::HLERequestContext& ctx) { | ||
| 281 | IPC::RequestParser rp{ctx}; | ||
| 282 | const auto dir_name_raw = rp.PopRaw<DirectoryName>(); | ||
| 283 | const auto file_name_raw = rp.PopRaw<FileName>(); | ||
| 284 | |||
| 285 | const auto dir_name = | ||
| 286 | Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size()); | ||
| 287 | const auto file_name = | ||
| 288 | Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size()); | ||
| 289 | |||
| 290 | LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name); | ||
| 291 | |||
| 292 | if (!VerifyNameValidDir(ctx, dir_name_raw) || !VerifyNameValidFile(ctx, file_name_raw)) | ||
| 293 | return; | ||
| 294 | |||
| 295 | if (current_file != nullptr) { | ||
| 296 | LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); | ||
| 297 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 298 | rb.Push(ERROR_ENTITY_ALREADY_OPEN); | ||
| 299 | return; | ||
| 300 | } | ||
| 301 | |||
| 302 | const auto dir = root->GetSubdirectory(dir_name); | ||
| 303 | |||
| 304 | if (dir == nullptr) { | ||
| 305 | LOG_ERROR(Service_BCAT, "The directory of name={} couldn't be opened!", dir_name); | ||
| 306 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 307 | rb.Push(ERROR_FAILED_OPEN_ENTITY); | ||
| 308 | return; | ||
| 309 | } | ||
| 310 | |||
| 311 | current_file = dir->GetFile(file_name); | ||
| 312 | |||
| 313 | if (current_file == nullptr) { | ||
| 314 | LOG_ERROR(Service_BCAT, "The file of name={} couldn't be opened!", file_name); | ||
| 315 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 316 | rb.Push(ERROR_FAILED_OPEN_ENTITY); | ||
| 317 | return; | ||
| 318 | } | ||
| 319 | |||
| 320 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 321 | rb.Push(RESULT_SUCCESS); | ||
| 322 | } | ||
| 323 | |||
| 324 | void Read(Kernel::HLERequestContext& ctx) { | ||
| 325 | IPC::RequestParser rp{ctx}; | ||
| 326 | const auto offset{rp.PopRaw<u64>()}; | ||
| 327 | |||
| 328 | auto size = ctx.GetWriteBufferSize(); | ||
| 329 | |||
| 330 | LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, size); | ||
| 331 | |||
| 332 | if (current_file == nullptr) { | ||
| 333 | LOG_ERROR(Service_BCAT, "There is no file currently open!"); | ||
| 334 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 335 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 336 | } | ||
| 337 | |||
| 338 | size = std::min<u64>(current_file->GetSize() - offset, size); | ||
| 339 | const auto buffer = current_file->ReadBytes(size, offset); | ||
| 340 | ctx.WriteBuffer(buffer); | ||
| 341 | |||
| 342 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 343 | rb.Push(RESULT_SUCCESS); | ||
| 344 | rb.Push<u64>(buffer.size()); | ||
| 345 | } | ||
| 346 | |||
| 347 | void GetSize(Kernel::HLERequestContext& ctx) { | ||
| 348 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 349 | |||
| 350 | if (current_file == nullptr) { | ||
| 351 | LOG_ERROR(Service_BCAT, "There is no file currently open!"); | ||
| 352 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 353 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 354 | } | ||
| 355 | |||
| 356 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 357 | rb.Push(RESULT_SUCCESS); | ||
| 358 | rb.Push<u64>(current_file->GetSize()); | ||
| 359 | } | ||
| 360 | |||
| 361 | void GetDigest(Kernel::HLERequestContext& ctx) { | ||
| 362 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 363 | |||
| 364 | if (current_file == nullptr) { | ||
| 365 | LOG_ERROR(Service_BCAT, "There is no file currently open!"); | ||
| 366 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 367 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 368 | } | ||
| 369 | |||
| 370 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 371 | rb.Push(RESULT_SUCCESS); | ||
| 372 | rb.PushRaw(DigestFile(current_file)); | ||
| 373 | } | ||
| 374 | |||
| 375 | FileSys::VirtualDir root; | ||
| 376 | FileSys::VirtualFile current_file; | ||
| 377 | }; | ||
| 378 | |||
| 379 | class IDeliveryCacheDirectoryService final | ||
| 380 | : public ServiceFramework<IDeliveryCacheDirectoryService> { | ||
| 381 | public: | ||
| 382 | IDeliveryCacheDirectoryService(FileSys::VirtualDir root_) | ||
| 383 | : ServiceFramework{"IDeliveryCacheDirectoryService"}, root(std::move(root_)) { | ||
| 384 | // clang-format off | ||
| 385 | static const FunctionInfo functions[] = { | ||
| 386 | {0, &IDeliveryCacheDirectoryService::Open, "Open"}, | ||
| 387 | {1, &IDeliveryCacheDirectoryService::Read, "Read"}, | ||
| 388 | {2, &IDeliveryCacheDirectoryService::GetCount, "GetCount"}, | ||
| 389 | }; | ||
| 390 | // clang-format on | ||
| 391 | |||
| 392 | RegisterHandlers(functions); | ||
| 393 | } | ||
| 394 | |||
| 395 | private: | ||
| 396 | void Open(Kernel::HLERequestContext& ctx) { | ||
| 397 | IPC::RequestParser rp{ctx}; | ||
| 398 | const auto name_raw = rp.PopRaw<DirectoryName>(); | ||
| 399 | const auto name = | ||
| 400 | Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); | ||
| 401 | |||
| 402 | LOG_DEBUG(Service_BCAT, "called, name={}", name); | ||
| 403 | |||
| 404 | if (!VerifyNameValidDir(ctx, name_raw)) | ||
| 405 | return; | ||
| 406 | |||
| 407 | if (current_dir != nullptr) { | ||
| 408 | LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); | ||
| 409 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 410 | rb.Push(ERROR_ENTITY_ALREADY_OPEN); | ||
| 411 | return; | ||
| 412 | } | ||
| 413 | |||
| 414 | current_dir = root->GetSubdirectory(name); | ||
| 415 | |||
| 416 | if (current_dir == nullptr) { | ||
| 417 | LOG_ERROR(Service_BCAT, "Failed to open the directory name={}!", name); | ||
| 418 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 419 | rb.Push(ERROR_FAILED_OPEN_ENTITY); | ||
| 420 | return; | ||
| 421 | } | ||
| 422 | |||
| 423 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 424 | rb.Push(RESULT_SUCCESS); | ||
| 425 | } | ||
| 426 | |||
| 427 | void Read(Kernel::HLERequestContext& ctx) { | ||
| 428 | auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry); | ||
| 429 | |||
| 430 | LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size); | ||
| 431 | |||
| 432 | if (current_dir == nullptr) { | ||
| 433 | LOG_ERROR(Service_BCAT, "There is no open directory!"); | ||
| 434 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 435 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 436 | return; | ||
| 437 | } | ||
| 438 | |||
| 439 | const auto files = current_dir->GetFiles(); | ||
| 440 | write_size = std::min<u64>(write_size, files.size()); | ||
| 441 | std::vector<DeliveryCacheDirectoryEntry> entries(write_size); | ||
| 442 | std::transform( | ||
| 443 | files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) { | ||
| 444 | FileName name{}; | ||
| 445 | std::memcpy(name.data(), file->GetName().data(), | ||
| 446 | std::min(file->GetName().size(), name.size())); | ||
| 447 | return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)}; | ||
| 448 | }); | ||
| 449 | |||
| 450 | ctx.WriteBuffer(entries); | ||
| 451 | |||
| 452 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 453 | rb.Push(RESULT_SUCCESS); | ||
| 454 | rb.Push<u32>(write_size * sizeof(DeliveryCacheDirectoryEntry)); | ||
| 455 | } | ||
| 456 | |||
| 457 | void GetCount(Kernel::HLERequestContext& ctx) { | ||
| 458 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 459 | |||
| 460 | if (current_dir == nullptr) { | ||
| 461 | LOG_ERROR(Service_BCAT, "There is no open directory!"); | ||
| 462 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 463 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 464 | return; | ||
| 465 | } | ||
| 466 | |||
| 467 | const auto files = current_dir->GetFiles(); | ||
| 468 | |||
| 469 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 470 | rb.Push(RESULT_SUCCESS); | ||
| 471 | rb.Push<u32>(files.size()); | ||
| 472 | } | ||
| 473 | |||
| 474 | FileSys::VirtualDir root; | ||
| 475 | FileSys::VirtualDir current_dir; | ||
| 476 | }; | ||
| 477 | |||
| 478 | class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> { | ||
| 479 | public: | ||
| 480 | IDeliveryCacheStorageService(FileSys::VirtualDir root_) | ||
| 481 | : ServiceFramework{"IDeliveryCacheStorageService"}, root(std::move(root_)) { | ||
| 482 | // clang-format off | ||
| 483 | static const FunctionInfo functions[] = { | ||
| 484 | {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"}, | ||
| 485 | {1, &IDeliveryCacheStorageService::CreateDirectoryService, "CreateDirectoryService"}, | ||
| 486 | {10, &IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory, "EnumerateDeliveryCacheDirectory"}, | ||
| 487 | }; | ||
| 488 | // clang-format on | ||
| 489 | |||
| 490 | RegisterHandlers(functions); | ||
| 491 | |||
| 492 | for (const auto& subdir : root->GetSubdirectories()) { | ||
| 493 | DirectoryName name{}; | ||
| 494 | std::memcpy(name.data(), subdir->GetName().data(), | ||
| 495 | std::min(sizeof(DirectoryName) - 1, subdir->GetName().size())); | ||
| 496 | entries.push_back(name); | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | private: | ||
| 501 | void CreateFileService(Kernel::HLERequestContext& ctx) { | ||
| 502 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 503 | |||
| 504 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 505 | rb.Push(RESULT_SUCCESS); | ||
| 506 | rb.PushIpcInterface<IDeliveryCacheFileService>(root); | ||
| 507 | } | ||
| 508 | |||
| 509 | void CreateDirectoryService(Kernel::HLERequestContext& ctx) { | ||
| 510 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 511 | |||
| 512 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 513 | rb.Push(RESULT_SUCCESS); | ||
| 514 | rb.PushIpcInterface<IDeliveryCacheDirectoryService>(root); | ||
| 515 | } | ||
| 516 | |||
| 517 | void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { | ||
| 518 | auto size = ctx.GetWriteBufferSize() / sizeof(DirectoryName); | ||
| 519 | |||
| 520 | LOG_DEBUG(Service_BCAT, "called, size={:016X}", size); | ||
| 521 | |||
| 522 | size = std::min<u64>(size, entries.size() - next_read_index); | ||
| 523 | ctx.WriteBuffer(entries.data() + next_read_index, size * sizeof(DirectoryName)); | ||
| 524 | next_read_index += size; | ||
| 525 | |||
| 526 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 527 | rb.Push(RESULT_SUCCESS); | ||
| 528 | rb.Push<u32>(size); | ||
| 529 | } | ||
| 530 | |||
| 531 | FileSys::VirtualDir root; | ||
| 532 | std::vector<DirectoryName> entries; | ||
| 533 | u64 next_read_index = 0; | ||
| 534 | }; | ||
| 535 | |||
| 536 | void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { | ||
| 537 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 538 | |||
| 539 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 540 | rb.Push(RESULT_SUCCESS); | ||
| 541 | rb.PushIpcInterface<IDeliveryCacheStorageService>( | ||
| 542 | fsc.GetBCATDirectory(Core::CurrentProcess()->GetTitleID())); | ||
| 543 | } | ||
| 544 | |||
| 545 | void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( | ||
| 546 | Kernel::HLERequestContext& ctx) { | ||
| 547 | IPC::RequestParser rp{ctx}; | ||
| 548 | const auto title_id = rp.PopRaw<u64>(); | ||
| 549 | |||
| 550 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); | ||
| 551 | |||
| 552 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 553 | rb.Push(RESULT_SUCCESS); | ||
| 554 | rb.PushIpcInterface<IDeliveryCacheStorageService>(fsc.GetBCATDirectory(title_id)); | ||
| 555 | } | ||
| 556 | |||
| 557 | std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter) { | ||
| 558 | const auto backend = Settings::values.bcat_backend; | ||
| 559 | |||
| 560 | #ifdef YUZU_ENABLE_BOXCAT | ||
| 561 | if (backend == "boxcat") | ||
| 562 | return std::make_unique<Boxcat>(std::move(getter)); | ||
| 563 | #endif | ||
| 564 | |||
| 565 | return std::make_unique<NullBackend>(std::move(getter)); | ||
| 41 | } | 566 | } |
| 42 | 567 | ||
| 43 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 568 | Module::Interface::Interface(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc, |
| 44 | : ServiceFramework(name), module(std::move(module)) {} | 569 | const char* name) |
| 570 | : ServiceFramework(name), module(std::move(module)), fsc(fsc), | ||
| 571 | backend(CreateBackendFromSettings([&fsc](u64 tid) { return fsc.GetBCATDirectory(tid); })) {} | ||
| 45 | 572 | ||
| 46 | Module::Interface::~Interface() = default; | 573 | Module::Interface::~Interface() = default; |
| 47 | 574 | ||
| 48 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 575 | void InstallInterfaces(Core::System& system) { |
| 49 | auto module = std::make_shared<Module>(); | 576 | auto module = std::make_shared<Module>(); |
| 50 | std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager); | 577 | std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:a") |
| 51 | std::make_shared<BCAT>(module, "bcat:m")->InstallAsService(service_manager); | 578 | ->InstallAsService(system.ServiceManager()); |
| 52 | std::make_shared<BCAT>(module, "bcat:u")->InstallAsService(service_manager); | 579 | std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:m") |
| 53 | std::make_shared<BCAT>(module, "bcat:s")->InstallAsService(service_manager); | 580 | ->InstallAsService(system.ServiceManager()); |
| 581 | std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:u") | ||
| 582 | ->InstallAsService(system.ServiceManager()); | ||
| 583 | std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:s") | ||
| 584 | ->InstallAsService(system.ServiceManager()); | ||
| 54 | } | 585 | } |
| 55 | 586 | ||
| 56 | } // namespace Service::BCAT | 587 | } // namespace Service::BCAT |
diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h index f0d63cab0..27469926a 100644 --- a/src/core/hle/service/bcat/module.h +++ b/src/core/hle/service/bcat/module.h | |||
| @@ -6,23 +6,39 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Service::BCAT { | 9 | namespace Service { |
| 10 | |||
| 11 | namespace FileSystem { | ||
| 12 | class FileSystemController; | ||
| 13 | } // namespace FileSystem | ||
| 14 | |||
| 15 | namespace BCAT { | ||
| 16 | |||
| 17 | class Backend; | ||
| 10 | 18 | ||
| 11 | class Module final { | 19 | class Module final { |
| 12 | public: | 20 | public: |
| 13 | class Interface : public ServiceFramework<Interface> { | 21 | class Interface : public ServiceFramework<Interface> { |
| 14 | public: | 22 | public: |
| 15 | explicit Interface(std::shared_ptr<Module> module, const char* name); | 23 | explicit Interface(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc, |
| 24 | const char* name); | ||
| 16 | ~Interface() override; | 25 | ~Interface() override; |
| 17 | 26 | ||
| 18 | void CreateBcatService(Kernel::HLERequestContext& ctx); | 27 | void CreateBcatService(Kernel::HLERequestContext& ctx); |
| 28 | void CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx); | ||
| 29 | void CreateDeliveryCacheStorageServiceWithApplicationId(Kernel::HLERequestContext& ctx); | ||
| 19 | 30 | ||
| 20 | protected: | 31 | protected: |
| 32 | FileSystem::FileSystemController& fsc; | ||
| 33 | |||
| 21 | std::shared_ptr<Module> module; | 34 | std::shared_ptr<Module> module; |
| 35 | std::unique_ptr<Backend> backend; | ||
| 22 | }; | 36 | }; |
| 23 | }; | 37 | }; |
| 24 | 38 | ||
| 25 | /// Registers all BCAT services with the specified service manager. | 39 | /// Registers all BCAT services with the specified service manager. |
| 26 | void InstallInterfaces(SM::ServiceManager& service_manager); | 40 | void InstallInterfaces(Core::System& system); |
| 41 | |||
| 42 | } // namespace BCAT | ||
| 27 | 43 | ||
| 28 | } // namespace Service::BCAT | 44 | } // namespace Service |
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index 3c7ca2c44..afce581e5 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp | |||
| @@ -16,7 +16,7 @@ namespace Service::BtDrv { | |||
| 16 | 16 | ||
| 17 | class Bt final : public ServiceFramework<Bt> { | 17 | class Bt final : public ServiceFramework<Bt> { |
| 18 | public: | 18 | public: |
| 19 | explicit Bt() : ServiceFramework{"bt"} { | 19 | explicit Bt(Core::System& system) : ServiceFramework{"bt"} { |
| 20 | // clang-format off | 20 | // clang-format off |
| 21 | static const FunctionInfo functions[] = { | 21 | static const FunctionInfo functions[] = { |
| 22 | {0, nullptr, "LeClientReadCharacteristic"}, | 22 | {0, nullptr, "LeClientReadCharacteristic"}, |
| @@ -33,7 +33,7 @@ public: | |||
| 33 | // clang-format on | 33 | // clang-format on |
| 34 | RegisterHandlers(functions); | 34 | RegisterHandlers(functions); |
| 35 | 35 | ||
| 36 | auto& kernel = Core::System::GetInstance().Kernel(); | 36 | auto& kernel = system.Kernel(); |
| 37 | register_event = Kernel::WritableEvent::CreateEventPair( | 37 | register_event = Kernel::WritableEvent::CreateEventPair( |
| 38 | kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent"); | 38 | kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent"); |
| 39 | } | 39 | } |
| @@ -163,9 +163,9 @@ public: | |||
| 163 | } | 163 | } |
| 164 | }; | 164 | }; |
| 165 | 165 | ||
| 166 | void InstallInterfaces(SM::ServiceManager& sm) { | 166 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 167 | std::make_shared<BtDrv>()->InstallAsService(sm); | 167 | std::make_shared<BtDrv>()->InstallAsService(sm); |
| 168 | std::make_shared<Bt>()->InstallAsService(sm); | 168 | std::make_shared<Bt>(system)->InstallAsService(sm); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | } // namespace Service::BtDrv | 171 | } // namespace Service::BtDrv |
diff --git a/src/core/hle/service/btdrv/btdrv.h b/src/core/hle/service/btdrv/btdrv.h index 164e56f43..191410dbc 100644 --- a/src/core/hle/service/btdrv/btdrv.h +++ b/src/core/hle/service/btdrv/btdrv.h | |||
| @@ -8,9 +8,13 @@ namespace Service::SM { | |||
| 8 | class ServiceManager; | 8 | class ServiceManager; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 11 | namespace Service::BtDrv { | 15 | namespace Service::BtDrv { |
| 12 | 16 | ||
| 13 | /// Registers all BtDrv services with the specified service manager. | 17 | /// Registers all BtDrv services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& sm); | 18 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 15 | 19 | ||
| 16 | } // namespace Service::BtDrv | 20 | } // namespace Service::BtDrv |
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index b439ee7ec..920fc6ff7 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp | |||
| @@ -17,7 +17,7 @@ namespace Service::BTM { | |||
| 17 | 17 | ||
| 18 | class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { | 18 | class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { |
| 19 | public: | 19 | public: |
| 20 | explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} { | 20 | explicit IBtmUserCore(Core::System& system) : ServiceFramework{"IBtmUserCore"} { |
| 21 | // clang-format off | 21 | // clang-format off |
| 22 | static const FunctionInfo functions[] = { | 22 | static const FunctionInfo functions[] = { |
| 23 | {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, | 23 | {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, |
| @@ -56,7 +56,7 @@ public: | |||
| 56 | // clang-format on | 56 | // clang-format on |
| 57 | RegisterHandlers(functions); | 57 | RegisterHandlers(functions); |
| 58 | 58 | ||
| 59 | auto& kernel = Core::System::GetInstance().Kernel(); | 59 | auto& kernel = system.Kernel(); |
| 60 | scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, | 60 | scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, |
| 61 | "IBtmUserCore:ScanEvent"); | 61 | "IBtmUserCore:ScanEvent"); |
| 62 | connection_event = Kernel::WritableEvent::CreateEventPair( | 62 | connection_event = Kernel::WritableEvent::CreateEventPair( |
| @@ -108,7 +108,7 @@ private: | |||
| 108 | 108 | ||
| 109 | class BTM_USR final : public ServiceFramework<BTM_USR> { | 109 | class BTM_USR final : public ServiceFramework<BTM_USR> { |
| 110 | public: | 110 | public: |
| 111 | explicit BTM_USR() : ServiceFramework{"btm:u"} { | 111 | explicit BTM_USR(Core::System& system) : ServiceFramework{"btm:u"}, system(system) { |
| 112 | // clang-format off | 112 | // clang-format off |
| 113 | static const FunctionInfo functions[] = { | 113 | static const FunctionInfo functions[] = { |
| 114 | {0, &BTM_USR::GetCore, "GetCore"}, | 114 | {0, &BTM_USR::GetCore, "GetCore"}, |
| @@ -123,8 +123,10 @@ private: | |||
| 123 | 123 | ||
| 124 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 124 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 125 | rb.Push(RESULT_SUCCESS); | 125 | rb.Push(RESULT_SUCCESS); |
| 126 | rb.PushIpcInterface<IBtmUserCore>(); | 126 | rb.PushIpcInterface<IBtmUserCore>(system); |
| 127 | } | 127 | } |
| 128 | |||
| 129 | Core::System& system; | ||
| 128 | }; | 130 | }; |
| 129 | 131 | ||
| 130 | class BTM final : public ServiceFramework<BTM> { | 132 | class BTM final : public ServiceFramework<BTM> { |
| @@ -268,11 +270,11 @@ private: | |||
| 268 | } | 270 | } |
| 269 | }; | 271 | }; |
| 270 | 272 | ||
| 271 | void InstallInterfaces(SM::ServiceManager& sm) { | 273 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 272 | std::make_shared<BTM>()->InstallAsService(sm); | 274 | std::make_shared<BTM>()->InstallAsService(sm); |
| 273 | std::make_shared<BTM_DBG>()->InstallAsService(sm); | 275 | std::make_shared<BTM_DBG>()->InstallAsService(sm); |
| 274 | std::make_shared<BTM_SYS>()->InstallAsService(sm); | 276 | std::make_shared<BTM_SYS>()->InstallAsService(sm); |
| 275 | std::make_shared<BTM_USR>()->InstallAsService(sm); | 277 | std::make_shared<BTM_USR>(system)->InstallAsService(sm); |
| 276 | } | 278 | } |
| 277 | 279 | ||
| 278 | } // namespace Service::BTM | 280 | } // namespace Service::BTM |
diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h index e6425a7e3..c6b878043 100644 --- a/src/core/hle/service/btm/btm.h +++ b/src/core/hle/service/btm/btm.h | |||
| @@ -8,8 +8,12 @@ namespace Service::SM { | |||
| 8 | class ServiceManager; | 8 | class ServiceManager; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | }; | ||
| 14 | |||
| 11 | namespace Service::BTM { | 15 | namespace Service::BTM { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::BTM | 19 | } // namespace Service::BTM |
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 01fa06ad3..b2ebf6240 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp | |||
| @@ -20,8 +20,8 @@ | |||
| 20 | 20 | ||
| 21 | namespace Service::Fatal { | 21 | namespace Service::Fatal { |
| 22 | 22 | ||
| 23 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 23 | Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) |
| 24 | : ServiceFramework(name), module(std::move(module)) {} | 24 | : ServiceFramework(name), module(std::move(module)), system(system) {} |
| 25 | 25 | ||
| 26 | Module::Interface::~Interface() = default; | 26 | Module::Interface::~Interface() = default; |
| 27 | 27 | ||
| @@ -64,7 +64,8 @@ enum class FatalType : u32 { | |||
| 64 | ErrorScreen = 2, | 64 | ErrorScreen = 2, |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { | 67 | static void GenerateErrorReport(Core::System& system, ResultCode error_code, |
| 68 | const FatalInfo& info) { | ||
| 68 | const auto title_id = Core::CurrentProcess()->GetTitleID(); | 69 | const auto title_id = Core::CurrentProcess()->GetTitleID(); |
| 69 | std::string crash_report = fmt::format( | 70 | std::string crash_report = fmt::format( |
| 70 | "Yuzu {}-{} crash report\n" | 71 | "Yuzu {}-{} crash report\n" |
| @@ -101,18 +102,19 @@ static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { | |||
| 101 | 102 | ||
| 102 | LOG_ERROR(Service_Fatal, "{}", crash_report); | 103 | LOG_ERROR(Service_Fatal, "{}", crash_report); |
| 103 | 104 | ||
| 104 | Core::System::GetInstance().GetReporter().SaveCrashReport( | 105 | system.GetReporter().SaveCrashReport( |
| 105 | title_id, error_code, info.set_flags, info.program_entry_point, info.sp, info.pc, | 106 | title_id, error_code, info.set_flags, info.program_entry_point, info.sp, info.pc, |
| 106 | info.pstate, info.afsr0, info.afsr1, info.esr, info.far, info.registers, info.backtrace, | 107 | info.pstate, info.afsr0, info.afsr1, info.esr, info.far, info.registers, info.backtrace, |
| 107 | info.backtrace_size, info.ArchAsString(), info.unk10); | 108 | info.backtrace_size, info.ArchAsString(), info.unk10); |
| 108 | } | 109 | } |
| 109 | 110 | ||
| 110 | static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) { | 111 | static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type, |
| 112 | const FatalInfo& info) { | ||
| 111 | LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", | 113 | LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", |
| 112 | static_cast<u32>(fatal_type), error_code.raw); | 114 | static_cast<u32>(fatal_type), error_code.raw); |
| 113 | switch (fatal_type) { | 115 | switch (fatal_type) { |
| 114 | case FatalType::ErrorReportAndScreen: | 116 | case FatalType::ErrorReportAndScreen: |
| 115 | GenerateErrorReport(error_code, info); | 117 | GenerateErrorReport(system, error_code, info); |
| 116 | [[fallthrough]]; | 118 | [[fallthrough]]; |
| 117 | case FatalType::ErrorScreen: | 119 | case FatalType::ErrorScreen: |
| 118 | // Since we have no fatal:u error screen. We should just kill execution instead | 120 | // Since we have no fatal:u error screen. We should just kill execution instead |
| @@ -120,7 +122,7 @@ static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const F | |||
| 120 | break; | 122 | break; |
| 121 | // Should not throw a fatal screen but should generate an error report | 123 | // Should not throw a fatal screen but should generate an error report |
| 122 | case FatalType::ErrorReport: | 124 | case FatalType::ErrorReport: |
| 123 | GenerateErrorReport(error_code, info); | 125 | GenerateErrorReport(system, error_code, info); |
| 124 | break; | 126 | break; |
| 125 | } | 127 | } |
| 126 | } | 128 | } |
| @@ -130,7 +132,7 @@ void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) { | |||
| 130 | IPC::RequestParser rp{ctx}; | 132 | IPC::RequestParser rp{ctx}; |
| 131 | const auto error_code = rp.Pop<ResultCode>(); | 133 | const auto error_code = rp.Pop<ResultCode>(); |
| 132 | 134 | ||
| 133 | ThrowFatalError(error_code, FatalType::ErrorScreen, {}); | 135 | ThrowFatalError(system, error_code, FatalType::ErrorScreen, {}); |
| 134 | IPC::ResponseBuilder rb{ctx, 2}; | 136 | IPC::ResponseBuilder rb{ctx, 2}; |
| 135 | rb.Push(RESULT_SUCCESS); | 137 | rb.Push(RESULT_SUCCESS); |
| 136 | } | 138 | } |
| @@ -141,7 +143,8 @@ void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) { | |||
| 141 | const auto error_code = rp.Pop<ResultCode>(); | 143 | const auto error_code = rp.Pop<ResultCode>(); |
| 142 | const auto fatal_type = rp.PopEnum<FatalType>(); | 144 | const auto fatal_type = rp.PopEnum<FatalType>(); |
| 143 | 145 | ||
| 144 | ThrowFatalError(error_code, fatal_type, {}); // No info is passed with ThrowFatalWithPolicy | 146 | ThrowFatalError(system, error_code, fatal_type, |
| 147 | {}); // No info is passed with ThrowFatalWithPolicy | ||
| 145 | IPC::ResponseBuilder rb{ctx, 2}; | 148 | IPC::ResponseBuilder rb{ctx, 2}; |
| 146 | rb.Push(RESULT_SUCCESS); | 149 | rb.Push(RESULT_SUCCESS); |
| 147 | } | 150 | } |
| @@ -157,15 +160,15 @@ void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) | |||
| 157 | ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!"); | 160 | ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!"); |
| 158 | std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo)); | 161 | std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo)); |
| 159 | 162 | ||
| 160 | ThrowFatalError(error_code, fatal_type, info); | 163 | ThrowFatalError(system, error_code, fatal_type, info); |
| 161 | IPC::ResponseBuilder rb{ctx, 2}; | 164 | IPC::ResponseBuilder rb{ctx, 2}; |
| 162 | rb.Push(RESULT_SUCCESS); | 165 | rb.Push(RESULT_SUCCESS); |
| 163 | } | 166 | } |
| 164 | 167 | ||
| 165 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 168 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 166 | auto module = std::make_shared<Module>(); | 169 | auto module = std::make_shared<Module>(); |
| 167 | std::make_shared<Fatal_P>(module)->InstallAsService(service_manager); | 170 | std::make_shared<Fatal_P>(module, system)->InstallAsService(service_manager); |
| 168 | std::make_shared<Fatal_U>(module)->InstallAsService(service_manager); | 171 | std::make_shared<Fatal_U>(module, system)->InstallAsService(service_manager); |
| 169 | } | 172 | } |
| 170 | 173 | ||
| 171 | } // namespace Service::Fatal | 174 | } // namespace Service::Fatal |
diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h index 09371ff7f..bd9339dfc 100644 --- a/src/core/hle/service/fatal/fatal.h +++ b/src/core/hle/service/fatal/fatal.h | |||
| @@ -6,13 +6,17 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Fatal { | 13 | namespace Service::Fatal { |
| 10 | 14 | ||
| 11 | class Module final { | 15 | class Module final { |
| 12 | public: | 16 | public: |
| 13 | class Interface : public ServiceFramework<Interface> { | 17 | class Interface : public ServiceFramework<Interface> { |
| 14 | public: | 18 | public: |
| 15 | explicit Interface(std::shared_ptr<Module> module, const char* name); | 19 | explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); |
| 16 | ~Interface() override; | 20 | ~Interface() override; |
| 17 | 21 | ||
| 18 | void ThrowFatal(Kernel::HLERequestContext& ctx); | 22 | void ThrowFatal(Kernel::HLERequestContext& ctx); |
| @@ -21,9 +25,10 @@ public: | |||
| 21 | 25 | ||
| 22 | protected: | 26 | protected: |
| 23 | std::shared_ptr<Module> module; | 27 | std::shared_ptr<Module> module; |
| 28 | Core::System& system; | ||
| 24 | }; | 29 | }; |
| 25 | }; | 30 | }; |
| 26 | 31 | ||
| 27 | void InstallInterfaces(SM::ServiceManager& service_manager); | 32 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 28 | 33 | ||
| 29 | } // namespace Service::Fatal | 34 | } // namespace Service::Fatal |
diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp index 9e5f872ff..066ccf6b0 100644 --- a/src/core/hle/service/fatal/fatal_p.cpp +++ b/src/core/hle/service/fatal/fatal_p.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Fatal { | 7 | namespace Service::Fatal { |
| 8 | 8 | ||
| 9 | Fatal_P::Fatal_P(std::shared_ptr<Module> module) | 9 | Fatal_P::Fatal_P(std::shared_ptr<Module> module, Core::System& system) |
| 10 | : Module::Interface(std::move(module), "fatal:p") {} | 10 | : Module::Interface(std::move(module), system, "fatal:p") {} |
| 11 | 11 | ||
| 12 | Fatal_P::~Fatal_P() = default; | 12 | Fatal_P::~Fatal_P() = default; |
| 13 | 13 | ||
diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h index 6e9c5979f..c6d953cb5 100644 --- a/src/core/hle/service/fatal/fatal_p.h +++ b/src/core/hle/service/fatal/fatal_p.h | |||
| @@ -10,7 +10,7 @@ namespace Service::Fatal { | |||
| 10 | 10 | ||
| 11 | class Fatal_P final : public Module::Interface { | 11 | class Fatal_P final : public Module::Interface { |
| 12 | public: | 12 | public: |
| 13 | explicit Fatal_P(std::shared_ptr<Module> module); | 13 | explicit Fatal_P(std::shared_ptr<Module> module, Core::System& system); |
| 14 | ~Fatal_P() override; | 14 | ~Fatal_P() override; |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp index 1572a2051..8d72ed485 100644 --- a/src/core/hle/service/fatal/fatal_u.cpp +++ b/src/core/hle/service/fatal/fatal_u.cpp | |||
| @@ -6,7 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Fatal { | 7 | namespace Service::Fatal { |
| 8 | 8 | ||
| 9 | Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") { | 9 | Fatal_U::Fatal_U(std::shared_ptr<Module> module, Core::System& system) |
| 10 | : Module::Interface(std::move(module), system, "fatal:u") { | ||
| 10 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 11 | {0, &Fatal_U::ThrowFatal, "ThrowFatal"}, | 12 | {0, &Fatal_U::ThrowFatal, "ThrowFatal"}, |
| 12 | {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"}, | 13 | {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"}, |
diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h index 72cb6d076..34c5c7f95 100644 --- a/src/core/hle/service/fatal/fatal_u.h +++ b/src/core/hle/service/fatal/fatal_u.h | |||
| @@ -10,7 +10,7 @@ namespace Service::Fatal { | |||
| 10 | 10 | ||
| 11 | class Fatal_U final : public Module::Interface { | 11 | class Fatal_U final : public Module::Interface { |
| 12 | public: | 12 | public: |
| 13 | explicit Fatal_U(std::shared_ptr<Module> module); | 13 | explicit Fatal_U(std::shared_ptr<Module> module, Core::System& system); |
| 14 | ~Fatal_U() override; | 14 | ~Fatal_U() override; |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 14cd0e322..7fa4e820b 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -674,6 +674,15 @@ FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) | |||
| 674 | return bis_factory->GetModificationDumpRoot(title_id); | 674 | return bis_factory->GetModificationDumpRoot(title_id); |
| 675 | } | 675 | } |
| 676 | 676 | ||
| 677 | FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const { | ||
| 678 | LOG_TRACE(Service_FS, "Opening BCAT root for tid={:016X}", title_id); | ||
| 679 | |||
| 680 | if (bis_factory == nullptr) | ||
| 681 | return nullptr; | ||
| 682 | |||
| 683 | return bis_factory->GetBCATDirectory(title_id); | ||
| 684 | } | ||
| 685 | |||
| 677 | void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { | 686 | void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { |
| 678 | if (overwrite) { | 687 | if (overwrite) { |
| 679 | bis_factory = nullptr; | 688 | bis_factory = nullptr; |
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 3e0c03ec0..e6b49d8a2 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -110,6 +110,8 @@ public: | |||
| 110 | FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const; | 110 | FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const; |
| 111 | FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const; | 111 | FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const; |
| 112 | 112 | ||
| 113 | FileSys::VirtualDir GetBCATDirectory(u64 title_id) const; | ||
| 114 | |||
| 113 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function | 115 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function |
| 114 | // above is called. | 116 | // above is called. |
| 115 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); | 117 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index d1ec12ef9..42b4ee861 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -149,7 +149,8 @@ private: | |||
| 149 | 149 | ||
| 150 | class INotificationService final : public ServiceFramework<INotificationService> { | 150 | class INotificationService final : public ServiceFramework<INotificationService> { |
| 151 | public: | 151 | public: |
| 152 | INotificationService(Common::UUID uuid) : ServiceFramework("INotificationService"), uuid(uuid) { | 152 | INotificationService(Common::UUID uuid, Core::System& system) |
| 153 | : ServiceFramework("INotificationService"), uuid(uuid) { | ||
| 153 | // clang-format off | 154 | // clang-format off |
| 154 | static const FunctionInfo functions[] = { | 155 | static const FunctionInfo functions[] = { |
| 155 | {0, &INotificationService::GetEvent, "GetEvent"}, | 156 | {0, &INotificationService::GetEvent, "GetEvent"}, |
| @@ -159,6 +160,9 @@ public: | |||
| 159 | // clang-format on | 160 | // clang-format on |
| 160 | 161 | ||
| 161 | RegisterHandlers(functions); | 162 | RegisterHandlers(functions); |
| 163 | |||
| 164 | notification_event = Kernel::WritableEvent::CreateEventPair( | ||
| 165 | system.Kernel(), Kernel::ResetType::Manual, "INotificationService:NotifyEvent"); | ||
| 162 | } | 166 | } |
| 163 | 167 | ||
| 164 | private: | 168 | private: |
| @@ -167,13 +171,6 @@ private: | |||
| 167 | 171 | ||
| 168 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 172 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 169 | rb.Push(RESULT_SUCCESS); | 173 | rb.Push(RESULT_SUCCESS); |
| 170 | |||
| 171 | if (!is_event_created) { | ||
| 172 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 173 | notification_event = Kernel::WritableEvent::CreateEventPair( | ||
| 174 | kernel, Kernel::ResetType::Manual, "INotificationService:NotifyEvent"); | ||
| 175 | is_event_created = true; | ||
| 176 | } | ||
| 177 | rb.PushCopyObjects(notification_event.readable); | 174 | rb.PushCopyObjects(notification_event.readable); |
| 178 | } | 175 | } |
| 179 | 176 | ||
| @@ -261,21 +258,21 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx | |||
| 261 | 258 | ||
| 262 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 259 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 263 | rb.Push(RESULT_SUCCESS); | 260 | rb.Push(RESULT_SUCCESS); |
| 264 | rb.PushIpcInterface<INotificationService>(uuid); | 261 | rb.PushIpcInterface<INotificationService>(uuid, system); |
| 265 | } | 262 | } |
| 266 | 263 | ||
| 267 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 264 | Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) |
| 268 | : ServiceFramework(name), module(std::move(module)) {} | 265 | : ServiceFramework(name), module(std::move(module)), system(system) {} |
| 269 | 266 | ||
| 270 | Module::Interface::~Interface() = default; | 267 | Module::Interface::~Interface() = default; |
| 271 | 268 | ||
| 272 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 269 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 273 | auto module = std::make_shared<Module>(); | 270 | auto module = std::make_shared<Module>(); |
| 274 | std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager); | 271 | std::make_shared<Friend>(module, system, "friend:a")->InstallAsService(service_manager); |
| 275 | std::make_shared<Friend>(module, "friend:m")->InstallAsService(service_manager); | 272 | std::make_shared<Friend>(module, system, "friend:m")->InstallAsService(service_manager); |
| 276 | std::make_shared<Friend>(module, "friend:s")->InstallAsService(service_manager); | 273 | std::make_shared<Friend>(module, system, "friend:s")->InstallAsService(service_manager); |
| 277 | std::make_shared<Friend>(module, "friend:u")->InstallAsService(service_manager); | 274 | std::make_shared<Friend>(module, system, "friend:u")->InstallAsService(service_manager); |
| 278 | std::make_shared<Friend>(module, "friend:v")->InstallAsService(service_manager); | 275 | std::make_shared<Friend>(module, system, "friend:v")->InstallAsService(service_manager); |
| 279 | } | 276 | } |
| 280 | 277 | ||
| 281 | } // namespace Service::Friend | 278 | } // namespace Service::Friend |
diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h index 38d05fa8e..24f3fc969 100644 --- a/src/core/hle/service/friend/friend.h +++ b/src/core/hle/service/friend/friend.h | |||
| @@ -6,13 +6,17 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Friend { | 13 | namespace Service::Friend { |
| 10 | 14 | ||
| 11 | class Module final { | 15 | class Module final { |
| 12 | public: | 16 | public: |
| 13 | class Interface : public ServiceFramework<Interface> { | 17 | class Interface : public ServiceFramework<Interface> { |
| 14 | public: | 18 | public: |
| 15 | explicit Interface(std::shared_ptr<Module> module, const char* name); | 19 | explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); |
| 16 | ~Interface() override; | 20 | ~Interface() override; |
| 17 | 21 | ||
| 18 | void CreateFriendService(Kernel::HLERequestContext& ctx); | 22 | void CreateFriendService(Kernel::HLERequestContext& ctx); |
| @@ -20,10 +24,11 @@ public: | |||
| 20 | 24 | ||
| 21 | protected: | 25 | protected: |
| 22 | std::shared_ptr<Module> module; | 26 | std::shared_ptr<Module> module; |
| 27 | Core::System& system; | ||
| 23 | }; | 28 | }; |
| 24 | }; | 29 | }; |
| 25 | 30 | ||
| 26 | /// Registers all Friend services with the specified service manager. | 31 | /// Registers all Friend services with the specified service manager. |
| 27 | void InstallInterfaces(SM::ServiceManager& service_manager); | 32 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 28 | 33 | ||
| 29 | } // namespace Service::Friend | 34 | } // namespace Service::Friend |
diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp index 5b384f733..58155f652 100644 --- a/src/core/hle/service/friend/interface.cpp +++ b/src/core/hle/service/friend/interface.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Friend { | 7 | namespace Service::Friend { |
| 8 | 8 | ||
| 9 | Friend::Friend(std::shared_ptr<Module> module, const char* name) | 9 | Friend::Friend(std::shared_ptr<Module> module, Core::System& system, const char* name) |
| 10 | : Interface(std::move(module), name) { | 10 | : Interface(std::move(module), system, name) { |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, &Friend::CreateFriendService, "CreateFriendService"}, | 12 | {0, &Friend::CreateFriendService, "CreateFriendService"}, |
| 13 | {1, &Friend::CreateNotificationService, "CreateNotificationService"}, | 13 | {1, &Friend::CreateNotificationService, "CreateNotificationService"}, |
diff --git a/src/core/hle/service/friend/interface.h b/src/core/hle/service/friend/interface.h index 1963def39..465a35770 100644 --- a/src/core/hle/service/friend/interface.h +++ b/src/core/hle/service/friend/interface.h | |||
| @@ -10,7 +10,7 @@ namespace Service::Friend { | |||
| 10 | 10 | ||
| 11 | class Friend final : public Module::Interface { | 11 | class Friend final : public Module::Interface { |
| 12 | public: | 12 | public: |
| 13 | explicit Friend(std::shared_ptr<Module> module, const char* name); | 13 | explicit Friend(std::shared_ptr<Module> module, Core::System& system, const char* name); |
| 14 | ~Friend() override; | 14 | ~Friend() override; |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp index 0993a7815..8091db9d7 100644 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ b/src/core/hle/service/hid/controllers/controller_base.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::HID { | 7 | namespace Service::HID { |
| 8 | 8 | ||
| 9 | ControllerBase::ControllerBase() = default; | 9 | ControllerBase::ControllerBase(Core::System& system) : system(system) {} |
| 10 | ControllerBase::~ControllerBase() = default; | 10 | ControllerBase::~ControllerBase() = default; |
| 11 | 11 | ||
| 12 | void ControllerBase::ActivateController() { | 12 | void ControllerBase::ActivateController() { |
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 5e5097a03..8bc69c372 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h | |||
| @@ -11,10 +11,14 @@ namespace Core::Timing { | |||
| 11 | class CoreTiming; | 11 | class CoreTiming; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | namespace Core { | ||
| 15 | class System; | ||
| 16 | } | ||
| 17 | |||
| 14 | namespace Service::HID { | 18 | namespace Service::HID { |
| 15 | class ControllerBase { | 19 | class ControllerBase { |
| 16 | public: | 20 | public: |
| 17 | ControllerBase(); | 21 | explicit ControllerBase(Core::System& system); |
| 18 | virtual ~ControllerBase(); | 22 | virtual ~ControllerBase(); |
| 19 | 23 | ||
| 20 | // Called when the controller is initialized | 24 | // Called when the controller is initialized |
| @@ -46,5 +50,7 @@ protected: | |||
| 46 | s64_le entry_count; | 50 | s64_le entry_count; |
| 47 | }; | 51 | }; |
| 48 | static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); | 52 | static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); |
| 53 | |||
| 54 | Core::System& system; | ||
| 49 | }; | 55 | }; |
| 50 | } // namespace Service::HID | 56 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index c5c2e032a..8e8263f5b 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp | |||
| @@ -14,7 +14,8 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | |||
| 14 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | 14 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; |
| 15 | enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; | 15 | enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; |
| 16 | 16 | ||
| 17 | Controller_DebugPad::Controller_DebugPad() = default; | 17 | Controller_DebugPad::Controller_DebugPad(Core::System& system) |
| 18 | : ControllerBase(system), system(system) {} | ||
| 18 | Controller_DebugPad::~Controller_DebugPad() = default; | 19 | Controller_DebugPad::~Controller_DebugPad() = default; |
| 19 | 20 | ||
| 20 | void Controller_DebugPad::OnInit() {} | 21 | void Controller_DebugPad::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index e584b92ec..6c4de817e 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | namespace Service::HID { | 16 | namespace Service::HID { |
| 17 | class Controller_DebugPad final : public ControllerBase { | 17 | class Controller_DebugPad final : public ControllerBase { |
| 18 | public: | 18 | public: |
| 19 | Controller_DebugPad(); | 19 | explicit Controller_DebugPad(Core::System& system); |
| 20 | ~Controller_DebugPad() override; | 20 | ~Controller_DebugPad() override; |
| 21 | 21 | ||
| 22 | // Called when the controller is initialized | 22 | // Called when the controller is initialized |
| @@ -89,5 +89,6 @@ private: | |||
| 89 | buttons; | 89 | buttons; |
| 90 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> | 90 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> |
| 91 | analogs; | 91 | analogs; |
| 92 | Core::System& system; | ||
| 92 | }; | 93 | }; |
| 93 | } // namespace Service::HID | 94 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index a179252e3..80da0a0d3 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -10,7 +10,8 @@ | |||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; | 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; |
| 12 | 12 | ||
| 13 | Controller_Gesture::Controller_Gesture() = default; | 13 | Controller_Gesture::Controller_Gesture(Core::System& system) |
| 14 | : ControllerBase(system), system(system) {} | ||
| 14 | Controller_Gesture::~Controller_Gesture() = default; | 15 | Controller_Gesture::~Controller_Gesture() = default; |
| 15 | 16 | ||
| 16 | void Controller_Gesture::OnInit() {} | 17 | void Controller_Gesture::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index f305fe90f..396897527 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | namespace Service::HID { | 12 | namespace Service::HID { |
| 13 | class Controller_Gesture final : public ControllerBase { | 13 | class Controller_Gesture final : public ControllerBase { |
| 14 | public: | 14 | public: |
| 15 | Controller_Gesture(); | 15 | explicit Controller_Gesture(Core::System& system); |
| 16 | ~Controller_Gesture() override; | 16 | ~Controller_Gesture() override; |
| 17 | 17 | ||
| 18 | // Called when the controller is initialized | 18 | // Called when the controller is initialized |
| @@ -59,5 +59,6 @@ private: | |||
| 59 | std::array<GestureState, 17> gesture_states; | 59 | std::array<GestureState, 17> gesture_states; |
| 60 | }; | 60 | }; |
| 61 | SharedMemory shared_memory{}; | 61 | SharedMemory shared_memory{}; |
| 62 | Core::System& system; | ||
| 62 | }; | 63 | }; |
| 63 | } // namespace Service::HID | 64 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 92d7bfb52..e587b2e15 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp | |||
| @@ -12,7 +12,8 @@ namespace Service::HID { | |||
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; | 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; |
| 13 | constexpr u8 KEYS_PER_BYTE = 8; | 13 | constexpr u8 KEYS_PER_BYTE = 8; |
| 14 | 14 | ||
| 15 | Controller_Keyboard::Controller_Keyboard() = default; | 15 | Controller_Keyboard::Controller_Keyboard(Core::System& system) |
| 16 | : ControllerBase(system), system(system) {} | ||
| 16 | Controller_Keyboard::~Controller_Keyboard() = default; | 17 | Controller_Keyboard::~Controller_Keyboard() = default; |
| 17 | 18 | ||
| 18 | void Controller_Keyboard::OnInit() {} | 19 | void Controller_Keyboard::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 73cd2c7bb..ef586f7eb 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | namespace Service::HID { | 15 | namespace Service::HID { |
| 16 | class Controller_Keyboard final : public ControllerBase { | 16 | class Controller_Keyboard final : public ControllerBase { |
| 17 | public: | 17 | public: |
| 18 | Controller_Keyboard(); | 18 | explicit Controller_Keyboard(Core::System& system); |
| 19 | ~Controller_Keyboard() override; | 19 | ~Controller_Keyboard() override; |
| 20 | 20 | ||
| 21 | // Called when the controller is initialized | 21 | // Called when the controller is initialized |
| @@ -53,5 +53,6 @@ private: | |||
| 53 | keyboard_keys; | 53 | keyboard_keys; |
| 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods> | 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods> |
| 55 | keyboard_mods; | 55 | keyboard_mods; |
| 56 | Core::System& system; | ||
| 56 | }; | 57 | }; |
| 57 | } // namespace Service::HID | 58 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 11ab096d9..88f2ca4c1 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | namespace Service::HID { | 11 | namespace Service::HID { |
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; | 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; |
| 13 | 13 | ||
| 14 | Controller_Mouse::Controller_Mouse() = default; | 14 | Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system), system(system) {} |
| 15 | Controller_Mouse::~Controller_Mouse() = default; | 15 | Controller_Mouse::~Controller_Mouse() = default; |
| 16 | 16 | ||
| 17 | void Controller_Mouse::OnInit() {} | 17 | void Controller_Mouse::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 9d46eecbe..df2da6ae3 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | namespace Service::HID { | 14 | namespace Service::HID { |
| 15 | class Controller_Mouse final : public ControllerBase { | 15 | class Controller_Mouse final : public ControllerBase { |
| 16 | public: | 16 | public: |
| 17 | Controller_Mouse(); | 17 | explicit Controller_Mouse(Core::System& system); |
| 18 | ~Controller_Mouse() override; | 18 | ~Controller_Mouse() override; |
| 19 | 19 | ||
| 20 | // Called when the controller is initialized | 20 | // Called when the controller is initialized |
| @@ -53,5 +53,6 @@ private: | |||
| 53 | std::unique_ptr<Input::MouseDevice> mouse_device; | 53 | std::unique_ptr<Input::MouseDevice> mouse_device; |
| 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons> | 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons> |
| 55 | mouse_button_devices; | 55 | mouse_button_devices; |
| 56 | Core::System& system; | ||
| 56 | }; | 57 | }; |
| 57 | } // namespace Service::HID | 58 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index e47fe8188..a9cd119c4 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -93,7 +93,7 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) { | |||
| 93 | }; | 93 | }; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | Controller_NPad::Controller_NPad() = default; | 96 | Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} |
| 97 | Controller_NPad::~Controller_NPad() = default; | 97 | Controller_NPad::~Controller_NPad() = default; |
| 98 | 98 | ||
| 99 | void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | 99 | void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { |
| @@ -165,12 +165,15 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | |||
| 165 | controller.battery_level[0] = BATTERY_FULL; | 165 | controller.battery_level[0] = BATTERY_FULL; |
| 166 | controller.battery_level[1] = BATTERY_FULL; | 166 | controller.battery_level[1] = BATTERY_FULL; |
| 167 | controller.battery_level[2] = BATTERY_FULL; | 167 | controller.battery_level[2] = BATTERY_FULL; |
| 168 | styleset_changed_events[controller_idx].writable->Signal(); | ||
| 168 | } | 169 | } |
| 169 | 170 | ||
| 170 | void Controller_NPad::OnInit() { | 171 | void Controller_NPad::OnInit() { |
| 171 | auto& kernel = Core::System::GetInstance().Kernel(); | 172 | auto& kernel = system.Kernel(); |
| 172 | styleset_changed_event = Kernel::WritableEvent::CreateEventPair( | 173 | for (std::size_t i = 0; i < styleset_changed_events.size(); i++) { |
| 173 | kernel, Kernel::ResetType::Automatic, "npad:NpadStyleSetChanged"); | 174 | styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( |
| 175 | kernel, Kernel::ResetType::Manual, fmt::format("npad:NpadStyleSetChanged_{}", i)); | ||
| 176 | } | ||
| 174 | 177 | ||
| 175 | if (!IsControllerActivated()) { | 178 | if (!IsControllerActivated()) { |
| 176 | return; | 179 | return; |
| @@ -431,7 +434,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { | |||
| 431 | supported_npad_id_types.clear(); | 434 | supported_npad_id_types.clear(); |
| 432 | supported_npad_id_types.resize(length / sizeof(u32)); | 435 | supported_npad_id_types.resize(length / sizeof(u32)); |
| 433 | std::memcpy(supported_npad_id_types.data(), data, length); | 436 | std::memcpy(supported_npad_id_types.data(), data, length); |
| 434 | bool had_controller_update = false; | ||
| 435 | for (std::size_t i = 0; i < connected_controllers.size(); i++) { | 437 | for (std::size_t i = 0; i < connected_controllers.size(); i++) { |
| 436 | auto& controller = connected_controllers[i]; | 438 | auto& controller = connected_controllers[i]; |
| 437 | if (!controller.is_connected) { | 439 | if (!controller.is_connected) { |
| @@ -450,10 +452,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { | |||
| 450 | controller.type = requested_controller; | 452 | controller.type = requested_controller; |
| 451 | InitNewlyAddedControler(i); | 453 | InitNewlyAddedControler(i); |
| 452 | } | 454 | } |
| 453 | had_controller_update = true; | ||
| 454 | } | ||
| 455 | if (had_controller_update) { | ||
| 456 | styleset_changed_event.writable->Signal(); | ||
| 457 | } | 455 | } |
| 458 | } | 456 | } |
| 459 | } | 457 | } |
| @@ -468,7 +466,6 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { | |||
| 468 | } | 466 | } |
| 469 | 467 | ||
| 470 | void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { | 468 | void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { |
| 471 | styleset_changed_event.writable->Signal(); | ||
| 472 | hold_type = joy_hold_type; | 469 | hold_type = joy_hold_type; |
| 473 | } | 470 | } |
| 474 | 471 | ||
| @@ -479,7 +476,9 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { | |||
| 479 | void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { | 476 | void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { |
| 480 | const std::size_t npad_index = NPadIdToIndex(npad_id); | 477 | const std::size_t npad_index = NPadIdToIndex(npad_id); |
| 481 | ASSERT(npad_index < shared_memory_entries.size()); | 478 | ASSERT(npad_index < shared_memory_entries.size()); |
| 482 | shared_memory_entries[npad_index].pad_assignment = assignment_mode; | 479 | if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { |
| 480 | shared_memory_entries[npad_index].pad_assignment = assignment_mode; | ||
| 481 | } | ||
| 483 | } | 482 | } |
| 484 | 483 | ||
| 485 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | 484 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, |
| @@ -498,11 +497,12 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | |||
| 498 | last_processed_vibration = vibrations.back(); | 497 | last_processed_vibration = vibrations.back(); |
| 499 | } | 498 | } |
| 500 | 499 | ||
| 501 | Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const { | 500 | Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent( |
| 501 | u32 npad_id) const { | ||
| 502 | // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should | 502 | // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should |
| 503 | // be signalled at least once, and signaled after a new controller is connected? | 503 | // be signalled at least once, and signaled after a new controller is connected? |
| 504 | styleset_changed_event.writable->Signal(); | 504 | const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; |
| 505 | return styleset_changed_event.readable; | 505 | return styleset_event.readable; |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { | 508 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index f28b36806..1bc3d55d6 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -20,7 +20,7 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? | |||
| 20 | 20 | ||
| 21 | class Controller_NPad final : public ControllerBase { | 21 | class Controller_NPad final : public ControllerBase { |
| 22 | public: | 22 | public: |
| 23 | Controller_NPad(); | 23 | explicit Controller_NPad(Core::System& system); |
| 24 | ~Controller_NPad() override; | 24 | ~Controller_NPad() override; |
| 25 | 25 | ||
| 26 | // Called when the controller is initialized | 26 | // Called when the controller is initialized |
| @@ -109,7 +109,7 @@ public: | |||
| 109 | void VibrateController(const std::vector<u32>& controller_ids, | 109 | void VibrateController(const std::vector<u32>& controller_ids, |
| 110 | const std::vector<Vibration>& vibrations); | 110 | const std::vector<Vibration>& vibrations); |
| 111 | 111 | ||
| 112 | Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const; | 112 | Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; |
| 113 | Vibration GetLastVibration() const; | 113 | Vibration GetLastVibration() const; |
| 114 | 114 | ||
| 115 | void AddNewController(NPadControllerType controller); | 115 | void AddNewController(NPadControllerType controller); |
| @@ -315,7 +315,8 @@ private: | |||
| 315 | sticks; | 315 | sticks; |
| 316 | std::vector<u32> supported_npad_id_types{}; | 316 | std::vector<u32> supported_npad_id_types{}; |
| 317 | NpadHoldType hold_type{NpadHoldType::Vertical}; | 317 | NpadHoldType hold_type{NpadHoldType::Vertical}; |
| 318 | Kernel::EventPair styleset_changed_event; | 318 | // Each controller should have their own styleset changed event |
| 319 | std::array<Kernel::EventPair, 10> styleset_changed_events; | ||
| 319 | Vibration last_processed_vibration{}; | 320 | Vibration last_processed_vibration{}; |
| 320 | std::array<ControllerHolder, 10> connected_controllers{}; | 321 | std::array<ControllerHolder, 10> connected_controllers{}; |
| 321 | bool can_controllers_vibrate{true}; | 322 | bool can_controllers_vibrate{true}; |
| @@ -327,5 +328,6 @@ private: | |||
| 327 | std::array<ControllerPad, 10> npad_pad_states{}; | 328 | std::array<ControllerPad, 10> npad_pad_states{}; |
| 328 | bool IsControllerSupported(NPadControllerType controller); | 329 | bool IsControllerSupported(NPadControllerType controller); |
| 329 | bool is_in_lr_assignment_mode{false}; | 330 | bool is_in_lr_assignment_mode{false}; |
| 331 | Core::System& system; | ||
| 330 | }; | 332 | }; |
| 331 | } // namespace Service::HID | 333 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 946948f5e..9b829341e 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp | |||
| @@ -9,7 +9,8 @@ | |||
| 9 | 9 | ||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| 11 | 11 | ||
| 12 | Controller_Stubbed::Controller_Stubbed() = default; | 12 | Controller_Stubbed::Controller_Stubbed(Core::System& system) |
| 13 | : ControllerBase(system), system(system) {} | ||
| 13 | Controller_Stubbed::~Controller_Stubbed() = default; | 14 | Controller_Stubbed::~Controller_Stubbed() = default; |
| 14 | 15 | ||
| 15 | void Controller_Stubbed::OnInit() {} | 16 | void Controller_Stubbed::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 24469f03e..37d7d8538 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| 11 | class Controller_Stubbed final : public ControllerBase { | 11 | class Controller_Stubbed final : public ControllerBase { |
| 12 | public: | 12 | public: |
| 13 | Controller_Stubbed(); | 13 | explicit Controller_Stubbed(Core::System& system); |
| 14 | ~Controller_Stubbed() override; | 14 | ~Controller_Stubbed() override; |
| 15 | 15 | ||
| 16 | // Called when the controller is initialized | 16 | // Called when the controller is initialized |
| @@ -30,5 +30,6 @@ public: | |||
| 30 | private: | 30 | private: |
| 31 | bool smart_update{}; | 31 | bool smart_update{}; |
| 32 | std::size_t common_offset{}; | 32 | std::size_t common_offset{}; |
| 33 | Core::System& system; | ||
| 33 | }; | 34 | }; |
| 34 | } // namespace Service::HID | 35 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 1a8445a43..25912fd69 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -13,7 +13,8 @@ | |||
| 13 | namespace Service::HID { | 13 | namespace Service::HID { |
| 14 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; | 14 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; |
| 15 | 15 | ||
| 16 | Controller_Touchscreen::Controller_Touchscreen() = default; | 16 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system) |
| 17 | : ControllerBase(system), system(system) {} | ||
| 17 | Controller_Touchscreen::~Controller_Touchscreen() = default; | 18 | Controller_Touchscreen::~Controller_Touchscreen() = default; |
| 18 | 19 | ||
| 19 | void Controller_Touchscreen::OnInit() {} | 20 | void Controller_Touchscreen::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 76fc340e9..3429c84db 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | namespace Service::HID { | 14 | namespace Service::HID { |
| 15 | class Controller_Touchscreen final : public ControllerBase { | 15 | class Controller_Touchscreen final : public ControllerBase { |
| 16 | public: | 16 | public: |
| 17 | Controller_Touchscreen(); | 17 | explicit Controller_Touchscreen(Core::System& system); |
| 18 | ~Controller_Touchscreen() override; | 18 | ~Controller_Touchscreen() override; |
| 19 | 19 | ||
| 20 | // Called when the controller is initialized | 20 | // Called when the controller is initialized |
| @@ -69,5 +69,6 @@ private: | |||
| 69 | TouchScreenSharedMemory shared_memory{}; | 69 | TouchScreenSharedMemory shared_memory{}; |
| 70 | std::unique_ptr<Input::TouchDevice> touch_device; | 70 | std::unique_ptr<Input::TouchDevice> touch_device; |
| 71 | s64_le last_touch{}; | 71 | s64_le last_touch{}; |
| 72 | Core::System& system; | ||
| 72 | }; | 73 | }; |
| 73 | } // namespace Service::HID | 74 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index 1a9da9576..1bce044b4 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; | 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; |
| 12 | 12 | ||
| 13 | Controller_XPad::Controller_XPad() = default; | 13 | Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system), system(system) {} |
| 14 | Controller_XPad::~Controller_XPad() = default; | 14 | Controller_XPad::~Controller_XPad() = default; |
| 15 | 15 | ||
| 16 | void Controller_XPad::OnInit() {} | 16 | void Controller_XPad::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index 2864e6617..c445ebec0 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | namespace Service::HID { | 12 | namespace Service::HID { |
| 13 | class Controller_XPad final : public ControllerBase { | 13 | class Controller_XPad final : public ControllerBase { |
| 14 | public: | 14 | public: |
| 15 | Controller_XPad(); | 15 | explicit Controller_XPad(Core::System& system); |
| 16 | ~Controller_XPad() override; | 16 | ~Controller_XPad() override; |
| 17 | 17 | ||
| 18 | // Called when the controller is initialized | 18 | // Called when the controller is initialized |
| @@ -56,5 +56,6 @@ private: | |||
| 56 | }; | 56 | }; |
| 57 | static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); | 57 | static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); |
| 58 | SharedMemory shared_memory{}; | 58 | SharedMemory shared_memory{}; |
| 59 | Core::System& system; | ||
| 59 | }; | 60 | }; |
| 60 | } // namespace Service::HID | 61 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index f8b1ca816..8d76ba746 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -42,13 +42,14 @@ constexpr s64 accelerometer_update_ticks = static_cast<s64>(Core::Timing::BASE_C | |||
| 42 | constexpr s64 gyroscope_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); | 42 | constexpr s64 gyroscope_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); |
| 43 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; | 43 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; |
| 44 | 44 | ||
| 45 | IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { | 45 | IAppletResource::IAppletResource(Core::System& system) |
| 46 | : ServiceFramework("IAppletResource"), system(system) { | ||
| 46 | static const FunctionInfo functions[] = { | 47 | static const FunctionInfo functions[] = { |
| 47 | {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, | 48 | {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, |
| 48 | }; | 49 | }; |
| 49 | RegisterHandlers(functions); | 50 | RegisterHandlers(functions); |
| 50 | 51 | ||
| 51 | auto& kernel = Core::System::GetInstance().Kernel(); | 52 | auto& kernel = system.Kernel(); |
| 52 | shared_mem = Kernel::SharedMemory::Create( | 53 | shared_mem = Kernel::SharedMemory::Create( |
| 53 | kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, | 54 | kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, |
| 54 | Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); | 55 | Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); |
| @@ -74,7 +75,7 @@ IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { | |||
| 74 | GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); | 75 | GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); |
| 75 | 76 | ||
| 76 | // Register update callbacks | 77 | // Register update callbacks |
| 77 | auto& core_timing = Core::System::GetInstance().CoreTiming(); | 78 | auto& core_timing = system.CoreTiming(); |
| 78 | pad_update_event = | 79 | pad_update_event = |
| 79 | core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { | 80 | core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { |
| 80 | UpdateControllers(userdata, cycles_late); | 81 | UpdateControllers(userdata, cycles_late); |
| @@ -96,7 +97,7 @@ void IAppletResource::DeactivateController(HidController controller) { | |||
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | IAppletResource ::~IAppletResource() { | 99 | IAppletResource ::~IAppletResource() { |
| 99 | Core::System::GetInstance().CoreTiming().UnscheduleEvent(pad_update_event, 0); | 100 | system.CoreTiming().UnscheduleEvent(pad_update_event, 0); |
| 100 | } | 101 | } |
| 101 | 102 | ||
| 102 | void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 103 | void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| @@ -108,7 +109,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | |||
| 108 | } | 109 | } |
| 109 | 110 | ||
| 110 | void IAppletResource::UpdateControllers(u64 userdata, s64 cycles_late) { | 111 | void IAppletResource::UpdateControllers(u64 userdata, s64 cycles_late) { |
| 111 | auto& core_timing = Core::System::GetInstance().CoreTiming(); | 112 | auto& core_timing = system.CoreTiming(); |
| 112 | 113 | ||
| 113 | const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); | 114 | const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); |
| 114 | for (const auto& controller : controllers) { | 115 | for (const auto& controller : controllers) { |
| @@ -141,13 +142,13 @@ private: | |||
| 141 | 142 | ||
| 142 | std::shared_ptr<IAppletResource> Hid::GetAppletResource() { | 143 | std::shared_ptr<IAppletResource> Hid::GetAppletResource() { |
| 143 | if (applet_resource == nullptr) { | 144 | if (applet_resource == nullptr) { |
| 144 | applet_resource = std::make_shared<IAppletResource>(); | 145 | applet_resource = std::make_shared<IAppletResource>(system); |
| 145 | } | 146 | } |
| 146 | 147 | ||
| 147 | return applet_resource; | 148 | return applet_resource; |
| 148 | } | 149 | } |
| 149 | 150 | ||
| 150 | Hid::Hid() : ServiceFramework("hid") { | 151 | Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { |
| 151 | // clang-format off | 152 | // clang-format off |
| 152 | static const FunctionInfo functions[] = { | 153 | static const FunctionInfo functions[] = { |
| 153 | {0, &Hid::CreateAppletResource, "CreateAppletResource"}, | 154 | {0, &Hid::CreateAppletResource, "CreateAppletResource"}, |
| @@ -286,7 +287,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) { | |||
| 286 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 287 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 287 | 288 | ||
| 288 | if (applet_resource == nullptr) { | 289 | if (applet_resource == nullptr) { |
| 289 | applet_resource = std::make_shared<IAppletResource>(); | 290 | applet_resource = std::make_shared<IAppletResource>(system); |
| 290 | } | 291 | } |
| 291 | 292 | ||
| 292 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 293 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| @@ -479,7 +480,7 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | |||
| 479 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 480 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 480 | rb.Push(RESULT_SUCCESS); | 481 | rb.Push(RESULT_SUCCESS); |
| 481 | rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 482 | rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 482 | .GetStyleSetChangedEvent()); | 483 | .GetStyleSetChangedEvent(npad_id)); |
| 483 | } | 484 | } |
| 484 | 485 | ||
| 485 | void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { | 486 | void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { |
| @@ -1053,14 +1054,14 @@ void ReloadInputDevices() { | |||
| 1053 | Settings::values.is_device_reload_pending.store(true); | 1054 | Settings::values.is_device_reload_pending.store(true); |
| 1054 | } | 1055 | } |
| 1055 | 1056 | ||
| 1056 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 1057 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 1057 | std::make_shared<Hid>()->InstallAsService(service_manager); | 1058 | std::make_shared<Hid>(system)->InstallAsService(service_manager); |
| 1058 | std::make_shared<HidBus>()->InstallAsService(service_manager); | 1059 | std::make_shared<HidBus>()->InstallAsService(service_manager); |
| 1059 | std::make_shared<HidDbg>()->InstallAsService(service_manager); | 1060 | std::make_shared<HidDbg>()->InstallAsService(service_manager); |
| 1060 | std::make_shared<HidSys>()->InstallAsService(service_manager); | 1061 | std::make_shared<HidSys>()->InstallAsService(service_manager); |
| 1061 | std::make_shared<HidTmp>()->InstallAsService(service_manager); | 1062 | std::make_shared<HidTmp>()->InstallAsService(service_manager); |
| 1062 | 1063 | ||
| 1063 | std::make_shared<IRS>()->InstallAsService(service_manager); | 1064 | std::make_shared<IRS>(system)->InstallAsService(service_manager); |
| 1064 | std::make_shared<IRS_SYS>()->InstallAsService(service_manager); | 1065 | std::make_shared<IRS_SYS>()->InstallAsService(service_manager); |
| 1065 | 1066 | ||
| 1066 | std::make_shared<XCD_SYS>()->InstallAsService(service_manager); | 1067 | std::make_shared<XCD_SYS>()->InstallAsService(service_manager); |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 2fd6d9fc7..35b663679 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -42,7 +42,7 @@ enum class HidController : std::size_t { | |||
| 42 | 42 | ||
| 43 | class IAppletResource final : public ServiceFramework<IAppletResource> { | 43 | class IAppletResource final : public ServiceFramework<IAppletResource> { |
| 44 | public: | 44 | public: |
| 45 | IAppletResource(); | 45 | explicit IAppletResource(Core::System& system); |
| 46 | ~IAppletResource() override; | 46 | ~IAppletResource() override; |
| 47 | 47 | ||
| 48 | void ActivateController(HidController controller); | 48 | void ActivateController(HidController controller); |
| @@ -61,7 +61,7 @@ public: | |||
| 61 | private: | 61 | private: |
| 62 | template <typename T> | 62 | template <typename T> |
| 63 | void MakeController(HidController controller) { | 63 | void MakeController(HidController controller) { |
| 64 | controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); | 64 | controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); | 67 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); |
| @@ -70,6 +70,7 @@ private: | |||
| 70 | Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; | 70 | Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; |
| 71 | 71 | ||
| 72 | Core::Timing::EventType* pad_update_event; | 72 | Core::Timing::EventType* pad_update_event; |
| 73 | Core::System& system; | ||
| 73 | 74 | ||
| 74 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> | 75 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> |
| 75 | controllers{}; | 76 | controllers{}; |
| @@ -77,7 +78,7 @@ private: | |||
| 77 | 78 | ||
| 78 | class Hid final : public ServiceFramework<Hid> { | 79 | class Hid final : public ServiceFramework<Hid> { |
| 79 | public: | 80 | public: |
| 80 | Hid(); | 81 | explicit Hid(Core::System& system); |
| 81 | ~Hid() override; | 82 | ~Hid() override; |
| 82 | 83 | ||
| 83 | std::shared_ptr<IAppletResource> GetAppletResource(); | 84 | std::shared_ptr<IAppletResource> GetAppletResource(); |
| @@ -126,12 +127,13 @@ private: | |||
| 126 | void SwapNpadAssignment(Kernel::HLERequestContext& ctx); | 127 | void SwapNpadAssignment(Kernel::HLERequestContext& ctx); |
| 127 | 128 | ||
| 128 | std::shared_ptr<IAppletResource> applet_resource; | 129 | std::shared_ptr<IAppletResource> applet_resource; |
| 130 | Core::System& system; | ||
| 129 | }; | 131 | }; |
| 130 | 132 | ||
| 131 | /// Reload input devices. Used when input configuration changed | 133 | /// Reload input devices. Used when input configuration changed |
| 132 | void ReloadInputDevices(); | 134 | void ReloadInputDevices(); |
| 133 | 135 | ||
| 134 | /// Registers all HID services with the specified service manager. | 136 | /// Registers all HID services with the specified service manager. |
| 135 | void InstallInterfaces(SM::ServiceManager& service_manager); | 137 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 136 | 138 | ||
| 137 | } // namespace Service::HID | 139 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 2c4625c99..5e79e2c1a 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | namespace Service::HID { | 12 | namespace Service::HID { |
| 13 | 13 | ||
| 14 | IRS::IRS() : ServiceFramework{"irs"} { | 14 | IRS::IRS(Core::System& system) : ServiceFramework{"irs"}, system(system) { |
| 15 | // clang-format off | 15 | // clang-format off |
| 16 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 17 | {302, &IRS::ActivateIrsensor, "ActivateIrsensor"}, | 17 | {302, &IRS::ActivateIrsensor, "ActivateIrsensor"}, |
| @@ -37,7 +37,7 @@ IRS::IRS() : ServiceFramework{"irs"} { | |||
| 37 | 37 | ||
| 38 | RegisterHandlers(functions); | 38 | RegisterHandlers(functions); |
| 39 | 39 | ||
| 40 | auto& kernel = Core::System::GetInstance().Kernel(); | 40 | auto& kernel = system.Kernel(); |
| 41 | shared_mem = Kernel::SharedMemory::Create( | 41 | shared_mem = Kernel::SharedMemory::Create( |
| 42 | kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite, | 42 | kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite, |
| 43 | Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory"); | 43 | Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory"); |
| @@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | |||
| 98 | 98 | ||
| 99 | IPC::ResponseBuilder rb{ctx, 5}; | 99 | IPC::ResponseBuilder rb{ctx, 5}; |
| 100 | rb.Push(RESULT_SUCCESS); | 100 | rb.Push(RESULT_SUCCESS); |
| 101 | rb.PushRaw<u64>(Core::System::GetInstance().CoreTiming().GetTicks()); | 101 | rb.PushRaw<u64>(system.CoreTiming().GetTicks()); |
| 102 | rb.PushRaw<u32>(0); | 102 | rb.PushRaw<u32>(0); |
| 103 | } | 103 | } |
| 104 | 104 | ||
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index 12de6bfb3..eb4e898dd 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h | |||
| @@ -15,7 +15,7 @@ namespace Service::HID { | |||
| 15 | 15 | ||
| 16 | class IRS final : public ServiceFramework<IRS> { | 16 | class IRS final : public ServiceFramework<IRS> { |
| 17 | public: | 17 | public: |
| 18 | explicit IRS(); | 18 | explicit IRS(Core::System& system); |
| 19 | ~IRS() override; | 19 | ~IRS() override; |
| 20 | 20 | ||
| 21 | private: | 21 | private: |
| @@ -39,6 +39,7 @@ private: | |||
| 39 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); | 39 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); |
| 40 | Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; | 40 | Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; |
| 41 | const u32 device_handle{0xABCD}; | 41 | const u32 device_handle{0xABCD}; |
| 42 | Core::System& system; | ||
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { | 45 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { |
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 8ddad8682..3164ca26e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -78,7 +78,7 @@ public: | |||
| 78 | 78 | ||
| 79 | class RelocatableObject final : public ServiceFramework<RelocatableObject> { | 79 | class RelocatableObject final : public ServiceFramework<RelocatableObject> { |
| 80 | public: | 80 | public: |
| 81 | explicit RelocatableObject() : ServiceFramework{"ldr:ro"} { | 81 | explicit RelocatableObject(Core::System& system) : ServiceFramework{"ldr:ro"}, system(system) { |
| 82 | // clang-format off | 82 | // clang-format off |
| 83 | static const FunctionInfo functions[] = { | 83 | static const FunctionInfo functions[] = { |
| 84 | {0, &RelocatableObject::LoadNro, "LoadNro"}, | 84 | {0, &RelocatableObject::LoadNro, "LoadNro"}, |
| @@ -364,7 +364,7 @@ public: | |||
| 364 | vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size, | 364 | vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size, |
| 365 | Kernel::VMAPermission::ReadWrite); | 365 | Kernel::VMAPermission::ReadWrite); |
| 366 | 366 | ||
| 367 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); | 367 | system.InvalidateCpuInstructionCaches(); |
| 368 | 368 | ||
| 369 | nro.insert_or_assign(*map_address, | 369 | nro.insert_or_assign(*map_address, |
| 370 | NROInfo{hash, nro_address, nro_size, bss_address, bss_size}); | 370 | NROInfo{hash, nro_address, nro_size, bss_address, bss_size}); |
| @@ -430,7 +430,7 @@ public: | |||
| 430 | .IsSuccess()); | 430 | .IsSuccess()); |
| 431 | } | 431 | } |
| 432 | 432 | ||
| 433 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); | 433 | system.InvalidateCpuInstructionCaches(); |
| 434 | 434 | ||
| 435 | nro.erase(iter); | 435 | nro.erase(iter); |
| 436 | IPC::ResponseBuilder rb{ctx, 2}; | 436 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -516,13 +516,14 @@ private: | |||
| 516 | Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) && | 516 | Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) && |
| 517 | Common::Is4KBAligned(header.rw_size); | 517 | Common::Is4KBAligned(header.rw_size); |
| 518 | } | 518 | } |
| 519 | Core::System& system; | ||
| 519 | }; | 520 | }; |
| 520 | 521 | ||
| 521 | void InstallInterfaces(SM::ServiceManager& sm) { | 522 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 522 | std::make_shared<DebugMonitor>()->InstallAsService(sm); | 523 | std::make_shared<DebugMonitor>()->InstallAsService(sm); |
| 523 | std::make_shared<ProcessManager>()->InstallAsService(sm); | 524 | std::make_shared<ProcessManager>()->InstallAsService(sm); |
| 524 | std::make_shared<Shell>()->InstallAsService(sm); | 525 | std::make_shared<Shell>()->InstallAsService(sm); |
| 525 | std::make_shared<RelocatableObject>()->InstallAsService(sm); | 526 | std::make_shared<RelocatableObject>(system)->InstallAsService(sm); |
| 526 | } | 527 | } |
| 527 | 528 | ||
| 528 | } // namespace Service::LDR | 529 | } // namespace Service::LDR |
diff --git a/src/core/hle/service/ldr/ldr.h b/src/core/hle/service/ldr/ldr.h index 412410c4f..7ac8c0b65 100644 --- a/src/core/hle/service/ldr/ldr.h +++ b/src/core/hle/service/ldr/ldr.h | |||
| @@ -11,6 +11,6 @@ class ServiceManager; | |||
| 11 | namespace Service::LDR { | 11 | namespace Service::LDR { |
| 12 | 12 | ||
| 13 | /// Registers all LDR services with the specified service manager. | 13 | /// Registers all LDR services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& sm); | 14 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 15 | 15 | ||
| 16 | } // namespace Service::LDR | 16 | } // namespace Service::LDR |
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index a5cb06f8a..a42c22d44 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -23,9 +23,9 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, | |||
| 23 | constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); | 23 | constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); |
| 24 | } // namespace ErrCodes | 24 | } // namespace ErrCodes |
| 25 | 25 | ||
| 26 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 26 | Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) |
| 27 | : ServiceFramework(name), module(std::move(module)) { | 27 | : ServiceFramework(name), module(std::move(module)), system(system) { |
| 28 | auto& kernel = Core::System::GetInstance().Kernel(); | 28 | auto& kernel = system.Kernel(); |
| 29 | nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, | 29 | nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, |
| 30 | "IUser:NFCTagDetected"); | 30 | "IUser:NFCTagDetected"); |
| 31 | } | 31 | } |
| @@ -34,8 +34,8 @@ Module::Interface::~Interface() = default; | |||
| 34 | 34 | ||
| 35 | class IUser final : public ServiceFramework<IUser> { | 35 | class IUser final : public ServiceFramework<IUser> { |
| 36 | public: | 36 | public: |
| 37 | IUser(Module::Interface& nfp_interface) | 37 | IUser(Module::Interface& nfp_interface, Core::System& system) |
| 38 | : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) { | 38 | : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface), system(system) { |
| 39 | static const FunctionInfo functions[] = { | 39 | static const FunctionInfo functions[] = { |
| 40 | {0, &IUser::Initialize, "Initialize"}, | 40 | {0, &IUser::Initialize, "Initialize"}, |
| 41 | {1, &IUser::Finalize, "Finalize"}, | 41 | {1, &IUser::Finalize, "Finalize"}, |
| @@ -65,7 +65,7 @@ public: | |||
| 65 | }; | 65 | }; |
| 66 | RegisterHandlers(functions); | 66 | RegisterHandlers(functions); |
| 67 | 67 | ||
| 68 | auto& kernel = Core::System::GetInstance().Kernel(); | 68 | auto& kernel = system.Kernel(); |
| 69 | deactivate_event = Kernel::WritableEvent::CreateEventPair( | 69 | deactivate_event = Kernel::WritableEvent::CreateEventPair( |
| 70 | kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent"); | 70 | kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent"); |
| 71 | availability_change_event = Kernel::WritableEvent::CreateEventPair( | 71 | availability_change_event = Kernel::WritableEvent::CreateEventPair( |
| @@ -324,6 +324,7 @@ private: | |||
| 324 | Kernel::EventPair deactivate_event; | 324 | Kernel::EventPair deactivate_event; |
| 325 | Kernel::EventPair availability_change_event; | 325 | Kernel::EventPair availability_change_event; |
| 326 | const Module::Interface& nfp_interface; | 326 | const Module::Interface& nfp_interface; |
| 327 | Core::System& system; | ||
| 327 | }; | 328 | }; |
| 328 | 329 | ||
| 329 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | 330 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { |
| @@ -331,7 +332,7 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | |||
| 331 | 332 | ||
| 332 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 333 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 333 | rb.Push(RESULT_SUCCESS); | 334 | rb.Push(RESULT_SUCCESS); |
| 334 | rb.PushIpcInterface<IUser>(*this); | 335 | rb.PushIpcInterface<IUser>(*this, system); |
| 335 | } | 336 | } |
| 336 | 337 | ||
| 337 | bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | 338 | bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { |
| @@ -353,9 +354,9 @@ const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const | |||
| 353 | return amiibo; | 354 | return amiibo; |
| 354 | } | 355 | } |
| 355 | 356 | ||
| 356 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 357 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 357 | auto module = std::make_shared<Module>(); | 358 | auto module = std::make_shared<Module>(); |
| 358 | std::make_shared<NFP_User>(module)->InstallAsService(service_manager); | 359 | std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager); |
| 359 | } | 360 | } |
| 360 | 361 | ||
| 361 | } // namespace Service::NFP | 362 | } // namespace Service::NFP |
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index a1817e991..9718ef745 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h | |||
| @@ -16,7 +16,7 @@ class Module final { | |||
| 16 | public: | 16 | public: |
| 17 | class Interface : public ServiceFramework<Interface> { | 17 | class Interface : public ServiceFramework<Interface> { |
| 18 | public: | 18 | public: |
| 19 | explicit Interface(std::shared_ptr<Module> module, const char* name); | 19 | explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); |
| 20 | ~Interface() override; | 20 | ~Interface() override; |
| 21 | 21 | ||
| 22 | struct ModelInfo { | 22 | struct ModelInfo { |
| @@ -43,9 +43,10 @@ public: | |||
| 43 | 43 | ||
| 44 | protected: | 44 | protected: |
| 45 | std::shared_ptr<Module> module; | 45 | std::shared_ptr<Module> module; |
| 46 | Core::System& system; | ||
| 46 | }; | 47 | }; |
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | void InstallInterfaces(SM::ServiceManager& service_manager); | 50 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 50 | 51 | ||
| 51 | } // namespace Service::NFP | 52 | } // namespace Service::NFP |
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 784a87c1b..298184f17 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::NFP { | 7 | namespace Service::NFP { |
| 8 | 8 | ||
| 9 | NFP_User::NFP_User(std::shared_ptr<Module> module) | 9 | NFP_User::NFP_User(std::shared_ptr<Module> module, Core::System& system) |
| 10 | : Module::Interface(std::move(module), "nfp:user") { | 10 | : Module::Interface(std::move(module), system, "nfp:user") { |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, &NFP_User::CreateUserInterface, "CreateUserInterface"}, | 12 | {0, &NFP_User::CreateUserInterface, "CreateUserInterface"}, |
| 13 | }; | 13 | }; |
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h index 65d9aaf48..1686ebf20 100644 --- a/src/core/hle/service/nfp/nfp_user.h +++ b/src/core/hle/service/nfp/nfp_user.h | |||
| @@ -10,7 +10,7 @@ namespace Service::NFP { | |||
| 10 | 10 | ||
| 11 | class NFP_User final : public Module::Interface { | 11 | class NFP_User final : public Module::Interface { |
| 12 | public: | 12 | public: |
| 13 | explicit NFP_User(std::shared_ptr<Module> module); | 13 | explicit NFP_User(std::shared_ptr<Module> module, Core::System& system); |
| 14 | ~NFP_User() override; | 14 | ~NFP_User() override; |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 76b12b482..756a2af57 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -12,6 +12,13 @@ | |||
| 12 | 12 | ||
| 13 | namespace Service::NIFM { | 13 | namespace Service::NIFM { |
| 14 | 14 | ||
| 15 | enum class RequestState : u32 { | ||
| 16 | NotSubmitted = 1, | ||
| 17 | Error = 1, ///< The duplicate 1 is intentional; it means both not submitted and error on HW. | ||
| 18 | Pending = 2, | ||
| 19 | Connected = 3, | ||
| 20 | }; | ||
| 21 | |||
| 15 | class IScanRequest final : public ServiceFramework<IScanRequest> { | 22 | class IScanRequest final : public ServiceFramework<IScanRequest> { |
| 16 | public: | 23 | public: |
| 17 | explicit IScanRequest() : ServiceFramework("IScanRequest") { | 24 | explicit IScanRequest() : ServiceFramework("IScanRequest") { |
| @@ -31,7 +38,7 @@ public: | |||
| 31 | 38 | ||
| 32 | class IRequest final : public ServiceFramework<IRequest> { | 39 | class IRequest final : public ServiceFramework<IRequest> { |
| 33 | public: | 40 | public: |
| 34 | explicit IRequest() : ServiceFramework("IRequest") { | 41 | explicit IRequest(Core::System& system) : ServiceFramework("IRequest") { |
| 35 | static const FunctionInfo functions[] = { | 42 | static const FunctionInfo functions[] = { |
| 36 | {0, &IRequest::GetRequestState, "GetRequestState"}, | 43 | {0, &IRequest::GetRequestState, "GetRequestState"}, |
| 37 | {1, &IRequest::GetResult, "GetResult"}, | 44 | {1, &IRequest::GetResult, "GetResult"}, |
| @@ -61,7 +68,7 @@ public: | |||
| 61 | }; | 68 | }; |
| 62 | RegisterHandlers(functions); | 69 | RegisterHandlers(functions); |
| 63 | 70 | ||
| 64 | auto& kernel = Core::System::GetInstance().Kernel(); | 71 | auto& kernel = system.Kernel(); |
| 65 | event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, | 72 | event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, |
| 66 | "IRequest:Event1"); | 73 | "IRequest:Event1"); |
| 67 | event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, | 74 | event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, |
| @@ -81,7 +88,7 @@ private: | |||
| 81 | 88 | ||
| 82 | IPC::ResponseBuilder rb{ctx, 3}; | 89 | IPC::ResponseBuilder rb{ctx, 3}; |
| 83 | rb.Push(RESULT_SUCCESS); | 90 | rb.Push(RESULT_SUCCESS); |
| 84 | rb.Push<u32>(0); | 91 | rb.PushEnum(RequestState::Connected); |
| 85 | } | 92 | } |
| 86 | 93 | ||
| 87 | void GetResult(Kernel::HLERequestContext& ctx) { | 94 | void GetResult(Kernel::HLERequestContext& ctx) { |
| @@ -130,7 +137,7 @@ public: | |||
| 130 | 137 | ||
| 131 | class IGeneralService final : public ServiceFramework<IGeneralService> { | 138 | class IGeneralService final : public ServiceFramework<IGeneralService> { |
| 132 | public: | 139 | public: |
| 133 | IGeneralService(); | 140 | IGeneralService(Core::System& system); |
| 134 | 141 | ||
| 135 | private: | 142 | private: |
| 136 | void GetClientId(Kernel::HLERequestContext& ctx) { | 143 | void GetClientId(Kernel::HLERequestContext& ctx) { |
| @@ -155,7 +162,7 @@ private: | |||
| 155 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 162 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 156 | 163 | ||
| 157 | rb.Push(RESULT_SUCCESS); | 164 | rb.Push(RESULT_SUCCESS); |
| 158 | rb.PushIpcInterface<IRequest>(); | 165 | rb.PushIpcInterface<IRequest>(system); |
| 159 | } | 166 | } |
| 160 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { | 167 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { |
| 161 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 168 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| @@ -189,18 +196,20 @@ private: | |||
| 189 | 196 | ||
| 190 | IPC::ResponseBuilder rb{ctx, 3}; | 197 | IPC::ResponseBuilder rb{ctx, 3}; |
| 191 | rb.Push(RESULT_SUCCESS); | 198 | rb.Push(RESULT_SUCCESS); |
| 192 | rb.Push<u8>(0); | 199 | rb.Push<u8>(1); |
| 193 | } | 200 | } |
| 194 | void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { | 201 | void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { |
| 195 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 202 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 196 | 203 | ||
| 197 | IPC::ResponseBuilder rb{ctx, 3}; | 204 | IPC::ResponseBuilder rb{ctx, 3}; |
| 198 | rb.Push(RESULT_SUCCESS); | 205 | rb.Push(RESULT_SUCCESS); |
| 199 | rb.Push<u8>(0); | 206 | rb.Push<u8>(1); |
| 200 | } | 207 | } |
| 208 | Core::System& system; | ||
| 201 | }; | 209 | }; |
| 202 | 210 | ||
| 203 | IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { | 211 | IGeneralService::IGeneralService(Core::System& system) |
| 212 | : ServiceFramework("IGeneralService"), system(system) { | ||
| 204 | static const FunctionInfo functions[] = { | 213 | static const FunctionInfo functions[] = { |
| 205 | {1, &IGeneralService::GetClientId, "GetClientId"}, | 214 | {1, &IGeneralService::GetClientId, "GetClientId"}, |
| 206 | {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, | 215 | {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, |
| @@ -245,7 +254,8 @@ IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { | |||
| 245 | 254 | ||
| 246 | class NetworkInterface final : public ServiceFramework<NetworkInterface> { | 255 | class NetworkInterface final : public ServiceFramework<NetworkInterface> { |
| 247 | public: | 256 | public: |
| 248 | explicit NetworkInterface(const char* name) : ServiceFramework{name} { | 257 | explicit NetworkInterface(const char* name, Core::System& system) |
| 258 | : ServiceFramework{name}, system(system) { | ||
| 249 | static const FunctionInfo functions[] = { | 259 | static const FunctionInfo functions[] = { |
| 250 | {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, | 260 | {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, |
| 251 | {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"}, | 261 | {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"}, |
| @@ -258,7 +268,7 @@ public: | |||
| 258 | 268 | ||
| 259 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 269 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 260 | rb.Push(RESULT_SUCCESS); | 270 | rb.Push(RESULT_SUCCESS); |
| 261 | rb.PushIpcInterface<IGeneralService>(); | 271 | rb.PushIpcInterface<IGeneralService>(system); |
| 262 | } | 272 | } |
| 263 | 273 | ||
| 264 | void CreateGeneralService(Kernel::HLERequestContext& ctx) { | 274 | void CreateGeneralService(Kernel::HLERequestContext& ctx) { |
| @@ -266,14 +276,17 @@ public: | |||
| 266 | 276 | ||
| 267 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 277 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 268 | rb.Push(RESULT_SUCCESS); | 278 | rb.Push(RESULT_SUCCESS); |
| 269 | rb.PushIpcInterface<IGeneralService>(); | 279 | rb.PushIpcInterface<IGeneralService>(system); |
| 270 | } | 280 | } |
| 281 | |||
| 282 | private: | ||
| 283 | Core::System& system; | ||
| 271 | }; | 284 | }; |
| 272 | 285 | ||
| 273 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 286 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 274 | std::make_shared<NetworkInterface>("nifm:a")->InstallAsService(service_manager); | 287 | std::make_shared<NetworkInterface>("nifm:a", system)->InstallAsService(service_manager); |
| 275 | std::make_shared<NetworkInterface>("nifm:s")->InstallAsService(service_manager); | 288 | std::make_shared<NetworkInterface>("nifm:s", system)->InstallAsService(service_manager); |
| 276 | std::make_shared<NetworkInterface>("nifm:u")->InstallAsService(service_manager); | 289 | std::make_shared<NetworkInterface>("nifm:u", system)->InstallAsService(service_manager); |
| 277 | } | 290 | } |
| 278 | 291 | ||
| 279 | } // namespace Service::NIFM | 292 | } // namespace Service::NIFM |
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h index 4616b3b48..6857e18f9 100644 --- a/src/core/hle/service/nifm/nifm.h +++ b/src/core/hle/service/nifm/nifm.h | |||
| @@ -8,9 +8,13 @@ namespace Service::SM { | |||
| 8 | class ServiceManager; | 8 | class ServiceManager; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 11 | namespace Service::NIFM { | 15 | namespace Service::NIFM { |
| 12 | 16 | ||
| 13 | /// Registers all NIFM services with the specified service manager. | 17 | /// Registers all NIFM services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& service_manager); | 18 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 15 | 19 | ||
| 16 | } // namespace Service::NIFM | 20 | } // namespace Service::NIFM |
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index f319a3ca1..75d414952 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp | |||
| @@ -126,7 +126,7 @@ public: | |||
| 126 | class IEnsureNetworkClockAvailabilityService final | 126 | class IEnsureNetworkClockAvailabilityService final |
| 127 | : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { | 127 | : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { |
| 128 | public: | 128 | public: |
| 129 | IEnsureNetworkClockAvailabilityService() | 129 | explicit IEnsureNetworkClockAvailabilityService(Core::System& system) |
| 130 | : ServiceFramework("IEnsureNetworkClockAvailabilityService") { | 130 | : ServiceFramework("IEnsureNetworkClockAvailabilityService") { |
| 131 | static const FunctionInfo functions[] = { | 131 | static const FunctionInfo functions[] = { |
| 132 | {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, | 132 | {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, |
| @@ -139,7 +139,7 @@ public: | |||
| 139 | }; | 139 | }; |
| 140 | RegisterHandlers(functions); | 140 | RegisterHandlers(functions); |
| 141 | 141 | ||
| 142 | auto& kernel = Core::System::GetInstance().Kernel(); | 142 | auto& kernel = system.Kernel(); |
| 143 | finished_event = Kernel::WritableEvent::CreateEventPair( | 143 | finished_event = Kernel::WritableEvent::CreateEventPair( |
| 144 | kernel, Kernel::ResetType::Automatic, | 144 | kernel, Kernel::ResetType::Automatic, |
| 145 | "IEnsureNetworkClockAvailabilityService:FinishEvent"); | 145 | "IEnsureNetworkClockAvailabilityService:FinishEvent"); |
| @@ -200,7 +200,7 @@ private: | |||
| 200 | 200 | ||
| 201 | class NTC final : public ServiceFramework<NTC> { | 201 | class NTC final : public ServiceFramework<NTC> { |
| 202 | public: | 202 | public: |
| 203 | explicit NTC() : ServiceFramework{"ntc"} { | 203 | explicit NTC(Core::System& system) : ServiceFramework{"ntc"}, system(system) { |
| 204 | // clang-format off | 204 | // clang-format off |
| 205 | static const FunctionInfo functions[] = { | 205 | static const FunctionInfo functions[] = { |
| 206 | {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"}, | 206 | {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"}, |
| @@ -218,7 +218,7 @@ private: | |||
| 218 | 218 | ||
| 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 220 | rb.Push(RESULT_SUCCESS); | 220 | rb.Push(RESULT_SUCCESS); |
| 221 | rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); | 221 | rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(system); |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | // TODO(ogniK): Do we need these? | 224 | // TODO(ogniK): Do we need these? |
| @@ -235,13 +235,14 @@ private: | |||
| 235 | IPC::ResponseBuilder rb{ctx, 2}; | 235 | IPC::ResponseBuilder rb{ctx, 2}; |
| 236 | rb.Push(RESULT_SUCCESS); | 236 | rb.Push(RESULT_SUCCESS); |
| 237 | } | 237 | } |
| 238 | Core::System& system; | ||
| 238 | }; | 239 | }; |
| 239 | 240 | ||
| 240 | void InstallInterfaces(SM::ServiceManager& sm) { | 241 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 241 | std::make_shared<NIM>()->InstallAsService(sm); | 242 | std::make_shared<NIM>()->InstallAsService(sm); |
| 242 | std::make_shared<NIM_ECA>()->InstallAsService(sm); | 243 | std::make_shared<NIM_ECA>()->InstallAsService(sm); |
| 243 | std::make_shared<NIM_SHP>()->InstallAsService(sm); | 244 | std::make_shared<NIM_SHP>()->InstallAsService(sm); |
| 244 | std::make_shared<NTC>()->InstallAsService(sm); | 245 | std::make_shared<NTC>(system)->InstallAsService(sm); |
| 245 | } | 246 | } |
| 246 | 247 | ||
| 247 | } // namespace Service::NIM | 248 | } // namespace Service::NIM |
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h index 2a2a92df0..dbe25dc01 100644 --- a/src/core/hle/service/nim/nim.h +++ b/src/core/hle/service/nim/nim.h | |||
| @@ -8,8 +8,12 @@ namespace Service::SM { | |||
| 8 | class ServiceManager; | 8 | class ServiceManager; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 11 | namespace Service::NIM { | 15 | namespace Service::NIM { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::NIM | 19 | } // namespace Service::NIM |
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 13121c4f1..15c156ce1 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -617,7 +617,8 @@ public: | |||
| 617 | } | 617 | } |
| 618 | }; | 618 | }; |
| 619 | 619 | ||
| 620 | void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc) { | 620 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 621 | |||
| 621 | std::make_shared<NS>("ns:am2")->InstallAsService(service_manager); | 622 | std::make_shared<NS>("ns:am2")->InstallAsService(service_manager); |
| 622 | std::make_shared<NS>("ns:ec")->InstallAsService(service_manager); | 623 | std::make_shared<NS>("ns:ec")->InstallAsService(service_manager); |
| 623 | std::make_shared<NS>("ns:rid")->InstallAsService(service_manager); | 624 | std::make_shared<NS>("ns:rid")->InstallAsService(service_manager); |
| @@ -628,7 +629,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSyst | |||
| 628 | std::make_shared<NS_SU>()->InstallAsService(service_manager); | 629 | std::make_shared<NS_SU>()->InstallAsService(service_manager); |
| 629 | std::make_shared<NS_VM>()->InstallAsService(service_manager); | 630 | std::make_shared<NS_VM>()->InstallAsService(service_manager); |
| 630 | 631 | ||
| 631 | std::make_shared<PL_U>(fsc)->InstallAsService(service_manager); | 632 | std::make_shared<PL_U>(system)->InstallAsService(service_manager); |
| 632 | } | 633 | } |
| 633 | 634 | ||
| 634 | } // namespace Service::NS | 635 | } // namespace Service::NS |
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index d067e7a9a..13a64ad88 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h | |||
| @@ -97,8 +97,7 @@ private: | |||
| 97 | }; | 97 | }; |
| 98 | 98 | ||
| 99 | /// Registers all NS services with the specified service manager. | 99 | /// Registers all NS services with the specified service manager. |
| 100 | void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc); | 100 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 101 | 101 | ||
| 102 | } // namespace NS | 102 | } // namespace NS |
| 103 | |||
| 104 | } // namespace Service | 103 | } // namespace Service |
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 9d49f36e8..7dcdb4a07 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -150,8 +150,9 @@ struct PL_U::Impl { | |||
| 150 | std::vector<FontRegion> shared_font_regions; | 150 | std::vector<FontRegion> shared_font_regions; |
| 151 | }; | 151 | }; |
| 152 | 152 | ||
| 153 | PL_U::PL_U(FileSystem::FileSystemController& fsc) | 153 | PL_U::PL_U(Core::System& system) |
| 154 | : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { | 154 | : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()}, system(system) { |
| 155 | |||
| 155 | static const FunctionInfo functions[] = { | 156 | static const FunctionInfo functions[] = { |
| 156 | {0, &PL_U::RequestLoad, "RequestLoad"}, | 157 | {0, &PL_U::RequestLoad, "RequestLoad"}, |
| 157 | {1, &PL_U::GetLoadState, "GetLoadState"}, | 158 | {1, &PL_U::GetLoadState, "GetLoadState"}, |
| @@ -161,6 +162,9 @@ PL_U::PL_U(FileSystem::FileSystemController& fsc) | |||
| 161 | {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, | 162 | {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, |
| 162 | }; | 163 | }; |
| 163 | RegisterHandlers(functions); | 164 | RegisterHandlers(functions); |
| 165 | |||
| 166 | auto& fsc = system.GetFileSystemController(); | ||
| 167 | |||
| 164 | // Attempt to load shared font data from disk | 168 | // Attempt to load shared font data from disk |
| 165 | const auto* nand = fsc.GetSystemNANDContents(); | 169 | const auto* nand = fsc.GetSystemNANDContents(); |
| 166 | std::size_t offset = 0; | 170 | std::size_t offset = 0; |
| @@ -325,7 +329,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | |||
| 325 | Kernel::MemoryState::Shared); | 329 | Kernel::MemoryState::Shared); |
| 326 | 330 | ||
| 327 | // Create shared font memory object | 331 | // Create shared font memory object |
| 328 | auto& kernel = Core::System::GetInstance().Kernel(); | 332 | auto& kernel = system.Kernel(); |
| 329 | impl->shared_font_mem = Kernel::SharedMemory::Create( | 333 | impl->shared_font_mem = Kernel::SharedMemory::Create( |
| 330 | kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, | 334 | kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, |
| 331 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, | 335 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, |
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h index 35ca424d2..1063f4204 100644 --- a/src/core/hle/service/ns/pl_u.h +++ b/src/core/hle/service/ns/pl_u.h | |||
| @@ -17,7 +17,7 @@ namespace NS { | |||
| 17 | 17 | ||
| 18 | class PL_U final : public ServiceFramework<PL_U> { | 18 | class PL_U final : public ServiceFramework<PL_U> { |
| 19 | public: | 19 | public: |
| 20 | PL_U(FileSystem::FileSystemController& fsc); | 20 | explicit PL_U(Core::System& system); |
| 21 | ~PL_U() override; | 21 | ~PL_U() override; |
| 22 | 22 | ||
| 23 | private: | 23 | private: |
| @@ -30,6 +30,7 @@ private: | |||
| 30 | 30 | ||
| 31 | struct Impl; | 31 | struct Impl; |
| 32 | std::unique_ptr<Impl> impl; | 32 | std::unique_ptr<Impl> impl; |
| 33 | Core::System& system; | ||
| 33 | }; | 34 | }; |
| 34 | 35 | ||
| 35 | } // namespace NS | 36 | } // namespace NS |
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 5b8248433..1b52511a5 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 11 | #include "core/hle/service/nvdrv/nvdata.h" | 11 | #include "core/hle/service/nvdrv/nvdata.h" |
| 12 | #include "core/hle/service/service.h" | ||
| 12 | 13 | ||
| 13 | namespace Core { | 14 | namespace Core { |
| 14 | class System; | 15 | class System; |
| @@ -38,8 +39,9 @@ public: | |||
| 38 | * @param output A buffer where the output data will be written to. | 39 | * @param output A buffer where the output data will be written to. |
| 39 | * @returns The result code of the ioctl. | 40 | * @returns The result code of the ioctl. |
| 40 | */ | 41 | */ |
| 41 | virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 42 | virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 42 | IoctlCtrl& ctrl) = 0; | 43 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 44 | IoctlVersion version) = 0; | ||
| 43 | 45 | ||
| 44 | protected: | 46 | protected: |
| 45 | Core::System& system; | 47 | Core::System& system; |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 926a1285d..f764388bc 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | |||
| @@ -17,8 +17,9 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de | |||
| 17 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 17 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 18 | nvdisp_disp0 ::~nvdisp_disp0() = default; | 18 | nvdisp_disp0 ::~nvdisp_disp0() = default; |
| 19 | 19 | ||
| 20 | u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 20 | u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 21 | IoctlCtrl& ctrl) { | 21 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 22 | IoctlVersion version) { | ||
| 22 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 23 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); |
| 23 | return 0; | 24 | return 0; |
| 24 | } | 25 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index e79e490ff..6fcdeee84 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | |||
| @@ -20,8 +20,9 @@ public: | |||
| 20 | explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 20 | explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 21 | ~nvdisp_disp0() override; | 21 | ~nvdisp_disp0() override; |
| 22 | 22 | ||
| 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 24 | IoctlCtrl& ctrl) override; | 24 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 25 | IoctlVersion version) override; | ||
| 25 | 26 | ||
| 26 | /// Performs a screen flip, drawing the buffer pointed to by the handle. | 27 | /// Performs a screen flip, drawing the buffer pointed to by the handle. |
| 27 | void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, | 28 | void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 24ab3f2e9..6bc053f27 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -26,8 +26,9 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_ | |||
| 26 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 26 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 27 | nvhost_as_gpu::~nvhost_as_gpu() = default; | 27 | nvhost_as_gpu::~nvhost_as_gpu() = default; |
| 28 | 28 | ||
| 29 | u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 29 | u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 30 | IoctlCtrl& ctrl) { | 30 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 31 | IoctlVersion version) { | ||
| 31 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 32 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 32 | command.raw, input.size(), output.size()); | 33 | command.raw, input.size(), output.size()); |
| 33 | 34 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 30ca5f4c3..169fb8f0e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | |||
| @@ -20,8 +20,9 @@ public: | |||
| 20 | explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 20 | explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 21 | ~nvhost_as_gpu() override; | 21 | ~nvhost_as_gpu() override; |
| 22 | 22 | ||
| 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 24 | IoctlCtrl& ctrl) override; | 24 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 25 | IoctlVersion version) override; | ||
| 25 | 26 | ||
| 26 | private: | 27 | private: |
| 27 | enum class IoctlCommand : u32_le { | 28 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 9a66a5f88..ff6b1abae 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -19,8 +19,9 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface) | |||
| 19 | : nvdevice(system), events_interface{events_interface} {} | 19 | : nvdevice(system), events_interface{events_interface} {} |
| 20 | nvhost_ctrl::~nvhost_ctrl() = default; | 20 | nvhost_ctrl::~nvhost_ctrl() = default; |
| 21 | 21 | ||
| 22 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 22 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 23 | IoctlCtrl& ctrl) { | 23 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 24 | IoctlVersion version) { | ||
| 24 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 25 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 25 | command.raw, input.size(), output.size()); | 26 | command.raw, input.size(), output.size()); |
| 26 | 27 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 14e6e7e57..9898623de 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | |||
| @@ -17,8 +17,9 @@ public: | |||
| 17 | explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface); | 17 | explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface); |
| 18 | ~nvhost_ctrl() override; | 18 | ~nvhost_ctrl() override; |
| 19 | 19 | ||
| 20 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 20 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 21 | IoctlCtrl& ctrl) override; | 21 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 22 | IoctlVersion version) override; | ||
| 22 | 23 | ||
| 23 | private: | 24 | private: |
| 24 | enum class IoctlCommand : u32_le { | 25 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 988effd90..389ace76f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -15,14 +15,15 @@ namespace Service::Nvidia::Devices { | |||
| 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} | 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} |
| 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; | 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; |
| 17 | 17 | ||
| 18 | u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 18 | u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, |
| 19 | IoctlCtrl& ctrl) { | 19 | const std::vector<u8>& input2, std::vector<u8>& output, |
| 20 | std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) { | ||
| 20 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 21 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 21 | command.raw, input.size(), output.size()); | 22 | command.raw, input.size(), output.size()); |
| 22 | 23 | ||
| 23 | switch (static_cast<IoctlCommand>(command.raw)) { | 24 | switch (static_cast<IoctlCommand>(command.raw)) { |
| 24 | case IoctlCommand::IocGetCharacteristicsCommand: | 25 | case IoctlCommand::IocGetCharacteristicsCommand: |
| 25 | return GetCharacteristics(input, output); | 26 | return GetCharacteristics(input, output, output2, version); |
| 26 | case IoctlCommand::IocGetTPCMasksCommand: | 27 | case IoctlCommand::IocGetTPCMasksCommand: |
| 27 | return GetTPCMasks(input, output); | 28 | return GetTPCMasks(input, output); |
| 28 | case IoctlCommand::IocGetActiveSlotMaskCommand: | 29 | case IoctlCommand::IocGetActiveSlotMaskCommand: |
| @@ -44,7 +45,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec | |||
| 44 | return 0; | 45 | return 0; |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output) { | 48 | u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, |
| 49 | std::vector<u8>& output2, IoctlVersion version) { | ||
| 48 | LOG_DEBUG(Service_NVDRV, "called"); | 50 | LOG_DEBUG(Service_NVDRV, "called"); |
| 49 | IoctlCharacteristics params{}; | 51 | IoctlCharacteristics params{}; |
| 50 | std::memcpy(¶ms, input.data(), input.size()); | 52 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -85,7 +87,13 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto | |||
| 85 | params.gc.gr_compbit_store_base_hw = 0x0; | 87 | params.gc.gr_compbit_store_base_hw = 0x0; |
| 86 | params.gpu_characteristics_buf_size = 0xA0; | 88 | params.gpu_characteristics_buf_size = 0xA0; |
| 87 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) | 89 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) |
| 88 | std::memcpy(output.data(), ¶ms, output.size()); | 90 | |
| 91 | if (version == IoctlVersion::Version3) { | ||
| 92 | std::memcpy(output.data(), input.data(), output.size()); | ||
| 93 | std::memcpy(output2.data(), ¶ms.gc, output2.size()); | ||
| 94 | } else { | ||
| 95 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 96 | } | ||
| 89 | return 0; | 97 | return 0; |
| 90 | } | 98 | } |
| 91 | 99 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index 2b035ae3f..642b0a2cb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | |||
| @@ -16,8 +16,9 @@ public: | |||
| 16 | explicit nvhost_ctrl_gpu(Core::System& system); | 16 | explicit nvhost_ctrl_gpu(Core::System& system); |
| 17 | ~nvhost_ctrl_gpu() override; | 17 | ~nvhost_ctrl_gpu() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 20 | IoctlCtrl& ctrl) override; | 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 21 | IoctlVersion version) override; | ||
| 21 | 22 | ||
| 22 | private: | 23 | private: |
| 23 | enum class IoctlCommand : u32_le { | 24 | enum class IoctlCommand : u32_le { |
| @@ -162,7 +163,8 @@ private: | |||
| 162 | }; | 163 | }; |
| 163 | static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size"); | 164 | static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size"); |
| 164 | 165 | ||
| 165 | u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); | 166 | u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, |
| 167 | std::vector<u8>& output2, IoctlVersion version); | ||
| 166 | u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); | 168 | u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); |
| 167 | u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); | 169 | u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); |
| 168 | u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); | 170 | u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index b4ee2a255..2b8d1bef6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -17,8 +17,9 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | |||
| 17 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 17 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 18 | nvhost_gpu::~nvhost_gpu() = default; | 18 | nvhost_gpu::~nvhost_gpu() = default; |
| 19 | 19 | ||
| 20 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 20 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 21 | IoctlCtrl& ctrl) { | 21 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 22 | IoctlVersion version) { | ||
| 22 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 23 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 23 | command.raw, input.size(), output.size()); | 24 | command.raw, input.size(), output.size()); |
| 24 | 25 | ||
| @@ -50,7 +51,7 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u | |||
| 50 | return SubmitGPFIFO(input, output); | 51 | return SubmitGPFIFO(input, output); |
| 51 | } | 52 | } |
| 52 | if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { | 53 | if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { |
| 53 | return KickoffPB(input, output); | 54 | return KickoffPB(input, output, input2, version); |
| 54 | } | 55 | } |
| 55 | } | 56 | } |
| 56 | 57 | ||
| @@ -173,7 +174,8 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 173 | return 0; | 174 | return 0; |
| 174 | } | 175 | } |
| 175 | 176 | ||
| 176 | u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) { | 177 | u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, |
| 178 | const std::vector<u8>& input2, IoctlVersion version) { | ||
| 177 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 179 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 178 | UNIMPLEMENTED(); | 180 | UNIMPLEMENTED(); |
| 179 | } | 181 | } |
| @@ -183,9 +185,13 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 183 | params.num_entries, params.flags.raw); | 185 | params.num_entries, params.flags.raw); |
| 184 | 186 | ||
| 185 | Tegra::CommandList entries(params.num_entries); | 187 | Tegra::CommandList entries(params.num_entries); |
| 186 | Memory::ReadBlock(params.address, entries.data(), | 188 | if (version == IoctlVersion::Version2) { |
| 187 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 189 | std::memcpy(entries.data(), input2.data(), |
| 188 | 190 | params.num_entries * sizeof(Tegra::CommandListHeader)); | |
| 191 | } else { | ||
| 192 | Memory::ReadBlock(params.address, entries.data(), | ||
| 193 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 194 | } | ||
| 189 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); | 195 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); |
| 190 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); | 196 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); |
| 191 | 197 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index d2e8fbae9..d056dd046 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h | |||
| @@ -24,8 +24,9 @@ public: | |||
| 24 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 24 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 25 | ~nvhost_gpu() override; | 25 | ~nvhost_gpu() override; |
| 26 | 26 | ||
| 27 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 27 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 28 | IoctlCtrl& ctrl) override; | 28 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 29 | IoctlVersion version) override; | ||
| 29 | 30 | ||
| 30 | private: | 31 | private: |
| 31 | enum class IoctlCommand : u32_le { | 32 | enum class IoctlCommand : u32_le { |
| @@ -183,7 +184,8 @@ private: | |||
| 183 | u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); | 184 | u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); |
| 184 | u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); | 185 | u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); |
| 185 | u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); | 186 | u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); |
| 186 | u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output); | 187 | u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, |
| 188 | const std::vector<u8>& input2, IoctlVersion version); | ||
| 187 | u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); | 189 | u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); |
| 188 | u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); | 190 | u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); |
| 189 | 191 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index f572ad30f..bdae8b887 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -13,8 +13,9 @@ namespace Service::Nvidia::Devices { | |||
| 13 | nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} | 13 | nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} |
| 14 | nvhost_nvdec::~nvhost_nvdec() = default; | 14 | nvhost_nvdec::~nvhost_nvdec() = default; |
| 15 | 15 | ||
| 16 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 16 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 17 | IoctlCtrl& ctrl) { | 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 18 | IoctlVersion version) { | ||
| 18 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 19 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 19 | command.raw, input.size(), output.size()); | 20 | command.raw, input.size(), output.size()); |
| 20 | 21 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 2710f0511..cbdac8069 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | |||
| @@ -16,8 +16,9 @@ public: | |||
| 16 | explicit nvhost_nvdec(Core::System& system); | 16 | explicit nvhost_nvdec(Core::System& system); |
| 17 | ~nvhost_nvdec() override; | 17 | ~nvhost_nvdec() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 20 | IoctlCtrl& ctrl) override; | 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 21 | IoctlVersion version) override; | ||
| 21 | 22 | ||
| 22 | private: | 23 | private: |
| 23 | enum class IoctlCommand : u32_le { | 24 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 38282956f..96e7b7dab 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp | |||
| @@ -13,8 +13,9 @@ namespace Service::Nvidia::Devices { | |||
| 13 | nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} | 13 | nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} |
| 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; | 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; |
| 15 | 15 | ||
| 16 | u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 16 | u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 17 | IoctlCtrl& ctrl) { | 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 18 | IoctlVersion version) { | ||
| 18 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 19 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 19 | command.raw, input.size(), output.size()); | 20 | command.raw, input.size(), output.size()); |
| 20 | 21 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 379766693..98dcac52f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h | |||
| @@ -16,8 +16,9 @@ public: | |||
| 16 | explicit nvhost_nvjpg(Core::System& system); | 16 | explicit nvhost_nvjpg(Core::System& system); |
| 17 | ~nvhost_nvjpg() override; | 17 | ~nvhost_nvjpg() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 20 | IoctlCtrl& ctrl) override; | 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 21 | IoctlVersion version) override; | ||
| 21 | 22 | ||
| 22 | private: | 23 | private: |
| 23 | enum class IoctlCommand : u32_le { | 24 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 70e8091db..c695b8863 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -13,8 +13,9 @@ namespace Service::Nvidia::Devices { | |||
| 13 | nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {} | 13 | nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {} |
| 14 | nvhost_vic::~nvhost_vic() = default; | 14 | nvhost_vic::~nvhost_vic() = default; |
| 15 | 15 | ||
| 16 | u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 16 | u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 17 | IoctlCtrl& ctrl) { | 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 18 | IoctlVersion version) { | ||
| 18 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 19 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 19 | command.raw, input.size(), output.size()); | 20 | command.raw, input.size(), output.size()); |
| 20 | 21 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index 7d111977e..bec32bea1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h | |||
| @@ -16,8 +16,9 @@ public: | |||
| 16 | explicit nvhost_vic(Core::System& system); | 16 | explicit nvhost_vic(Core::System& system); |
| 17 | ~nvhost_vic() override; | 17 | ~nvhost_vic() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 20 | IoctlCtrl& ctrl) override; | 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 21 | IoctlVersion version) override; | ||
| 21 | 22 | ||
| 22 | private: | 23 | private: |
| 23 | enum class IoctlCommand : u32_le { | 24 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 223b496b7..8c742316c 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -28,8 +28,9 @@ VAddr nvmap::GetObjectAddress(u32 handle) const { | |||
| 28 | return object->addr; | 28 | return object->addr; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 31 | u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 32 | IoctlCtrl& ctrl) { | 32 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 33 | IoctlVersion version) { | ||
| 33 | switch (static_cast<IoctlCommand>(command.raw)) { | 34 | switch (static_cast<IoctlCommand>(command.raw)) { |
| 34 | case IoctlCommand::Create: | 35 | case IoctlCommand::Create: |
| 35 | return IocCreate(input, output); | 36 | return IocCreate(input, output); |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index bf4a101c2..73c2e8809 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h | |||
| @@ -22,8 +22,9 @@ public: | |||
| 22 | /// Returns the allocated address of an nvmap object given its handle. | 22 | /// Returns the allocated address of an nvmap object given its handle. |
| 23 | VAddr GetObjectAddress(u32 handle) const; | 23 | VAddr GetObjectAddress(u32 handle) const; |
| 24 | 24 | ||
| 25 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | 25 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 26 | IoctlCtrl& ctrl) override; | 26 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 27 | IoctlVersion version) override; | ||
| 27 | 28 | ||
| 28 | /// Represents an nvmap object. | 29 | /// Represents an nvmap object. |
| 29 | struct Object { | 30 | struct Object { |
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index d5be64ed2..5e0c23602 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -33,42 +33,77 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) { | |||
| 33 | rb.Push<u32>(0); | 33 | rb.Push<u32>(0); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { | 36 | void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { |
| 37 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 38 | |||
| 39 | IPC::RequestParser rp{ctx}; | 37 | IPC::RequestParser rp{ctx}; |
| 40 | u32 fd = rp.Pop<u32>(); | 38 | u32 fd = rp.Pop<u32>(); |
| 41 | u32 command = rp.Pop<u32>(); | 39 | u32 command = rp.Pop<u32>(); |
| 42 | 40 | ||
| 43 | std::vector<u8> output(ctx.GetWriteBufferSize()); | 41 | /// Ioctl 3 has 2 outputs, first in the input params, second is the result |
| 42 | std::vector<u8> output(ctx.GetWriteBufferSize(0)); | ||
| 43 | std::vector<u8> output2; | ||
| 44 | if (version == IoctlVersion::Version3) { | ||
| 45 | output2.resize((ctx.GetWriteBufferSize(1))); | ||
| 46 | } | ||
| 47 | |||
| 48 | /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer. | ||
| 49 | /// KickOfPB uses this | ||
| 50 | auto input = ctx.ReadBuffer(0); | ||
| 51 | |||
| 52 | std::vector<u8> input2; | ||
| 53 | if (version == IoctlVersion::Version2) { | ||
| 54 | input2 = ctx.ReadBuffer(1); | ||
| 55 | } | ||
| 44 | 56 | ||
| 45 | IoctlCtrl ctrl{}; | 57 | IoctlCtrl ctrl{}; |
| 46 | 58 | ||
| 47 | u32 result = nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output, ctrl); | 59 | u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version); |
| 48 | 60 | ||
| 49 | if (ctrl.must_delay) { | 61 | if (ctrl.must_delay) { |
| 50 | ctrl.fresh_call = false; | 62 | ctrl.fresh_call = false; |
| 51 | ctx.SleepClientThread( | 63 | ctx.SleepClientThread("NVServices::DelayedResponse", ctrl.timeout, |
| 52 | "NVServices::DelayedResponse", ctrl.timeout, | 64 | [=](Kernel::SharedPtr<Kernel::Thread> thread, |
| 53 | [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, | 65 | Kernel::HLERequestContext& ctx, |
| 54 | Kernel::ThreadWakeupReason reason) { | 66 | Kernel::ThreadWakeupReason reason) { |
| 55 | IoctlCtrl ctrl2{ctrl}; | 67 | IoctlCtrl ctrl2{ctrl}; |
| 56 | std::vector<u8> output2 = output; | 68 | std::vector<u8> tmp_output = output; |
| 57 | u32 result = nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output2, ctrl2); | 69 | std::vector<u8> tmp_output2 = output2; |
| 58 | ctx.WriteBuffer(output2); | 70 | u32 result = nvdrv->Ioctl(fd, command, input, input2, tmp_output, |
| 59 | IPC::ResponseBuilder rb{ctx, 3}; | 71 | tmp_output2, ctrl2, version); |
| 60 | rb.Push(RESULT_SUCCESS); | 72 | ctx.WriteBuffer(tmp_output, 0); |
| 61 | rb.Push(result); | 73 | if (version == IoctlVersion::Version3) { |
| 62 | }, | 74 | ctx.WriteBuffer(tmp_output2, 1); |
| 63 | nvdrv->GetEventWriteable(ctrl.event_id)); | 75 | } |
| 76 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 77 | rb.Push(RESULT_SUCCESS); | ||
| 78 | rb.Push(result); | ||
| 79 | }, | ||
| 80 | nvdrv->GetEventWriteable(ctrl.event_id)); | ||
| 64 | } else { | 81 | } else { |
| 65 | ctx.WriteBuffer(output); | 82 | ctx.WriteBuffer(output); |
| 83 | if (version == IoctlVersion::Version3) { | ||
| 84 | ctx.WriteBuffer(output2, 1); | ||
| 85 | } | ||
| 66 | } | 86 | } |
| 67 | IPC::ResponseBuilder rb{ctx, 3}; | 87 | IPC::ResponseBuilder rb{ctx, 3}; |
| 68 | rb.Push(RESULT_SUCCESS); | 88 | rb.Push(RESULT_SUCCESS); |
| 69 | rb.Push(result); | 89 | rb.Push(result); |
| 70 | } | 90 | } |
| 71 | 91 | ||
| 92 | void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { | ||
| 93 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 94 | IoctlBase(ctx, IoctlVersion::Version1); | ||
| 95 | } | ||
| 96 | |||
| 97 | void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { | ||
| 98 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 99 | IoctlBase(ctx, IoctlVersion::Version2); | ||
| 100 | } | ||
| 101 | |||
| 102 | void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { | ||
| 103 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 104 | IoctlBase(ctx, IoctlVersion::Version3); | ||
| 105 | } | ||
| 106 | |||
| 72 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { | 107 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { |
| 73 | LOG_DEBUG(Service_NVDRV, "called"); | 108 | LOG_DEBUG(Service_NVDRV, "called"); |
| 74 | 109 | ||
| @@ -154,8 +189,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) | |||
| 154 | {8, &NVDRV::SetClientPID, "SetClientPID"}, | 189 | {8, &NVDRV::SetClientPID, "SetClientPID"}, |
| 155 | {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, | 190 | {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, |
| 156 | {10, nullptr, "InitializeDevtools"}, | 191 | {10, nullptr, "InitializeDevtools"}, |
| 157 | {11, &NVDRV::Ioctl, "Ioctl2"}, | 192 | {11, &NVDRV::Ioctl2, "Ioctl2"}, |
| 158 | {12, nullptr, "Ioctl3"}, | 193 | {12, &NVDRV::Ioctl3, "Ioctl3"}, |
| 159 | {13, &NVDRV::FinishInitialize, "FinishInitialize"}, | 194 | {13, &NVDRV::FinishInitialize, "FinishInitialize"}, |
| 160 | }; | 195 | }; |
| 161 | RegisterHandlers(functions); | 196 | RegisterHandlers(functions); |
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 10a0ecd52..9269ce00c 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h | |||
| @@ -24,6 +24,8 @@ public: | |||
| 24 | private: | 24 | private: |
| 25 | void Open(Kernel::HLERequestContext& ctx); | 25 | void Open(Kernel::HLERequestContext& ctx); |
| 26 | void Ioctl(Kernel::HLERequestContext& ctx); | 26 | void Ioctl(Kernel::HLERequestContext& ctx); |
| 27 | void Ioctl2(Kernel::HLERequestContext& ctx); | ||
| 28 | void Ioctl3(Kernel::HLERequestContext& ctx); | ||
| 27 | void Close(Kernel::HLERequestContext& ctx); | 29 | void Close(Kernel::HLERequestContext& ctx); |
| 28 | void Initialize(Kernel::HLERequestContext& ctx); | 30 | void Initialize(Kernel::HLERequestContext& ctx); |
| 29 | void QueryEvent(Kernel::HLERequestContext& ctx); | 31 | void QueryEvent(Kernel::HLERequestContext& ctx); |
| @@ -31,6 +33,7 @@ private: | |||
| 31 | void FinishInitialize(Kernel::HLERequestContext& ctx); | 33 | void FinishInitialize(Kernel::HLERequestContext& ctx); |
| 32 | void GetStatus(Kernel::HLERequestContext& ctx); | 34 | void GetStatus(Kernel::HLERequestContext& ctx); |
| 33 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); | 35 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); |
| 36 | void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); | ||
| 34 | 37 | ||
| 35 | std::shared_ptr<Module> nvdrv; | 38 | std::shared_ptr<Module> nvdrv; |
| 36 | 39 | ||
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index ac03cbc23..529b03471 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h | |||
| @@ -34,6 +34,12 @@ enum class EventState { | |||
| 34 | Busy = 3, | 34 | Busy = 3, |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | enum class IoctlVersion : u32 { | ||
| 38 | Version1, | ||
| 39 | Version2, | ||
| 40 | Version3, | ||
| 41 | }; | ||
| 42 | |||
| 37 | struct IoctlCtrl { | 43 | struct IoctlCtrl { |
| 38 | // First call done to the servioce for services that call itself again after a call. | 44 | // First call done to the servioce for services that call itself again after a call. |
| 39 | bool fresh_call{true}; | 45 | bool fresh_call{true}; |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 2011a226a..307a7e928 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -71,13 +71,14 @@ u32 Module::Open(const std::string& device_name) { | |||
| 71 | return fd; | 71 | return fd; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output, | 74 | u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 75 | IoctlCtrl& ctrl) { | 75 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 76 | IoctlVersion version) { | ||
| 76 | auto itr = open_files.find(fd); | 77 | auto itr = open_files.find(fd); |
| 77 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); | 78 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); |
| 78 | 79 | ||
| 79 | auto& device = itr->second; | 80 | auto& device = itr->second; |
| 80 | return device->ioctl({command}, input, output, ctrl); | 81 | return device->ioctl({command}, input, input2, output, output2, ctrl, version); |
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | ResultCode Module::Close(u32 fd) { | 84 | ResultCode Module::Close(u32 fd) { |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index a339ab672..f8bb28969 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -106,8 +106,9 @@ public: | |||
| 106 | /// Opens a device node and returns a file descriptor to it. | 106 | /// Opens a device node and returns a file descriptor to it. |
| 107 | u32 Open(const std::string& device_name); | 107 | u32 Open(const std::string& device_name); |
| 108 | /// Sends an ioctl command to the specified file descriptor. | 108 | /// Sends an ioctl command to the specified file descriptor. |
| 109 | u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output, | 109 | u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| 110 | IoctlCtrl& ctrl); | 110 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, |
| 111 | IoctlVersion version); | ||
| 111 | /// Closes a device file descriptor and returns operation success. | 112 | /// Closes a device file descriptor and returns operation success. |
| 112 | ResultCode Close(u32 fd); | 113 | ResultCode Close(u32 fd); |
| 113 | 114 | ||
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index f9db79370..2e4d707b9 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -29,26 +29,28 @@ namespace Service::NVFlinger { | |||
| 29 | constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); | 29 | constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); |
| 30 | constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30); | 30 | constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30); |
| 31 | 31 | ||
| 32 | NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} { | 32 | NVFlinger::NVFlinger(Core::System& system) : system(system) { |
| 33 | displays.emplace_back(0, "Default"); | 33 | displays.emplace_back(0, "Default", system); |
| 34 | displays.emplace_back(1, "External"); | 34 | displays.emplace_back(1, "External", system); |
| 35 | displays.emplace_back(2, "Edid"); | 35 | displays.emplace_back(2, "Edid", system); |
| 36 | displays.emplace_back(3, "Internal"); | 36 | displays.emplace_back(3, "Internal", system); |
| 37 | displays.emplace_back(4, "Null"); | 37 | displays.emplace_back(4, "Null", system); |
| 38 | 38 | ||
| 39 | // Schedule the screen composition events | 39 | // Schedule the screen composition events |
| 40 | composition_event = core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, | 40 | composition_event = system.CoreTiming().RegisterEvent( |
| 41 | s64 cycles_late) { | 41 | "ScreenComposition", [this](u64 userdata, s64 cycles_late) { |
| 42 | Compose(); | 42 | Compose(); |
| 43 | const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); | 43 | const auto ticks = |
| 44 | this->core_timing.ScheduleEvent(std::max<s64>(0LL, ticks - cycles_late), composition_event); | 44 | Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); |
| 45 | }); | 45 | this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - cycles_late), |
| 46 | 46 | composition_event); | |
| 47 | core_timing.ScheduleEvent(frame_ticks, composition_event); | 47 | }); |
| 48 | |||
| 49 | system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); | ||
| 48 | } | 50 | } |
| 49 | 51 | ||
| 50 | NVFlinger::~NVFlinger() { | 52 | NVFlinger::~NVFlinger() { |
| 51 | core_timing.UnscheduleEvent(composition_event, 0); | 53 | system.CoreTiming().UnscheduleEvent(composition_event, 0); |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | 56 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { |
| @@ -185,11 +187,9 @@ void NVFlinger::Compose() { | |||
| 185 | MicroProfileFlip(); | 187 | MicroProfileFlip(); |
| 186 | 188 | ||
| 187 | if (!buffer) { | 189 | if (!buffer) { |
| 188 | auto& system_instance = Core::System::GetInstance(); | ||
| 189 | |||
| 190 | // There was no queued buffer to draw, render previous frame | 190 | // There was no queued buffer to draw, render previous frame |
| 191 | system_instance.GetPerfStats().EndGameFrame(); | 191 | system.GetPerfStats().EndGameFrame(); |
| 192 | system_instance.GPU().SwapBuffers({}); | 192 | system.GPU().SwapBuffers({}); |
| 193 | continue; | 193 | continue; |
| 194 | } | 194 | } |
| 195 | 195 | ||
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 988be8726..5d7e3bfb8 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -38,7 +38,7 @@ class BufferQueue; | |||
| 38 | 38 | ||
| 39 | class NVFlinger final { | 39 | class NVFlinger final { |
| 40 | public: | 40 | public: |
| 41 | explicit NVFlinger(Core::Timing::CoreTiming& core_timing); | 41 | explicit NVFlinger(Core::System& system); |
| 42 | ~NVFlinger(); | 42 | ~NVFlinger(); |
| 43 | 43 | ||
| 44 | /// Sets the NVDrv module instance to use to send buffers to the GPU. | 44 | /// Sets the NVDrv module instance to use to send buffers to the GPU. |
| @@ -105,8 +105,7 @@ private: | |||
| 105 | /// Event that handles screen composition. | 105 | /// Event that handles screen composition. |
| 106 | Core::Timing::EventType* composition_event; | 106 | Core::Timing::EventType* composition_event; |
| 107 | 107 | ||
| 108 | /// Core timing instance for registering/unregistering the composition event. | 108 | Core::System& system; |
| 109 | Core::Timing::CoreTiming& core_timing; | ||
| 110 | }; | 109 | }; |
| 111 | 110 | ||
| 112 | } // namespace Service::NVFlinger | 111 | } // namespace Service::NVFlinger |
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 0f79135ff..18d895263 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp | |||
| @@ -15,7 +15,7 @@ namespace Service::PlayReport { | |||
| 15 | 15 | ||
| 16 | class PlayReport final : public ServiceFramework<PlayReport> { | 16 | class PlayReport final : public ServiceFramework<PlayReport> { |
| 17 | public: | 17 | public: |
| 18 | explicit PlayReport(Core::System& system, const char* name) | 18 | explicit PlayReport(const char* name, Core::System& system) |
| 19 | : ServiceFramework{name}, system(system) { | 19 | : ServiceFramework{name}, system(system) { |
| 20 | // clang-format off | 20 | // clang-format off |
| 21 | static const FunctionInfo functions[] = { | 21 | static const FunctionInfo functions[] = { |
| @@ -128,12 +128,12 @@ private: | |||
| 128 | Core::System& system; | 128 | Core::System& system; |
| 129 | }; | 129 | }; |
| 130 | 130 | ||
| 131 | void InstallInterfaces(Core::System& system) { | 131 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 132 | std::make_shared<PlayReport>(system, "prepo:a")->InstallAsService(system.ServiceManager()); | 132 | std::make_shared<PlayReport>("prepo:a", system)->InstallAsService(service_manager); |
| 133 | std::make_shared<PlayReport>(system, "prepo:a2")->InstallAsService(system.ServiceManager()); | 133 | std::make_shared<PlayReport>("prepo:a2", system)->InstallAsService(service_manager); |
| 134 | std::make_shared<PlayReport>(system, "prepo:m")->InstallAsService(system.ServiceManager()); | 134 | std::make_shared<PlayReport>("prepo:m", system)->InstallAsService(service_manager); |
| 135 | std::make_shared<PlayReport>(system, "prepo:s")->InstallAsService(system.ServiceManager()); | 135 | std::make_shared<PlayReport>("prepo:s", system)->InstallAsService(service_manager); |
| 136 | std::make_shared<PlayReport>(system, "prepo:u")->InstallAsService(system.ServiceManager()); | 136 | std::make_shared<PlayReport>("prepo:u", system)->InstallAsService(service_manager); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | } // namespace Service::PlayReport | 139 | } // namespace Service::PlayReport |
diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h index 0ebc3a938..a5682ee26 100644 --- a/src/core/hle/service/prepo/prepo.h +++ b/src/core/hle/service/prepo/prepo.h | |||
| @@ -8,8 +8,12 @@ namespace Service::SM { | |||
| 8 | class ServiceManager; | 8 | class ServiceManager; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 11 | namespace Service::PlayReport { | 15 | namespace Service::PlayReport { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(Core::System& system); | 17 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::PlayReport | 19 | } // namespace Service::PlayReport |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 906fdc415..f2c6fe9dc 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -198,50 +198,50 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co | |||
| 198 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { | 198 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { |
| 199 | // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it | 199 | // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it |
| 200 | // here and pass it into the respective InstallInterfaces functions. | 200 | // here and pass it into the respective InstallInterfaces functions. |
| 201 | auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming()); | 201 | auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system); |
| 202 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); | 202 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); |
| 203 | 203 | ||
| 204 | SM::ServiceManager::InstallInterfaces(sm); | 204 | SM::ServiceManager::InstallInterfaces(sm); |
| 205 | 205 | ||
| 206 | Account::InstallInterfaces(system); | 206 | Account::InstallInterfaces(system); |
| 207 | AM::InstallInterfaces(*sm, nv_flinger, system); | 207 | AM::InstallInterfaces(*sm, nv_flinger, system); |
| 208 | AOC::InstallInterfaces(*sm); | 208 | AOC::InstallInterfaces(*sm, system); |
| 209 | APM::InstallInterfaces(system); | 209 | APM::InstallInterfaces(system); |
| 210 | Audio::InstallInterfaces(*sm, system); | 210 | Audio::InstallInterfaces(*sm, system); |
| 211 | BCAT::InstallInterfaces(*sm); | 211 | BCAT::InstallInterfaces(system); |
| 212 | BPC::InstallInterfaces(*sm); | 212 | BPC::InstallInterfaces(*sm); |
| 213 | BtDrv::InstallInterfaces(*sm); | 213 | BtDrv::InstallInterfaces(*sm, system); |
| 214 | BTM::InstallInterfaces(*sm); | 214 | BTM::InstallInterfaces(*sm, system); |
| 215 | Capture::InstallInterfaces(*sm); | 215 | Capture::InstallInterfaces(*sm); |
| 216 | ERPT::InstallInterfaces(*sm); | 216 | ERPT::InstallInterfaces(*sm); |
| 217 | ES::InstallInterfaces(*sm); | 217 | ES::InstallInterfaces(*sm); |
| 218 | EUPLD::InstallInterfaces(*sm); | 218 | EUPLD::InstallInterfaces(*sm); |
| 219 | Fatal::InstallInterfaces(*sm); | 219 | Fatal::InstallInterfaces(*sm, system); |
| 220 | FGM::InstallInterfaces(*sm); | 220 | FGM::InstallInterfaces(*sm); |
| 221 | FileSystem::InstallInterfaces(system); | 221 | FileSystem::InstallInterfaces(system); |
| 222 | Friend::InstallInterfaces(*sm); | 222 | Friend::InstallInterfaces(*sm, system); |
| 223 | Glue::InstallInterfaces(system); | 223 | Glue::InstallInterfaces(system); |
| 224 | GRC::InstallInterfaces(*sm); | 224 | GRC::InstallInterfaces(*sm); |
| 225 | HID::InstallInterfaces(*sm); | 225 | HID::InstallInterfaces(*sm, system); |
| 226 | LBL::InstallInterfaces(*sm); | 226 | LBL::InstallInterfaces(*sm); |
| 227 | LDN::InstallInterfaces(*sm); | 227 | LDN::InstallInterfaces(*sm); |
| 228 | LDR::InstallInterfaces(*sm); | 228 | LDR::InstallInterfaces(*sm, system); |
| 229 | LM::InstallInterfaces(*sm); | 229 | LM::InstallInterfaces(*sm); |
| 230 | Migration::InstallInterfaces(*sm); | 230 | Migration::InstallInterfaces(*sm); |
| 231 | Mii::InstallInterfaces(*sm); | 231 | Mii::InstallInterfaces(*sm); |
| 232 | MM::InstallInterfaces(*sm); | 232 | MM::InstallInterfaces(*sm); |
| 233 | NCM::InstallInterfaces(*sm); | 233 | NCM::InstallInterfaces(*sm); |
| 234 | NFC::InstallInterfaces(*sm); | 234 | NFC::InstallInterfaces(*sm); |
| 235 | NFP::InstallInterfaces(*sm); | 235 | NFP::InstallInterfaces(*sm, system); |
| 236 | NIFM::InstallInterfaces(*sm); | 236 | NIFM::InstallInterfaces(*sm, system); |
| 237 | NIM::InstallInterfaces(*sm); | 237 | NIM::InstallInterfaces(*sm, system); |
| 238 | NPNS::InstallInterfaces(*sm); | 238 | NPNS::InstallInterfaces(*sm); |
| 239 | NS::InstallInterfaces(*sm, system.GetFileSystemController()); | 239 | NS::InstallInterfaces(*sm, system); |
| 240 | Nvidia::InstallInterfaces(*sm, *nv_flinger, system); | 240 | Nvidia::InstallInterfaces(*sm, *nv_flinger, system); |
| 241 | PCIe::InstallInterfaces(*sm); | 241 | PCIe::InstallInterfaces(*sm); |
| 242 | PCTL::InstallInterfaces(*sm); | 242 | PCTL::InstallInterfaces(*sm); |
| 243 | PCV::InstallInterfaces(*sm); | 243 | PCV::InstallInterfaces(*sm); |
| 244 | PlayReport::InstallInterfaces(system); | 244 | PlayReport::InstallInterfaces(*sm, system); |
| 245 | PM::InstallInterfaces(system); | 245 | PM::InstallInterfaces(system); |
| 246 | PSC::InstallInterfaces(*sm); | 246 | PSC::InstallInterfaces(*sm); |
| 247 | PSM::InstallInterfaces(*sm); | 247 | PSM::InstallInterfaces(*sm); |
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index 1030185e0..9565e7de5 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp | |||
| @@ -7,8 +7,8 @@ | |||
| 7 | namespace Service::Time { | 7 | namespace Service::Time { |
| 8 | 8 | ||
| 9 | Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, | 9 | Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, |
| 10 | const char* name) | 10 | Core::System& system, const char* name) |
| 11 | : Module::Interface(std::move(time), std::move(shared_memory), name) { | 11 | : Module::Interface(std::move(time), std::move(shared_memory), system, name) { |
| 12 | // clang-format off | 12 | // clang-format off |
| 13 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 14 | {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, | 14 | {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, |
diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h index bdf0883e2..5c63a07f4 100644 --- a/src/core/hle/service/time/interface.h +++ b/src/core/hle/service/time/interface.h | |||
| @@ -13,7 +13,7 @@ class SharedMemory; | |||
| 13 | class Time final : public Module::Interface { | 13 | class Time final : public Module::Interface { |
| 14 | public: | 14 | public: |
| 15 | explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, | 15 | explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, |
| 16 | const char* name); | 16 | Core::System& system, const char* name); |
| 17 | ~Time() override; | 17 | ~Time() override; |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index ae6446204..1b9ab8401 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -126,8 +126,8 @@ private: | |||
| 126 | 126 | ||
| 127 | class ISteadyClock final : public ServiceFramework<ISteadyClock> { | 127 | class ISteadyClock final : public ServiceFramework<ISteadyClock> { |
| 128 | public: | 128 | public: |
| 129 | ISteadyClock(std::shared_ptr<SharedMemory> shared_memory) | 129 | ISteadyClock(std::shared_ptr<SharedMemory> shared_memory, Core::System& system) |
| 130 | : ServiceFramework("ISteadyClock"), shared_memory(shared_memory) { | 130 | : ServiceFramework("ISteadyClock"), shared_memory(shared_memory), system(system) { |
| 131 | static const FunctionInfo functions[] = { | 131 | static const FunctionInfo functions[] = { |
| 132 | {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, | 132 | {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, |
| 133 | }; | 133 | }; |
| @@ -150,12 +150,13 @@ private: | |||
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | SteadyClockTimePoint GetCurrentTimePoint() const { | 152 | SteadyClockTimePoint GetCurrentTimePoint() const { |
| 153 | const auto& core_timing = Core::System::GetInstance().CoreTiming(); | 153 | const auto& core_timing = system.CoreTiming(); |
| 154 | const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); | 154 | const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); |
| 155 | return {static_cast<u64_le>(ms.count() / 1000), {}}; | 155 | return {static_cast<u64_le>(ms.count() / 1000), {}}; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | std::shared_ptr<SharedMemory> shared_memory; | 158 | std::shared_ptr<SharedMemory> shared_memory; |
| 159 | Core::System& system; | ||
| 159 | }; | 160 | }; |
| 160 | 161 | ||
| 161 | class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { | 162 | class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { |
| @@ -290,7 +291,7 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { | |||
| 290 | 291 | ||
| 291 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 292 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 292 | rb.Push(RESULT_SUCCESS); | 293 | rb.Push(RESULT_SUCCESS); |
| 293 | rb.PushIpcInterface<ISteadyClock>(shared_memory); | 294 | rb.PushIpcInterface<ISteadyClock>(shared_memory, system); |
| 294 | } | 295 | } |
| 295 | 296 | ||
| 296 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { | 297 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { |
| @@ -325,7 +326,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | |||
| 325 | return; | 326 | return; |
| 326 | } | 327 | } |
| 327 | 328 | ||
| 328 | const auto& core_timing = Core::System::GetInstance().CoreTiming(); | 329 | const auto& core_timing = system.CoreTiming(); |
| 329 | const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); | 330 | const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); |
| 330 | const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}}; | 331 | const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}}; |
| 331 | 332 | ||
| @@ -407,8 +408,10 @@ void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled( | |||
| 407 | } | 408 | } |
| 408 | 409 | ||
| 409 | Module::Interface::Interface(std::shared_ptr<Module> time, | 410 | Module::Interface::Interface(std::shared_ptr<Module> time, |
| 410 | std::shared_ptr<SharedMemory> shared_memory, const char* name) | 411 | std::shared_ptr<SharedMemory> shared_memory, Core::System& system, |
| 411 | : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)) {} | 412 | const char* name) |
| 413 | : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)), | ||
| 414 | system(system) {} | ||
| 412 | 415 | ||
| 413 | Module::Interface::~Interface() = default; | 416 | Module::Interface::~Interface() = default; |
| 414 | 417 | ||
| @@ -416,9 +419,11 @@ void InstallInterfaces(Core::System& system) { | |||
| 416 | auto time = std::make_shared<Module>(); | 419 | auto time = std::make_shared<Module>(); |
| 417 | auto shared_mem = std::make_shared<SharedMemory>(system); | 420 | auto shared_mem = std::make_shared<SharedMemory>(system); |
| 418 | 421 | ||
| 419 | std::make_shared<Time>(time, shared_mem, "time:a")->InstallAsService(system.ServiceManager()); | 422 | std::make_shared<Time>(time, shared_mem, system, "time:a") |
| 420 | std::make_shared<Time>(time, shared_mem, "time:s")->InstallAsService(system.ServiceManager()); | 423 | ->InstallAsService(system.ServiceManager()); |
| 421 | std::make_shared<Time>(std::move(time), shared_mem, "time:u") | 424 | std::make_shared<Time>(time, shared_mem, system, "time:s") |
| 425 | ->InstallAsService(system.ServiceManager()); | ||
| 426 | std::make_shared<Time>(std::move(time), shared_mem, system, "time:u") | ||
| 422 | ->InstallAsService(system.ServiceManager()); | 427 | ->InstallAsService(system.ServiceManager()); |
| 423 | } | 428 | } |
| 424 | 429 | ||
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index e0708f856..c32d32860 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h | |||
| @@ -80,7 +80,8 @@ public: | |||
| 80 | class Interface : public ServiceFramework<Interface> { | 80 | class Interface : public ServiceFramework<Interface> { |
| 81 | public: | 81 | public: |
| 82 | explicit Interface(std::shared_ptr<Module> time, | 82 | explicit Interface(std::shared_ptr<Module> time, |
| 83 | std::shared_ptr<SharedMemory> shared_memory, const char* name); | 83 | std::shared_ptr<SharedMemory> shared_memory, Core::System& system, |
| 84 | const char* name); | ||
| 84 | ~Interface() override; | 85 | ~Interface() override; |
| 85 | 86 | ||
| 86 | void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); | 87 | void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); |
| @@ -97,6 +98,7 @@ public: | |||
| 97 | protected: | 98 | protected: |
| 98 | std::shared_ptr<Module> time; | 99 | std::shared_ptr<Module> time; |
| 99 | std::shared_ptr<SharedMemory> shared_memory; | 100 | std::shared_ptr<SharedMemory> shared_memory; |
| 101 | Core::System& system; | ||
| 100 | }; | 102 | }; |
| 101 | }; | 103 | }; |
| 102 | 104 | ||
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index a8d088305..006a6d9ff 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp | |||
| @@ -15,8 +15,8 @@ | |||
| 15 | 15 | ||
| 16 | namespace Service::VI { | 16 | namespace Service::VI { |
| 17 | 17 | ||
| 18 | Display::Display(u64 id, std::string name) : id{id}, name{std::move(name)} { | 18 | Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} { |
| 19 | auto& kernel = Core::System::GetInstance().Kernel(); | 19 | auto& kernel = system.Kernel(); |
| 20 | vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, | 20 | vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, |
| 21 | fmt::format("Display VSync Event {}", id)); | 21 | fmt::format("Display VSync Event {}", id)); |
| 22 | } | 22 | } |
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 2acd46ff8..f56b5badc 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h | |||
| @@ -26,7 +26,7 @@ public: | |||
| 26 | /// @param id The unique ID for this display. | 26 | /// @param id The unique ID for this display. |
| 27 | /// @param name The name for this display. | 27 | /// @param name The name for this display. |
| 28 | /// | 28 | /// |
| 29 | Display(u64 id, std::string name); | 29 | Display(u64 id, std::string name, Core::System& system); |
| 30 | ~Display(); | 30 | ~Display(); |
| 31 | 31 | ||
| 32 | Display(const Display&) = delete; | 32 | Display(const Display&) = delete; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index e75c700ad..f629892ae 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -150,6 +150,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, | |||
| 150 | // Apply cheats if they exist and the program has a valid title ID | 150 | // Apply cheats if they exist and the program has a valid title ID |
| 151 | if (pm) { | 151 | if (pm) { |
| 152 | auto& system = Core::System::GetInstance(); | 152 | auto& system = Core::System::GetInstance(); |
| 153 | system.SetCurrentProcessBuildID(nso_header.build_id); | ||
| 153 | const auto cheats = pm->CreateCheatList(system, nso_header.build_id); | 154 | const auto cheats = pm->CreateCheatList(system, nso_header.build_id); |
| 154 | if (!cheats.empty()) { | 155 | if (!cheats.empty()) { |
| 155 | system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); | 156 | system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 7de3fd1e5..d1fc94060 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -103,6 +103,8 @@ void LogSettings() { | |||
| 103 | LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub); | 103 | LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub); |
| 104 | LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port); | 104 | LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port); |
| 105 | LogSetting("Debugging_ProgramArgs", Settings::values.program_args); | 105 | LogSetting("Debugging_ProgramArgs", Settings::values.program_args); |
| 106 | LogSetting("Services_BCATBackend", Settings::values.bcat_backend); | ||
| 107 | LogSetting("Services_BCATBoxcatLocal", Settings::values.bcat_boxcat_local); | ||
| 106 | } | 108 | } |
| 107 | 109 | ||
| 108 | } // namespace Settings | 110 | } // namespace Settings |
diff --git a/src/core/settings.h b/src/core/settings.h index 47bddfb30..9c98a9287 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -448,6 +448,10 @@ struct Values { | |||
| 448 | bool reporting_services; | 448 | bool reporting_services; |
| 449 | bool quest_flag; | 449 | bool quest_flag; |
| 450 | 450 | ||
| 451 | // BCAT | ||
| 452 | std::string bcat_backend; | ||
| 453 | bool bcat_boxcat_local; | ||
| 454 | |||
| 451 | // WebService | 455 | // WebService |
| 452 | bool enable_telemetry; | 456 | bool enable_telemetry; |
| 453 | std::string web_api_url; | 457 | std::string web_api_url; |
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 98a8b5337..7ff44f06d 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp | |||
| @@ -29,8 +29,8 @@ void Fermi2D::CallMethod(const GPU::MethodCall& method_call) { | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | void Fermi2D::HandleSurfaceCopy() { | 31 | void Fermi2D::HandleSurfaceCopy() { |
| 32 | LOG_WARNING(HW_GPU, "Requested a surface copy with operation {}", | 32 | LOG_DEBUG(HW_GPU, "Requested a surface copy with operation {}", |
| 33 | static_cast<u32>(regs.operation)); | 33 | static_cast<u32>(regs.operation)); |
| 34 | 34 | ||
| 35 | // TODO(Subv): Only raw copies are implemented. | 35 | // TODO(Subv): Only raw copies are implemented. |
| 36 | ASSERT(regs.operation == Operation::SrcCopy); | 36 | ASSERT(regs.operation == Operation::SrcCopy); |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index fb3d1112c..b318aedb8 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -92,6 +92,10 @@ void Maxwell3D::InitializeRegisterDefaults() { | |||
| 92 | 92 | ||
| 93 | // Some games (like Super Mario Odyssey) assume that SRGB is enabled. | 93 | // Some games (like Super Mario Odyssey) assume that SRGB is enabled. |
| 94 | regs.framebuffer_srgb = 1; | 94 | regs.framebuffer_srgb = 1; |
| 95 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true; | ||
| 96 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true; | ||
| 97 | mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; | ||
| 98 | mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true; | ||
| 95 | } | 99 | } |
| 96 | 100 | ||
| 97 | #define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name)) | 101 | #define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name)) |
| @@ -256,6 +260,9 @@ void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u3 | |||
| 256 | 260 | ||
| 257 | // Execute the current macro. | 261 | // Execute the current macro. |
| 258 | macro_interpreter.Execute(macro_positions[entry], num_parameters, parameters); | 262 | macro_interpreter.Execute(macro_positions[entry], num_parameters, parameters); |
| 263 | if (mme_draw.current_mode != MMEDrawMode::Undefined) { | ||
| 264 | FlushMMEInlineDraw(); | ||
| 265 | } | ||
| 259 | } | 266 | } |
| 260 | 267 | ||
| 261 | void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { | 268 | void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { |
| @@ -416,6 +423,97 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { | |||
| 416 | } | 423 | } |
| 417 | } | 424 | } |
| 418 | 425 | ||
| 426 | void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) { | ||
| 427 | if (mme_draw.current_mode == MMEDrawMode::Undefined) { | ||
| 428 | if (mme_draw.gl_begin_consume) { | ||
| 429 | mme_draw.current_mode = expected_mode; | ||
| 430 | mme_draw.current_count = count; | ||
| 431 | mme_draw.instance_count = 1; | ||
| 432 | mme_draw.gl_begin_consume = false; | ||
| 433 | mme_draw.gl_end_count = 0; | ||
| 434 | } | ||
| 435 | return; | ||
| 436 | } else { | ||
| 437 | if (mme_draw.current_mode == expected_mode && count == mme_draw.current_count && | ||
| 438 | mme_draw.instance_mode && mme_draw.gl_begin_consume) { | ||
| 439 | mme_draw.instance_count++; | ||
| 440 | mme_draw.gl_begin_consume = false; | ||
| 441 | return; | ||
| 442 | } else { | ||
| 443 | FlushMMEInlineDraw(); | ||
| 444 | } | ||
| 445 | } | ||
| 446 | // Tail call in case it needs to retry. | ||
| 447 | StepInstance(expected_mode, count); | ||
| 448 | } | ||
| 449 | |||
| 450 | void Maxwell3D::CallMethodFromMME(const GPU::MethodCall& method_call) { | ||
| 451 | const u32 method = method_call.method; | ||
| 452 | if (mme_inline[method]) { | ||
| 453 | regs.reg_array[method] = method_call.argument; | ||
| 454 | if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count) || | ||
| 455 | method == MAXWELL3D_REG_INDEX(index_array.count)) { | ||
| 456 | const MMEDrawMode expected_mode = method == MAXWELL3D_REG_INDEX(vertex_buffer.count) | ||
| 457 | ? MMEDrawMode::Array | ||
| 458 | : MMEDrawMode::Indexed; | ||
| 459 | StepInstance(expected_mode, method_call.argument); | ||
| 460 | } else if (method == MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)) { | ||
| 461 | mme_draw.instance_mode = | ||
| 462 | (regs.draw.instance_next != 0) || (regs.draw.instance_cont != 0); | ||
| 463 | mme_draw.gl_begin_consume = true; | ||
| 464 | } else { | ||
| 465 | mme_draw.gl_end_count++; | ||
| 466 | } | ||
| 467 | } else { | ||
| 468 | if (mme_draw.current_mode != MMEDrawMode::Undefined) { | ||
| 469 | FlushMMEInlineDraw(); | ||
| 470 | } | ||
| 471 | CallMethod(method_call); | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | void Maxwell3D::FlushMMEInlineDraw() { | ||
| 476 | LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()), | ||
| 477 | regs.vertex_buffer.count); | ||
| 478 | ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?"); | ||
| 479 | ASSERT(mme_draw.instance_count == mme_draw.gl_end_count); | ||
| 480 | |||
| 481 | auto debug_context = system.GetGPUDebugContext(); | ||
| 482 | |||
| 483 | if (debug_context) { | ||
| 484 | debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr); | ||
| 485 | } | ||
| 486 | |||
| 487 | // Both instance configuration registers can not be set at the same time. | ||
| 488 | ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont, | ||
| 489 | "Illegal combination of instancing parameters"); | ||
| 490 | |||
| 491 | const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed; | ||
| 492 | if (ShouldExecute()) { | ||
| 493 | rasterizer.DrawMultiBatch(is_indexed); | ||
| 494 | } | ||
| 495 | |||
| 496 | if (debug_context) { | ||
| 497 | debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr); | ||
| 498 | } | ||
| 499 | |||
| 500 | // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if | ||
| 501 | // the game is trying to draw indexed or direct mode. This needs to be verified on HW still - | ||
| 502 | // it's possible that it is incorrect and that there is some other register used to specify the | ||
| 503 | // drawing mode. | ||
| 504 | if (is_indexed) { | ||
| 505 | regs.index_array.count = 0; | ||
| 506 | } else { | ||
| 507 | regs.vertex_buffer.count = 0; | ||
| 508 | } | ||
| 509 | mme_draw.current_mode = MMEDrawMode::Undefined; | ||
| 510 | mme_draw.current_count = 0; | ||
| 511 | mme_draw.instance_count = 0; | ||
| 512 | mme_draw.instance_mode = false; | ||
| 513 | mme_draw.gl_begin_consume = false; | ||
| 514 | mme_draw.gl_end_count = 0; | ||
| 515 | } | ||
| 516 | |||
| 419 | void Maxwell3D::ProcessMacroUpload(u32 data) { | 517 | void Maxwell3D::ProcessMacroUpload(u32 data) { |
| 420 | ASSERT_MSG(regs.macros.upload_address < macro_memory.size(), | 518 | ASSERT_MSG(regs.macros.upload_address < macro_memory.size(), |
| 421 | "upload_address exceeded macro_memory size!"); | 519 | "upload_address exceeded macro_memory size!"); |
| @@ -564,7 +662,9 @@ void Maxwell3D::DrawArrays() { | |||
| 564 | } | 662 | } |
| 565 | 663 | ||
| 566 | const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count}; | 664 | const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count}; |
| 567 | rasterizer.AccelerateDrawBatch(is_indexed); | 665 | if (ShouldExecute()) { |
| 666 | rasterizer.DrawBatch(is_indexed); | ||
| 667 | } | ||
| 568 | 668 | ||
| 569 | if (debug_context) { | 669 | if (debug_context) { |
| 570 | debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr); | 670 | debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr); |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index e5ec90717..4c97759ed 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -811,8 +811,9 @@ public: | |||
| 811 | INSERT_PADDING_WORDS(0x21); | 811 | INSERT_PADDING_WORDS(0x21); |
| 812 | 812 | ||
| 813 | u32 vb_element_base; | 813 | u32 vb_element_base; |
| 814 | u32 vb_base_instance; | ||
| 814 | 815 | ||
| 815 | INSERT_PADDING_WORDS(0x36); | 816 | INSERT_PADDING_WORDS(0x35); |
| 816 | 817 | ||
| 817 | union { | 818 | union { |
| 818 | BitField<0, 1, u32> c0; | 819 | BitField<0, 1, u32> c0; |
| @@ -1238,6 +1239,11 @@ public: | |||
| 1238 | /// Write the value to the register identified by method. | 1239 | /// Write the value to the register identified by method. |
| 1239 | void CallMethod(const GPU::MethodCall& method_call); | 1240 | void CallMethod(const GPU::MethodCall& method_call); |
| 1240 | 1241 | ||
| 1242 | /// Write the value to the register identified by method. | ||
| 1243 | void CallMethodFromMME(const GPU::MethodCall& method_call); | ||
| 1244 | |||
| 1245 | void FlushMMEInlineDraw(); | ||
| 1246 | |||
| 1241 | /// Given a Texture Handle, returns the TSC and TIC entries. | 1247 | /// Given a Texture Handle, returns the TSC and TIC entries. |
| 1242 | Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle, | 1248 | Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle, |
| 1243 | std::size_t offset) const; | 1249 | std::size_t offset) const; |
| @@ -1263,6 +1269,21 @@ public: | |||
| 1263 | return execute_on; | 1269 | return execute_on; |
| 1264 | } | 1270 | } |
| 1265 | 1271 | ||
| 1272 | enum class MMEDrawMode : u32 { | ||
| 1273 | Undefined, | ||
| 1274 | Array, | ||
| 1275 | Indexed, | ||
| 1276 | }; | ||
| 1277 | |||
| 1278 | struct MMEDrawState { | ||
| 1279 | MMEDrawMode current_mode{MMEDrawMode::Undefined}; | ||
| 1280 | u32 current_count{}; | ||
| 1281 | u32 instance_count{}; | ||
| 1282 | bool instance_mode{}; | ||
| 1283 | bool gl_begin_consume{}; | ||
| 1284 | u32 gl_end_count{}; | ||
| 1285 | } mme_draw; | ||
| 1286 | |||
| 1266 | private: | 1287 | private: |
| 1267 | void InitializeRegisterDefaults(); | 1288 | void InitializeRegisterDefaults(); |
| 1268 | 1289 | ||
| @@ -1275,6 +1296,8 @@ private: | |||
| 1275 | /// Start offsets of each macro in macro_memory | 1296 | /// Start offsets of each macro in macro_memory |
| 1276 | std::array<u32, 0x80> macro_positions = {}; | 1297 | std::array<u32, 0x80> macro_positions = {}; |
| 1277 | 1298 | ||
| 1299 | std::array<bool, Regs::NUM_REGS> mme_inline{}; | ||
| 1300 | |||
| 1278 | /// Memory for macro code | 1301 | /// Memory for macro code |
| 1279 | MacroMemory macro_memory; | 1302 | MacroMemory macro_memory; |
| 1280 | 1303 | ||
| @@ -1346,6 +1369,9 @@ private: | |||
| 1346 | 1369 | ||
| 1347 | /// Handles a write to the VERTEX_END_GL register, triggering a draw. | 1370 | /// Handles a write to the VERTEX_END_GL register, triggering a draw. |
| 1348 | void DrawArrays(); | 1371 | void DrawArrays(); |
| 1372 | |||
| 1373 | // Handles a instance drawcall from MME | ||
| 1374 | void StepInstance(MMEDrawMode expected_mode, u32 count); | ||
| 1349 | }; | 1375 | }; |
| 1350 | 1376 | ||
| 1351 | #define ASSERT_REG_POSITION(field_name, position) \ | 1377 | #define ASSERT_REG_POSITION(field_name, position) \ |
| @@ -1402,6 +1428,7 @@ ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); | |||
| 1402 | ASSERT_REG_POSITION(frag_color_clamp, 0x4EA); | 1428 | ASSERT_REG_POSITION(frag_color_clamp, 0x4EA); |
| 1403 | ASSERT_REG_POSITION(screen_y_control, 0x4EB); | 1429 | ASSERT_REG_POSITION(screen_y_control, 0x4EB); |
| 1404 | ASSERT_REG_POSITION(vb_element_base, 0x50D); | 1430 | ASSERT_REG_POSITION(vb_element_base, 0x50D); |
| 1431 | ASSERT_REG_POSITION(vb_base_instance, 0x50E); | ||
| 1405 | ASSERT_REG_POSITION(clip_distance_enabled, 0x544); | 1432 | ASSERT_REG_POSITION(clip_distance_enabled, 0x544); |
| 1406 | ASSERT_REG_POSITION(point_size, 0x546); | 1433 | ASSERT_REG_POSITION(point_size, 0x546); |
| 1407 | ASSERT_REG_POSITION(zeta_enable, 0x54E); | 1434 | ASSERT_REG_POSITION(zeta_enable, 0x54E); |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 28272ef6f..7a6355ce2 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -544,7 +544,7 @@ enum class VoteOperation : u64 { | |||
| 544 | Eq = 2, // allThreadsEqualNV | 544 | Eq = 2, // allThreadsEqualNV |
| 545 | }; | 545 | }; |
| 546 | 546 | ||
| 547 | enum class ImageAtomicSize : u64 { | 547 | enum class ImageAtomicOperationType : u64 { |
| 548 | U32 = 0, | 548 | U32 = 0, |
| 549 | S32 = 1, | 549 | S32 = 1, |
| 550 | U64 = 2, | 550 | U64 = 2, |
| @@ -1432,11 +1432,11 @@ union Instruction { | |||
| 1432 | ASSERT(mode == SurfaceDataMode::D_BA); | 1432 | ASSERT(mode == SurfaceDataMode::D_BA); |
| 1433 | return store_data_layout; | 1433 | return store_data_layout; |
| 1434 | } | 1434 | } |
| 1435 | } sust; | 1435 | } suldst; |
| 1436 | 1436 | ||
| 1437 | union { | 1437 | union { |
| 1438 | BitField<28, 1, u64> is_ba; | 1438 | BitField<28, 1, u64> is_ba; |
| 1439 | BitField<51, 3, ImageAtomicSize> size; | 1439 | BitField<51, 3, ImageAtomicOperationType> operation_type; |
| 1440 | BitField<33, 3, ImageType> image_type; | 1440 | BitField<33, 3, ImageType> image_type; |
| 1441 | BitField<29, 4, ImageAtomicOperation> operation; | 1441 | BitField<29, 4, ImageAtomicOperation> operation; |
| 1442 | BitField<49, 2, OutOfBoundsStore> out_of_bounds_store; | 1442 | BitField<49, 2, OutOfBoundsStore> out_of_bounds_store; |
| @@ -1595,6 +1595,7 @@ public: | |||
| 1595 | TMML_B, // Texture Mip Map Level | 1595 | TMML_B, // Texture Mip Map Level |
| 1596 | TMML, // Texture Mip Map Level | 1596 | TMML, // Texture Mip Map Level |
| 1597 | SUST, // Surface Store | 1597 | SUST, // Surface Store |
| 1598 | SULD, // Surface Load | ||
| 1598 | SUATOM, // Surface Atomic Operation | 1599 | SUATOM, // Surface Atomic Operation |
| 1599 | EXIT, | 1600 | EXIT, |
| 1600 | NOP, | 1601 | NOP, |
| @@ -1884,6 +1885,7 @@ private: | |||
| 1884 | INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"), | 1885 | INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"), |
| 1885 | INST("1101111101011---", Id::TMML, Type::Texture, "TMML"), | 1886 | INST("1101111101011---", Id::TMML, Type::Texture, "TMML"), |
| 1886 | INST("11101011001-----", Id::SUST, Type::Image, "SUST"), | 1887 | INST("11101011001-----", Id::SUST, Type::Image, "SUST"), |
| 1888 | INST("11101011000-----", Id::SULD, Type::Image, "SULD"), | ||
| 1887 | INST("1110101000------", Id::SUATOM, Type::Image, "SUATOM_D"), | 1889 | INST("1110101000------", Id::SUATOM, Type::Image, "SUATOM_D"), |
| 1888 | INST("0101000010110---", Id::NOP, Type::Trivial, "NOP"), | 1890 | INST("0101000010110---", Id::NOP, Type::Trivial, "NOP"), |
| 1889 | INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), | 1891 | INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 2c47541cb..76cfe8107 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -122,6 +122,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { | |||
| 122 | case RenderTargetFormat::RGBA16_UINT: | 122 | case RenderTargetFormat::RGBA16_UINT: |
| 123 | case RenderTargetFormat::RGBA16_UNORM: | 123 | case RenderTargetFormat::RGBA16_UNORM: |
| 124 | case RenderTargetFormat::RGBA16_FLOAT: | 124 | case RenderTargetFormat::RGBA16_FLOAT: |
| 125 | case RenderTargetFormat::RGBX16_FLOAT: | ||
| 125 | case RenderTargetFormat::RG32_FLOAT: | 126 | case RenderTargetFormat::RG32_FLOAT: |
| 126 | case RenderTargetFormat::RG32_UINT: | 127 | case RenderTargetFormat::RG32_UINT: |
| 127 | return 8; | 128 | return 8; |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 78bc0601a..29fa8e95b 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -42,6 +42,7 @@ enum class RenderTargetFormat : u32 { | |||
| 42 | RGBA16_FLOAT = 0xCA, | 42 | RGBA16_FLOAT = 0xCA, |
| 43 | RG32_FLOAT = 0xCB, | 43 | RG32_FLOAT = 0xCB, |
| 44 | RG32_UINT = 0xCD, | 44 | RG32_UINT = 0xCD, |
| 45 | RGBX16_FLOAT = 0xCE, | ||
| 45 | BGRA8_UNORM = 0xCF, | 46 | BGRA8_UNORM = 0xCF, |
| 46 | BGRA8_SRGB = 0xD0, | 47 | BGRA8_SRGB = 0xD0, |
| 47 | RGB10_A2_UNORM = 0xD1, | 48 | RGB10_A2_UNORM = 0xD1, |
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp index 62afc0d11..dbaeac6db 100644 --- a/src/video_core/macro_interpreter.cpp +++ b/src/video_core/macro_interpreter.cpp | |||
| @@ -257,7 +257,7 @@ void MacroInterpreter::SetMethodAddress(u32 address) { | |||
| 257 | } | 257 | } |
| 258 | 258 | ||
| 259 | void MacroInterpreter::Send(u32 value) { | 259 | void MacroInterpreter::Send(u32 value) { |
| 260 | maxwell3d.CallMethod({method_address.address, value}); | 260 | maxwell3d.CallMethodFromMME({method_address.address, value}); |
| 261 | // Increment the method address by the method increment. | 261 | // Increment the method address by the method increment. |
| 262 | method_address.address.Assign(method_address.address.Value() + | 262 | method_address.address.Assign(method_address.address.Value() + |
| 263 | method_address.increment.Value()); | 263 | method_address.increment.Value()); |
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp index 084f85e67..ab71870ab 100644 --- a/src/video_core/morton.cpp +++ b/src/video_core/morton.cpp | |||
| @@ -83,6 +83,7 @@ static constexpr ConversionArray morton_to_linear_fns = { | |||
| 83 | MortonCopy<true, PixelFormat::RG8U>, | 83 | MortonCopy<true, PixelFormat::RG8U>, |
| 84 | MortonCopy<true, PixelFormat::RG8S>, | 84 | MortonCopy<true, PixelFormat::RG8S>, |
| 85 | MortonCopy<true, PixelFormat::RG32UI>, | 85 | MortonCopy<true, PixelFormat::RG32UI>, |
| 86 | MortonCopy<true, PixelFormat::RGBX16F>, | ||
| 86 | MortonCopy<true, PixelFormat::R32UI>, | 87 | MortonCopy<true, PixelFormat::R32UI>, |
| 87 | MortonCopy<true, PixelFormat::ASTC_2D_8X8>, | 88 | MortonCopy<true, PixelFormat::ASTC_2D_8X8>, |
| 88 | MortonCopy<true, PixelFormat::ASTC_2D_8X5>, | 89 | MortonCopy<true, PixelFormat::ASTC_2D_8X5>, |
| @@ -151,6 +152,7 @@ static constexpr ConversionArray linear_to_morton_fns = { | |||
| 151 | MortonCopy<false, PixelFormat::RG8U>, | 152 | MortonCopy<false, PixelFormat::RG8U>, |
| 152 | MortonCopy<false, PixelFormat::RG8S>, | 153 | MortonCopy<false, PixelFormat::RG8S>, |
| 153 | MortonCopy<false, PixelFormat::RG32UI>, | 154 | MortonCopy<false, PixelFormat::RG32UI>, |
| 155 | MortonCopy<false, PixelFormat::RGBX16F>, | ||
| 154 | MortonCopy<false, PixelFormat::R32UI>, | 156 | MortonCopy<false, PixelFormat::R32UI>, |
| 155 | nullptr, | 157 | nullptr, |
| 156 | nullptr, | 158 | nullptr, |
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 6b3f2d50a..5b0eca9e2 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -29,7 +29,10 @@ public: | |||
| 29 | virtual ~RasterizerInterface() {} | 29 | virtual ~RasterizerInterface() {} |
| 30 | 30 | ||
| 31 | /// Draw the current batch of vertex arrays | 31 | /// Draw the current batch of vertex arrays |
| 32 | virtual void DrawArrays() = 0; | 32 | virtual bool DrawBatch(bool is_indexed) = 0; |
| 33 | |||
| 34 | /// Draw the current batch of multiple instances of vertex arrays | ||
| 35 | virtual bool DrawMultiBatch(bool is_indexed) = 0; | ||
| 33 | 36 | ||
| 34 | /// Clear the current framebuffer | 37 | /// Clear the current framebuffer |
| 35 | virtual void Clear() = 0; | 38 | virtual void Clear() = 0; |
| @@ -69,10 +72,6 @@ public: | |||
| 69 | return false; | 72 | return false; |
| 70 | } | 73 | } |
| 71 | 74 | ||
| 72 | virtual bool AccelerateDrawBatch(bool is_indexed) { | ||
| 73 | return false; | ||
| 74 | } | ||
| 75 | |||
| 76 | /// Increase/decrease the number of object in pages touching the specified region | 75 | /// Increase/decrease the number of object in pages touching the specified region |
| 77 | virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {} | 76 | virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {} |
| 78 | 77 | ||
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 4f59a87b4..64de7e425 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -2,8 +2,10 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 5 | #include <array> | 6 | #include <array> |
| 6 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <vector> | ||
| 7 | #include <glad/glad.h> | 9 | #include <glad/glad.h> |
| 8 | 10 | ||
| 9 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| @@ -30,9 +32,27 @@ bool TestProgram(const GLchar* glsl) { | |||
| 30 | return link_status == GL_TRUE; | 32 | return link_status == GL_TRUE; |
| 31 | } | 33 | } |
| 32 | 34 | ||
| 35 | std::vector<std::string_view> GetExtensions() { | ||
| 36 | GLint num_extensions; | ||
| 37 | glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); | ||
| 38 | std::vector<std::string_view> extensions; | ||
| 39 | extensions.reserve(num_extensions); | ||
| 40 | for (GLint index = 0; index < num_extensions; ++index) { | ||
| 41 | extensions.push_back( | ||
| 42 | reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(index)))); | ||
| 43 | } | ||
| 44 | return extensions; | ||
| 45 | } | ||
| 46 | |||
| 47 | bool HasExtension(const std::vector<std::string_view>& images, std::string_view extension) { | ||
| 48 | return std::find(images.begin(), images.end(), extension) != images.end(); | ||
| 49 | } | ||
| 50 | |||
| 33 | } // Anonymous namespace | 51 | } // Anonymous namespace |
| 34 | 52 | ||
| 35 | Device::Device() { | 53 | Device::Device() { |
| 54 | const std::vector extensions = GetExtensions(); | ||
| 55 | |||
| 36 | uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); | 56 | uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); |
| 37 | shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT); | 57 | shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT); |
| 38 | max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); | 58 | max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); |
| @@ -40,6 +60,7 @@ Device::Device() { | |||
| 40 | has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group && | 60 | has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group && |
| 41 | GLAD_GL_NV_shader_thread_shuffle; | 61 | GLAD_GL_NV_shader_thread_shuffle; |
| 42 | has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; | 62 | has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; |
| 63 | has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted"); | ||
| 43 | has_variable_aoffi = TestVariableAoffi(); | 64 | has_variable_aoffi = TestVariableAoffi(); |
| 44 | has_component_indexing_bug = TestComponentIndexingBug(); | 65 | has_component_indexing_bug = TestComponentIndexingBug(); |
| 45 | has_precise_bug = TestPreciseBug(); | 66 | has_precise_bug = TestPreciseBug(); |
| @@ -55,6 +76,7 @@ Device::Device(std::nullptr_t) { | |||
| 55 | max_varyings = 15; | 76 | max_varyings = 15; |
| 56 | has_warp_intrinsics = true; | 77 | has_warp_intrinsics = true; |
| 57 | has_vertex_viewport_layer = true; | 78 | has_vertex_viewport_layer = true; |
| 79 | has_image_load_formatted = true; | ||
| 58 | has_variable_aoffi = true; | 80 | has_variable_aoffi = true; |
| 59 | has_component_indexing_bug = false; | 81 | has_component_indexing_bug = false; |
| 60 | has_precise_bug = false; | 82 | has_precise_bug = false; |
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index ba6dcd3be..bb273c3d6 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h | |||
| @@ -38,6 +38,10 @@ public: | |||
| 38 | return has_vertex_viewport_layer; | 38 | return has_vertex_viewport_layer; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | bool HasImageLoadFormatted() const { | ||
| 42 | return has_image_load_formatted; | ||
| 43 | } | ||
| 44 | |||
| 41 | bool HasVariableAoffi() const { | 45 | bool HasVariableAoffi() const { |
| 42 | return has_variable_aoffi; | 46 | return has_variable_aoffi; |
| 43 | } | 47 | } |
| @@ -61,6 +65,7 @@ private: | |||
| 61 | u32 max_varyings{}; | 65 | u32 max_varyings{}; |
| 62 | bool has_warp_intrinsics{}; | 66 | bool has_warp_intrinsics{}; |
| 63 | bool has_vertex_viewport_layer{}; | 67 | bool has_vertex_viewport_layer{}; |
| 68 | bool has_image_load_formatted{}; | ||
| 64 | bool has_variable_aoffi{}; | 69 | bool has_variable_aoffi{}; |
| 65 | bool has_component_indexing_bug{}; | 70 | bool has_component_indexing_bug{}; |
| 66 | bool has_precise_bug{}; | 71 | bool has_precise_bug{}; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a2c1473db..6a17bed72 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -49,40 +49,6 @@ MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(128, 128, 192)); | |||
| 49 | MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); | 49 | MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); |
| 50 | MICROPROFILE_DEFINE(OpenGL_PrimitiveAssembly, "OpenGL", "Prim Asmbl", MP_RGB(255, 100, 100)); | 50 | MICROPROFILE_DEFINE(OpenGL_PrimitiveAssembly, "OpenGL", "Prim Asmbl", MP_RGB(255, 100, 100)); |
| 51 | 51 | ||
| 52 | struct DrawParameters { | ||
| 53 | GLenum primitive_mode; | ||
| 54 | GLsizei count; | ||
| 55 | GLint current_instance; | ||
| 56 | bool use_indexed; | ||
| 57 | |||
| 58 | GLint vertex_first; | ||
| 59 | |||
| 60 | GLenum index_format; | ||
| 61 | GLint base_vertex; | ||
| 62 | GLintptr index_buffer_offset; | ||
| 63 | |||
| 64 | void DispatchDraw() const { | ||
| 65 | if (use_indexed) { | ||
| 66 | const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset); | ||
| 67 | if (current_instance > 0) { | ||
| 68 | glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format, | ||
| 69 | index_buffer_ptr, 1, base_vertex, | ||
| 70 | current_instance); | ||
| 71 | } else { | ||
| 72 | glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr, | ||
| 73 | base_vertex); | ||
| 74 | } | ||
| 75 | } else { | ||
| 76 | if (current_instance > 0) { | ||
| 77 | glDrawArraysInstancedBaseInstance(primitive_mode, vertex_first, count, 1, | ||
| 78 | current_instance); | ||
| 79 | } else { | ||
| 80 | glDrawArrays(primitive_mode, vertex_first, count); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | |||
| 86 | static std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer, | 52 | static std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer, |
| 87 | const GLShader::ConstBufferEntry& entry) { | 53 | const GLShader::ConstBufferEntry& entry) { |
| 88 | if (!entry.IsIndirect()) { | 54 | if (!entry.IsIndirect()) { |
| @@ -270,29 +236,6 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer() { | |||
| 270 | return offset; | 236 | return offset; |
| 271 | } | 237 | } |
| 272 | 238 | ||
| 273 | DrawParameters RasterizerOpenGL::SetupDraw(GLintptr index_buffer_offset) { | ||
| 274 | const auto& gpu = system.GPU().Maxwell3D(); | ||
| 275 | const auto& regs = gpu.regs; | ||
| 276 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; | ||
| 277 | |||
| 278 | DrawParameters params{}; | ||
| 279 | params.current_instance = gpu.state.current_instance; | ||
| 280 | |||
| 281 | params.use_indexed = is_indexed; | ||
| 282 | params.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology); | ||
| 283 | |||
| 284 | if (is_indexed) { | ||
| 285 | params.index_format = MaxwellToGL::IndexFormat(regs.index_array.format); | ||
| 286 | params.count = regs.index_array.count; | ||
| 287 | params.index_buffer_offset = index_buffer_offset; | ||
| 288 | params.base_vertex = static_cast<GLint>(regs.vb_element_base); | ||
| 289 | } else { | ||
| 290 | params.count = regs.vertex_buffer.count; | ||
| 291 | params.vertex_first = regs.vertex_buffer.first; | ||
| 292 | } | ||
| 293 | return params; | ||
| 294 | } | ||
| 295 | |||
| 296 | void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | 239 | void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { |
| 297 | MICROPROFILE_SCOPE(OpenGL_Shader); | 240 | MICROPROFILE_SCOPE(OpenGL_Shader); |
| 298 | auto& gpu = system.GPU().Maxwell3D(); | 241 | auto& gpu = system.GPU().Maxwell3D(); |
| @@ -399,12 +342,6 @@ std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const { | |||
| 399 | static_cast<std::size_t>(regs.index_array.FormatSizeInBytes()); | 342 | static_cast<std::size_t>(regs.index_array.FormatSizeInBytes()); |
| 400 | } | 343 | } |
| 401 | 344 | ||
| 402 | bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { | ||
| 403 | accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; | ||
| 404 | DrawArrays(); | ||
| 405 | return true; | ||
| 406 | } | ||
| 407 | |||
| 408 | template <typename Map, typename Interval> | 345 | template <typename Map, typename Interval> |
| 409 | static constexpr auto RangeFromInterval(Map& map, const Interval& interval) { | 346 | static constexpr auto RangeFromInterval(Map& map, const Interval& interval) { |
| 410 | return boost::make_iterator_range(map.equal_range(interval)); | 347 | return boost::make_iterator_range(map.equal_range(interval)); |
| @@ -640,17 +577,9 @@ void RasterizerOpenGL::Clear() { | |||
| 640 | } | 577 | } |
| 641 | } | 578 | } |
| 642 | 579 | ||
| 643 | void RasterizerOpenGL::DrawArrays() { | 580 | void RasterizerOpenGL::DrawPrelude() { |
| 644 | if (accelerate_draw == AccelDraw::Disabled) | ||
| 645 | return; | ||
| 646 | |||
| 647 | MICROPROFILE_SCOPE(OpenGL_Drawing); | ||
| 648 | auto& gpu = system.GPU().Maxwell3D(); | 581 | auto& gpu = system.GPU().Maxwell3D(); |
| 649 | 582 | ||
| 650 | if (!gpu.ShouldExecute()) { | ||
| 651 | return; | ||
| 652 | } | ||
| 653 | |||
| 654 | SyncColorMask(); | 583 | SyncColorMask(); |
| 655 | SyncFragmentColorClampState(); | 584 | SyncFragmentColorClampState(); |
| 656 | SyncMultiSampleState(); | 585 | SyncMultiSampleState(); |
| @@ -695,10 +624,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 695 | // Upload vertex and index data. | 624 | // Upload vertex and index data. |
| 696 | SetupVertexBuffer(vao); | 625 | SetupVertexBuffer(vao); |
| 697 | SetupVertexInstances(vao); | 626 | SetupVertexInstances(vao); |
| 698 | const GLintptr index_buffer_offset = SetupIndexBuffer(); | 627 | index_buffer_offset = SetupIndexBuffer(); |
| 699 | |||
| 700 | // Setup draw parameters. It will automatically choose what glDraw* method to use. | ||
| 701 | const DrawParameters params = SetupDraw(index_buffer_offset); | ||
| 702 | 628 | ||
| 703 | // Prepare packed bindings. | 629 | // Prepare packed bindings. |
| 704 | bind_ubo_pushbuffer.Setup(0); | 630 | bind_ubo_pushbuffer.Setup(0); |
| @@ -706,7 +632,8 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 706 | 632 | ||
| 707 | // Setup shaders and their used resources. | 633 | // Setup shaders and their used resources. |
| 708 | texture_cache.GuardSamplers(true); | 634 | texture_cache.GuardSamplers(true); |
| 709 | SetupShaders(params.primitive_mode); | 635 | const auto primitive_mode = MaxwellToGL::PrimitiveTopology(gpu.regs.draw.topology); |
| 636 | SetupShaders(primitive_mode); | ||
| 710 | texture_cache.GuardSamplers(false); | 637 | texture_cache.GuardSamplers(false); |
| 711 | 638 | ||
| 712 | ConfigureFramebuffers(); | 639 | ConfigureFramebuffers(); |
| @@ -730,11 +657,107 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 730 | if (texture_cache.TextureBarrier()) { | 657 | if (texture_cache.TextureBarrier()) { |
| 731 | glTextureBarrier(); | 658 | glTextureBarrier(); |
| 732 | } | 659 | } |
| 660 | } | ||
| 661 | |||
| 662 | struct DrawParams { | ||
| 663 | bool is_indexed{}; | ||
| 664 | bool is_instanced{}; | ||
| 665 | GLenum primitive_mode{}; | ||
| 666 | GLint count{}; | ||
| 667 | GLint base_vertex{}; | ||
| 668 | |||
| 669 | // Indexed settings | ||
| 670 | GLenum index_format{}; | ||
| 671 | GLintptr index_buffer_offset{}; | ||
| 672 | |||
| 673 | // Instanced setting | ||
| 674 | GLint num_instances{}; | ||
| 675 | GLint base_instance{}; | ||
| 676 | |||
| 677 | void DispatchDraw() { | ||
| 678 | if (is_indexed) { | ||
| 679 | const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset); | ||
| 680 | if (is_instanced) { | ||
| 681 | glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format, | ||
| 682 | index_buffer_ptr, num_instances, | ||
| 683 | base_vertex, base_instance); | ||
| 684 | } else { | ||
| 685 | glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr, | ||
| 686 | base_vertex); | ||
| 687 | } | ||
| 688 | } else { | ||
| 689 | if (is_instanced) { | ||
| 690 | glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, count, num_instances, | ||
| 691 | base_instance); | ||
| 692 | } else { | ||
| 693 | glDrawArrays(primitive_mode, base_vertex, count); | ||
| 694 | } | ||
| 695 | } | ||
| 696 | } | ||
| 697 | }; | ||
| 733 | 698 | ||
| 734 | params.DispatchDraw(); | 699 | bool RasterizerOpenGL::DrawBatch(bool is_indexed) { |
| 700 | accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; | ||
| 701 | |||
| 702 | MICROPROFILE_SCOPE(OpenGL_Drawing); | ||
| 735 | 703 | ||
| 704 | DrawPrelude(); | ||
| 705 | |||
| 706 | auto& maxwell3d = system.GPU().Maxwell3D(); | ||
| 707 | const auto& regs = maxwell3d.regs; | ||
| 708 | const auto current_instance = maxwell3d.state.current_instance; | ||
| 709 | DrawParams draw_call{}; | ||
| 710 | draw_call.is_indexed = is_indexed; | ||
| 711 | draw_call.num_instances = static_cast<GLint>(1); | ||
| 712 | draw_call.base_instance = static_cast<GLint>(current_instance); | ||
| 713 | draw_call.is_instanced = current_instance > 0; | ||
| 714 | draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology); | ||
| 715 | if (draw_call.is_indexed) { | ||
| 716 | draw_call.count = static_cast<GLint>(regs.index_array.count); | ||
| 717 | draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base); | ||
| 718 | draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format); | ||
| 719 | draw_call.index_buffer_offset = index_buffer_offset; | ||
| 720 | } else { | ||
| 721 | draw_call.count = static_cast<GLint>(regs.vertex_buffer.count); | ||
| 722 | draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first); | ||
| 723 | } | ||
| 724 | draw_call.DispatchDraw(); | ||
| 725 | |||
| 726 | maxwell3d.dirty.memory_general = false; | ||
| 736 | accelerate_draw = AccelDraw::Disabled; | 727 | accelerate_draw = AccelDraw::Disabled; |
| 737 | gpu.dirty.memory_general = false; | 728 | return true; |
| 729 | } | ||
| 730 | |||
| 731 | bool RasterizerOpenGL::DrawMultiBatch(bool is_indexed) { | ||
| 732 | accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; | ||
| 733 | |||
| 734 | MICROPROFILE_SCOPE(OpenGL_Drawing); | ||
| 735 | |||
| 736 | DrawPrelude(); | ||
| 737 | |||
| 738 | auto& maxwell3d = system.GPU().Maxwell3D(); | ||
| 739 | const auto& regs = maxwell3d.regs; | ||
| 740 | const auto& draw_setup = maxwell3d.mme_draw; | ||
| 741 | DrawParams draw_call{}; | ||
| 742 | draw_call.is_indexed = is_indexed; | ||
| 743 | draw_call.num_instances = static_cast<GLint>(draw_setup.instance_count); | ||
| 744 | draw_call.base_instance = static_cast<GLint>(regs.vb_base_instance); | ||
| 745 | draw_call.is_instanced = draw_setup.instance_count > 1; | ||
| 746 | draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology); | ||
| 747 | if (draw_call.is_indexed) { | ||
| 748 | draw_call.count = static_cast<GLint>(regs.index_array.count); | ||
| 749 | draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base); | ||
| 750 | draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format); | ||
| 751 | draw_call.index_buffer_offset = index_buffer_offset; | ||
| 752 | } else { | ||
| 753 | draw_call.count = static_cast<GLint>(regs.vertex_buffer.count); | ||
| 754 | draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first); | ||
| 755 | } | ||
| 756 | draw_call.DispatchDraw(); | ||
| 757 | |||
| 758 | maxwell3d.dirty.memory_general = false; | ||
| 759 | accelerate_draw = AccelDraw::Disabled; | ||
| 760 | return true; | ||
| 738 | } | 761 | } |
| 739 | 762 | ||
| 740 | void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { | 763 | void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 4f5c7f864..9c10ebda3 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -57,7 +57,8 @@ public: | |||
| 57 | ScreenInfo& info); | 57 | ScreenInfo& info); |
| 58 | ~RasterizerOpenGL() override; | 58 | ~RasterizerOpenGL() override; |
| 59 | 59 | ||
| 60 | void DrawArrays() override; | 60 | bool DrawBatch(bool is_indexed) override; |
| 61 | bool DrawMultiBatch(bool is_indexed) override; | ||
| 61 | void Clear() override; | 62 | void Clear() override; |
| 62 | void DispatchCompute(GPUVAddr code_addr) override; | 63 | void DispatchCompute(GPUVAddr code_addr) override; |
| 63 | void FlushAll() override; | 64 | void FlushAll() override; |
| @@ -71,7 +72,6 @@ public: | |||
| 71 | const Tegra::Engines::Fermi2D::Config& copy_config) override; | 72 | const Tegra::Engines::Fermi2D::Config& copy_config) override; |
| 72 | bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, | 73 | bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, |
| 73 | u32 pixel_stride) override; | 74 | u32 pixel_stride) override; |
| 74 | bool AccelerateDrawBatch(bool is_indexed) override; | ||
| 75 | void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override; | 75 | void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override; |
| 76 | void LoadDiskResources(const std::atomic_bool& stop_loading, | 76 | void LoadDiskResources(const std::atomic_bool& stop_loading, |
| 77 | const VideoCore::DiskResourceLoadCallback& callback) override; | 77 | const VideoCore::DiskResourceLoadCallback& callback) override; |
| @@ -105,6 +105,9 @@ private: | |||
| 105 | void SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entry, GPUVAddr gpu_addr, | 105 | void SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entry, GPUVAddr gpu_addr, |
| 106 | std::size_t size); | 106 | std::size_t size); |
| 107 | 107 | ||
| 108 | /// Syncs all the state, shaders, render targets and textures setting before a draw call. | ||
| 109 | void DrawPrelude(); | ||
| 110 | |||
| 108 | /// Configures the current textures to use for the draw command. Returns shaders texture buffer | 111 | /// Configures the current textures to use for the draw command. Returns shaders texture buffer |
| 109 | /// usage. | 112 | /// usage. |
| 110 | TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, | 113 | TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, |
| @@ -216,7 +219,7 @@ private: | |||
| 216 | 219 | ||
| 217 | GLintptr SetupIndexBuffer(); | 220 | GLintptr SetupIndexBuffer(); |
| 218 | 221 | ||
| 219 | DrawParameters SetupDraw(GLintptr index_buffer_offset); | 222 | GLintptr index_buffer_offset; |
| 220 | 223 | ||
| 221 | void SetupShaders(GLenum primitive_mode); | 224 | void SetupShaders(GLenum primitive_mode); |
| 222 | 225 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 0dbc4c02f..42ca3b1bd 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -211,14 +211,14 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn | |||
| 211 | const auto primitive_mode{variant.primitive_mode}; | 211 | const auto primitive_mode{variant.primitive_mode}; |
| 212 | const auto texture_buffer_usage{variant.texture_buffer_usage}; | 212 | const auto texture_buffer_usage{variant.texture_buffer_usage}; |
| 213 | 213 | ||
| 214 | std::string source = "#version 430 core\n" | 214 | std::string source = R"(#version 430 core |
| 215 | "#extension GL_ARB_separate_shader_objects : enable\n" | 215 | #extension GL_ARB_separate_shader_objects : enable |
| 216 | "#extension GL_NV_gpu_shader5 : enable\n" | 216 | #extension GL_ARB_shader_viewport_layer_array : enable |
| 217 | "#extension GL_NV_shader_thread_group : enable\n" | 217 | #extension GL_EXT_shader_image_load_formatted : enable |
| 218 | "#extension GL_NV_shader_thread_shuffle : enable\n"; | 218 | #extension GL_NV_gpu_shader5 : enable |
| 219 | if (entries.shader_viewport_layer_array) { | 219 | #extension GL_NV_shader_thread_group : enable |
| 220 | source += "#extension GL_ARB_shader_viewport_layer_array : enable\n"; | 220 | #extension GL_NV_shader_thread_shuffle : enable |
| 221 | } | 221 | )"; |
| 222 | if (program_type == ProgramType::Compute) { | 222 | if (program_type == ProgramType::Compute) { |
| 223 | source += "#extension GL_ARB_compute_variable_group_size : require\n"; | 223 | source += "#extension GL_ARB_compute_variable_group_size : require\n"; |
| 224 | } | 224 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 76439e7ab..8fa9e6534 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include "video_core/renderer_opengl/gl_device.h" | 19 | #include "video_core/renderer_opengl/gl_device.h" |
| 20 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 20 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 21 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" | 21 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" |
| 22 | #include "video_core/shader/node.h" | ||
| 22 | #include "video_core/shader/shader_ir.h" | 23 | #include "video_core/shader/shader_ir.h" |
| 23 | 24 | ||
| 24 | namespace OpenGL::GLShader { | 25 | namespace OpenGL::GLShader { |
| @@ -241,6 +242,26 @@ constexpr const char* GetTypeString(Type type) { | |||
| 241 | } | 242 | } |
| 242 | } | 243 | } |
| 243 | 244 | ||
| 245 | constexpr const char* GetImageTypeDeclaration(Tegra::Shader::ImageType image_type) { | ||
| 246 | switch (image_type) { | ||
| 247 | case Tegra::Shader::ImageType::Texture1D: | ||
| 248 | return "1D"; | ||
| 249 | case Tegra::Shader::ImageType::TextureBuffer: | ||
| 250 | return "Buffer"; | ||
| 251 | case Tegra::Shader::ImageType::Texture1DArray: | ||
| 252 | return "1DArray"; | ||
| 253 | case Tegra::Shader::ImageType::Texture2D: | ||
| 254 | return "2D"; | ||
| 255 | case Tegra::Shader::ImageType::Texture2DArray: | ||
| 256 | return "2DArray"; | ||
| 257 | case Tegra::Shader::ImageType::Texture3D: | ||
| 258 | return "3D"; | ||
| 259 | default: | ||
| 260 | UNREACHABLE(); | ||
| 261 | return "1D"; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 244 | /// Generates code to use for a swizzle operation. | 265 | /// Generates code to use for a swizzle operation. |
| 245 | constexpr const char* GetSwizzle(u32 element) { | 266 | constexpr const char* GetSwizzle(u32 element) { |
| 246 | constexpr std::array swizzle = {".x", ".y", ".z", ".w"}; | 267 | constexpr std::array swizzle = {".x", ".y", ".z", ".w"}; |
| @@ -398,8 +419,6 @@ public: | |||
| 398 | usage.is_read, usage.is_written); | 419 | usage.is_read, usage.is_written); |
| 399 | } | 420 | } |
| 400 | entries.clip_distances = ir.GetClipDistances(); | 421 | entries.clip_distances = ir.GetClipDistances(); |
| 401 | entries.shader_viewport_layer_array = | ||
| 402 | IsVertexShader(stage) && (ir.UsesLayer() || ir.UsesViewportIndex()); | ||
| 403 | entries.shader_length = ir.GetLength(); | 422 | entries.shader_length = ir.GetLength(); |
| 404 | return entries; | 423 | return entries; |
| 405 | } | 424 | } |
| @@ -462,6 +481,14 @@ private: | |||
| 462 | code.AddLine("float gl_PointSize;"); | 481 | code.AddLine("float gl_PointSize;"); |
| 463 | } | 482 | } |
| 464 | 483 | ||
| 484 | if (ir.UsesInstanceId()) { | ||
| 485 | code.AddLine("int gl_InstanceID;"); | ||
| 486 | } | ||
| 487 | |||
| 488 | if (ir.UsesVertexId()) { | ||
| 489 | code.AddLine("int gl_VertexID;"); | ||
| 490 | } | ||
| 491 | |||
| 465 | --code.scope; | 492 | --code.scope; |
| 466 | code.AddLine("}};"); | 493 | code.AddLine("}};"); |
| 467 | code.AddNewLine(); | 494 | code.AddNewLine(); |
| @@ -714,42 +741,6 @@ private: | |||
| 714 | void DeclareImages() { | 741 | void DeclareImages() { |
| 715 | const auto& images{ir.GetImages()}; | 742 | const auto& images{ir.GetImages()}; |
| 716 | for (const auto& [offset, image] : images) { | 743 | for (const auto& [offset, image] : images) { |
| 717 | const char* image_type = [&] { | ||
| 718 | switch (image.GetType()) { | ||
| 719 | case Tegra::Shader::ImageType::Texture1D: | ||
| 720 | return "image1D"; | ||
| 721 | case Tegra::Shader::ImageType::TextureBuffer: | ||
| 722 | return "imageBuffer"; | ||
| 723 | case Tegra::Shader::ImageType::Texture1DArray: | ||
| 724 | return "image1DArray"; | ||
| 725 | case Tegra::Shader::ImageType::Texture2D: | ||
| 726 | return "image2D"; | ||
| 727 | case Tegra::Shader::ImageType::Texture2DArray: | ||
| 728 | return "image2DArray"; | ||
| 729 | case Tegra::Shader::ImageType::Texture3D: | ||
| 730 | return "image3D"; | ||
| 731 | default: | ||
| 732 | UNREACHABLE(); | ||
| 733 | return "image1D"; | ||
| 734 | } | ||
| 735 | }(); | ||
| 736 | |||
| 737 | const auto [type_prefix, format] = [&]() -> std::pair<const char*, const char*> { | ||
| 738 | if (!image.IsSizeKnown()) { | ||
| 739 | return {"", ""}; | ||
| 740 | } | ||
| 741 | switch (image.GetSize()) { | ||
| 742 | case Tegra::Shader::ImageAtomicSize::U32: | ||
| 743 | return {"u", "r32ui, "}; | ||
| 744 | case Tegra::Shader::ImageAtomicSize::S32: | ||
| 745 | return {"i", "r32i, "}; | ||
| 746 | default: | ||
| 747 | UNIMPLEMENTED_MSG("Unimplemented atomic size={}", | ||
| 748 | static_cast<u32>(image.GetSize())); | ||
| 749 | return {"", ""}; | ||
| 750 | } | ||
| 751 | }(); | ||
| 752 | |||
| 753 | std::string qualifier = "coherent volatile"; | 744 | std::string qualifier = "coherent volatile"; |
| 754 | if (image.IsRead() && !image.IsWritten()) { | 745 | if (image.IsRead() && !image.IsWritten()) { |
| 755 | qualifier += " readonly"; | 746 | qualifier += " readonly"; |
| @@ -757,9 +748,10 @@ private: | |||
| 757 | qualifier += " writeonly"; | 748 | qualifier += " writeonly"; |
| 758 | } | 749 | } |
| 759 | 750 | ||
| 760 | code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform " | 751 | const char* format = image.IsAtomic() ? "r32ui, " : ""; |
| 761 | "{} {};", | 752 | const char* type_declaration = GetImageTypeDeclaration(image.GetType()); |
| 762 | image.GetIndex(), qualifier, image_type, GetImage(image)); | 753 | code.AddLine("layout ({}binding = IMAGE_BINDING_{}) {} uniform uimage{} {};", format, |
| 754 | image.GetIndex(), qualifier, type_declaration, GetImage(image)); | ||
| 763 | } | 755 | } |
| 764 | if (!images.empty()) { | 756 | if (!images.empty()) { |
| 765 | code.AddNewLine(); | 757 | code.AddNewLine(); |
| @@ -964,7 +956,7 @@ private: | |||
| 964 | switch (element) { | 956 | switch (element) { |
| 965 | case 2: | 957 | case 2: |
| 966 | // Config pack's first value is instance_id. | 958 | // Config pack's first value is instance_id. |
| 967 | return {"config_pack[0]", Type::Uint}; | 959 | return {"gl_InstanceID", Type::Int}; |
| 968 | case 3: | 960 | case 3: |
| 969 | return {"gl_VertexID", Type::Int}; | 961 | return {"gl_VertexID", Type::Int}; |
| 970 | } | 962 | } |
| @@ -1226,28 +1218,13 @@ private: | |||
| 1226 | } | 1218 | } |
| 1227 | 1219 | ||
| 1228 | std::string BuildImageValues(Operation operation) { | 1220 | std::string BuildImageValues(Operation operation) { |
| 1221 | constexpr std::array constructors{"uint", "uvec2", "uvec3", "uvec4"}; | ||
| 1229 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; | 1222 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
| 1230 | const auto [constructors, type] = [&]() -> std::pair<std::array<const char*, 4>, Type> { | ||
| 1231 | constexpr std::array float_constructors{"float", "vec2", "vec3", "vec4"}; | ||
| 1232 | if (!meta.image.IsSizeKnown()) { | ||
| 1233 | return {float_constructors, Type::Float}; | ||
| 1234 | } | ||
| 1235 | switch (meta.image.GetSize()) { | ||
| 1236 | case Tegra::Shader::ImageAtomicSize::U32: | ||
| 1237 | return {{"uint", "uvec2", "uvec3", "uvec4"}, Type::Uint}; | ||
| 1238 | case Tegra::Shader::ImageAtomicSize::S32: | ||
| 1239 | return {{"int", "ivec2", "ivec3", "ivec4"}, Type::Uint}; | ||
| 1240 | default: | ||
| 1241 | UNIMPLEMENTED_MSG("Unimplemented image size={}", | ||
| 1242 | static_cast<u32>(meta.image.GetSize())); | ||
| 1243 | return {float_constructors, Type::Float}; | ||
| 1244 | } | ||
| 1245 | }(); | ||
| 1246 | 1223 | ||
| 1247 | const std::size_t values_count{meta.values.size()}; | 1224 | const std::size_t values_count{meta.values.size()}; |
| 1248 | std::string expr = fmt::format("{}(", constructors.at(values_count - 1)); | 1225 | std::string expr = fmt::format("{}(", constructors.at(values_count - 1)); |
| 1249 | for (std::size_t i = 0; i < values_count; ++i) { | 1226 | for (std::size_t i = 0; i < values_count; ++i) { |
| 1250 | expr += Visit(meta.values.at(i)).As(type); | 1227 | expr += Visit(meta.values.at(i)).AsUint(); |
| 1251 | if (i + 1 < values_count) { | 1228 | if (i + 1 < values_count) { |
| 1252 | expr += ", "; | 1229 | expr += ", "; |
| 1253 | } | 1230 | } |
| @@ -1256,29 +1233,6 @@ private: | |||
| 1256 | return expr; | 1233 | return expr; |
| 1257 | } | 1234 | } |
| 1258 | 1235 | ||
| 1259 | Expression AtomicImage(Operation operation, const char* opname) { | ||
| 1260 | constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("}; | ||
| 1261 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; | ||
| 1262 | ASSERT(meta.values.size() == 1); | ||
| 1263 | ASSERT(meta.image.IsSizeKnown()); | ||
| 1264 | |||
| 1265 | const auto type = [&]() { | ||
| 1266 | switch (const auto size = meta.image.GetSize()) { | ||
| 1267 | case Tegra::Shader::ImageAtomicSize::U32: | ||
| 1268 | return Type::Uint; | ||
| 1269 | case Tegra::Shader::ImageAtomicSize::S32: | ||
| 1270 | return Type::Int; | ||
| 1271 | default: | ||
| 1272 | UNIMPLEMENTED_MSG("Unimplemented image size={}", static_cast<u32>(size)); | ||
| 1273 | return Type::Uint; | ||
| 1274 | } | ||
| 1275 | }(); | ||
| 1276 | |||
| 1277 | return {fmt::format("{}({}, {}, {})", opname, GetImage(meta.image), | ||
| 1278 | BuildIntegerCoordinates(operation), Visit(meta.values[0]).As(type)), | ||
| 1279 | type}; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | Expression Assign(Operation operation) { | 1236 | Expression Assign(Operation operation) { |
| 1283 | const Node& dest = operation[0]; | 1237 | const Node& dest = operation[0]; |
| 1284 | const Node& src = operation[1]; | 1238 | const Node& src = operation[1]; |
| @@ -1537,6 +1491,8 @@ private: | |||
| 1537 | case Tegra::Shader::HalfType::H1_H1: | 1491 | case Tegra::Shader::HalfType::H1_H1: |
| 1538 | return {fmt::format("vec2({}[1])", operand.AsHalfFloat()), Type::HalfFloat}; | 1492 | return {fmt::format("vec2({}[1])", operand.AsHalfFloat()), Type::HalfFloat}; |
| 1539 | } | 1493 | } |
| 1494 | UNREACHABLE(); | ||
| 1495 | return {"0", Type::Int}; | ||
| 1540 | } | 1496 | } |
| 1541 | 1497 | ||
| 1542 | Expression HMergeF32(Operation operation) { | 1498 | Expression HMergeF32(Operation operation) { |
| @@ -1801,6 +1757,19 @@ private: | |||
| 1801 | return {tmp, Type::Float}; | 1757 | return {tmp, Type::Float}; |
| 1802 | } | 1758 | } |
| 1803 | 1759 | ||
| 1760 | Expression ImageLoad(Operation operation) { | ||
| 1761 | if (!device.HasImageLoadFormatted()) { | ||
| 1762 | LOG_ERROR(Render_OpenGL, | ||
| 1763 | "Device lacks GL_EXT_shader_image_load_formatted, stubbing image load"); | ||
| 1764 | return {"0", Type::Int}; | ||
| 1765 | } | ||
| 1766 | |||
| 1767 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; | ||
| 1768 | return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image), | ||
| 1769 | BuildIntegerCoordinates(operation), GetSwizzle(meta.element)), | ||
| 1770 | Type::Uint}; | ||
| 1771 | } | ||
| 1772 | |||
| 1804 | Expression ImageStore(Operation operation) { | 1773 | Expression ImageStore(Operation operation) { |
| 1805 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; | 1774 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
| 1806 | code.AddLine("imageStore({}, {}, {});", GetImage(meta.image), | 1775 | code.AddLine("imageStore({}, {}, {});", GetImage(meta.image), |
| @@ -1808,31 +1777,14 @@ private: | |||
| 1808 | return {}; | 1777 | return {}; |
| 1809 | } | 1778 | } |
| 1810 | 1779 | ||
| 1811 | Expression AtomicImageAdd(Operation operation) { | 1780 | template <const std::string_view& opname> |
| 1812 | return AtomicImage(operation, "imageAtomicAdd"); | 1781 | Expression AtomicImage(Operation operation) { |
| 1813 | } | 1782 | const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
| 1814 | 1783 | ASSERT(meta.values.size() == 1); | |
| 1815 | Expression AtomicImageMin(Operation operation) { | ||
| 1816 | return AtomicImage(operation, "imageAtomicMin"); | ||
| 1817 | } | ||
| 1818 | |||
| 1819 | Expression AtomicImageMax(Operation operation) { | ||
| 1820 | return AtomicImage(operation, "imageAtomicMax"); | ||
| 1821 | } | ||
| 1822 | Expression AtomicImageAnd(Operation operation) { | ||
| 1823 | return AtomicImage(operation, "imageAtomicAnd"); | ||
| 1824 | } | ||
| 1825 | |||
| 1826 | Expression AtomicImageOr(Operation operation) { | ||
| 1827 | return AtomicImage(operation, "imageAtomicOr"); | ||
| 1828 | } | ||
| 1829 | |||
| 1830 | Expression AtomicImageXor(Operation operation) { | ||
| 1831 | return AtomicImage(operation, "imageAtomicXor"); | ||
| 1832 | } | ||
| 1833 | 1784 | ||
| 1834 | Expression AtomicImageExchange(Operation operation) { | 1785 | return {fmt::format("imageAtomic{}({}, {}, {})", opname, GetImage(meta.image), |
| 1835 | return AtomicImage(operation, "imageAtomicExchange"); | 1786 | BuildIntegerCoordinates(operation), Visit(meta.values[0]).AsUint()), |
| 1787 | Type::Uint}; | ||
| 1836 | } | 1788 | } |
| 1837 | 1789 | ||
| 1838 | Expression Branch(Operation operation) { | 1790 | Expression Branch(Operation operation) { |
| @@ -2027,6 +1979,12 @@ private: | |||
| 2027 | Func() = delete; | 1979 | Func() = delete; |
| 2028 | ~Func() = delete; | 1980 | ~Func() = delete; |
| 2029 | 1981 | ||
| 1982 | static constexpr std::string_view Add = "Add"; | ||
| 1983 | static constexpr std::string_view And = "And"; | ||
| 1984 | static constexpr std::string_view Or = "Or"; | ||
| 1985 | static constexpr std::string_view Xor = "Xor"; | ||
| 1986 | static constexpr std::string_view Exchange = "Exchange"; | ||
| 1987 | |||
| 2030 | static constexpr std::string_view ShuffleIndexed = "shuffleNV"; | 1988 | static constexpr std::string_view ShuffleIndexed = "shuffleNV"; |
| 2031 | static constexpr std::string_view ShuffleUp = "shuffleUpNV"; | 1989 | static constexpr std::string_view ShuffleUp = "shuffleUpNV"; |
| 2032 | static constexpr std::string_view ShuffleDown = "shuffleDownNV"; | 1990 | static constexpr std::string_view ShuffleDown = "shuffleDownNV"; |
| @@ -2164,14 +2122,14 @@ private: | |||
| 2164 | &GLSLDecompiler::TextureQueryLod, | 2122 | &GLSLDecompiler::TextureQueryLod, |
| 2165 | &GLSLDecompiler::TexelFetch, | 2123 | &GLSLDecompiler::TexelFetch, |
| 2166 | 2124 | ||
| 2125 | &GLSLDecompiler::ImageLoad, | ||
| 2167 | &GLSLDecompiler::ImageStore, | 2126 | &GLSLDecompiler::ImageStore, |
| 2168 | &GLSLDecompiler::AtomicImageAdd, | 2127 | |
| 2169 | &GLSLDecompiler::AtomicImageMin, | 2128 | &GLSLDecompiler::AtomicImage<Func::Add>, |
| 2170 | &GLSLDecompiler::AtomicImageMax, | 2129 | &GLSLDecompiler::AtomicImage<Func::And>, |
| 2171 | &GLSLDecompiler::AtomicImageAnd, | 2130 | &GLSLDecompiler::AtomicImage<Func::Or>, |
| 2172 | &GLSLDecompiler::AtomicImageOr, | 2131 | &GLSLDecompiler::AtomicImage<Func::Xor>, |
| 2173 | &GLSLDecompiler::AtomicImageXor, | 2132 | &GLSLDecompiler::AtomicImage<Func::Exchange>, |
| 2174 | &GLSLDecompiler::AtomicImageExchange, | ||
| 2175 | 2133 | ||
| 2176 | &GLSLDecompiler::Branch, | 2134 | &GLSLDecompiler::Branch, |
| 2177 | &GLSLDecompiler::BranchIndirect, | 2135 | &GLSLDecompiler::BranchIndirect, |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index 2ea02f5bf..e538dc001 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h | |||
| @@ -90,7 +90,6 @@ struct ShaderEntries { | |||
| 90 | std::vector<ImageEntry> images; | 90 | std::vector<ImageEntry> images; |
| 91 | std::vector<GlobalMemoryEntry> global_memory_entries; | 91 | std::vector<GlobalMemoryEntry> global_memory_entries; |
| 92 | std::array<bool, Maxwell::NumClipDistances> clip_distances{}; | 92 | std::array<bool, Maxwell::NumClipDistances> clip_distances{}; |
| 93 | bool shader_viewport_layer_array{}; | ||
| 94 | std::size_t shader_length{}; | 93 | std::size_t shader_length{}; |
| 95 | }; | 94 | }; |
| 96 | 95 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index f141c4e3b..6a7012b54 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | |||
| @@ -343,20 +343,17 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | |||
| 343 | u8 is_bindless{}; | 343 | u8 is_bindless{}; |
| 344 | u8 is_written{}; | 344 | u8 is_written{}; |
| 345 | u8 is_read{}; | 345 | u8 is_read{}; |
| 346 | u8 is_size_known{}; | 346 | u8 is_atomic{}; |
| 347 | u32 size{}; | ||
| 348 | if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || | 347 | if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || |
| 349 | !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) || | 348 | !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) || |
| 350 | !LoadObjectFromPrecompiled(is_written) || !LoadObjectFromPrecompiled(is_read) || | 349 | !LoadObjectFromPrecompiled(is_written) || !LoadObjectFromPrecompiled(is_read) || |
| 351 | !LoadObjectFromPrecompiled(is_size_known) || !LoadObjectFromPrecompiled(size)) { | 350 | !LoadObjectFromPrecompiled(is_atomic)) { |
| 352 | return {}; | 351 | return {}; |
| 353 | } | 352 | } |
| 354 | entry.entries.images.emplace_back( | 353 | entry.entries.images.emplace_back( |
| 355 | static_cast<std::size_t>(offset), static_cast<std::size_t>(index), | 354 | static_cast<std::size_t>(offset), static_cast<std::size_t>(index), |
| 356 | static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0, is_written != 0, | 355 | static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0, is_written != 0, |
| 357 | is_read != 0, | 356 | is_read != 0, is_atomic != 0); |
| 358 | is_size_known ? std::make_optional(static_cast<Tegra::Shader::ImageAtomicSize>(size)) | ||
| 359 | : std::nullopt); | ||
| 360 | } | 357 | } |
| 361 | 358 | ||
| 362 | u32 global_memory_count{}; | 359 | u32 global_memory_count{}; |
| @@ -382,12 +379,6 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | |||
| 382 | } | 379 | } |
| 383 | } | 380 | } |
| 384 | 381 | ||
| 385 | bool shader_viewport_layer_array{}; | ||
| 386 | if (!LoadObjectFromPrecompiled(shader_viewport_layer_array)) { | ||
| 387 | return {}; | ||
| 388 | } | ||
| 389 | entry.entries.shader_viewport_layer_array = shader_viewport_layer_array; | ||
| 390 | |||
| 391 | u64 shader_length{}; | 382 | u64 shader_length{}; |
| 392 | if (!LoadObjectFromPrecompiled(shader_length)) { | 383 | if (!LoadObjectFromPrecompiled(shader_length)) { |
| 393 | return {}; | 384 | return {}; |
| @@ -435,14 +426,13 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: | |||
| 435 | return false; | 426 | return false; |
| 436 | } | 427 | } |
| 437 | for (const auto& image : entries.images) { | 428 | for (const auto& image : entries.images) { |
| 438 | const u32 size = image.IsSizeKnown() ? static_cast<u32>(image.GetSize()) : 0U; | ||
| 439 | if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) || | 429 | if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) || |
| 440 | !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) || | 430 | !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) || |
| 441 | !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) || | 431 | !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) || |
| 442 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) || | 432 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) || |
| 443 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0)) || | 433 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0)) || |
| 444 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) || | 434 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) || |
| 445 | !SaveObjectToPrecompiled(image.IsSizeKnown()) || !SaveObjectToPrecompiled(size)) { | 435 | !SaveObjectToPrecompiled(static_cast<u8>(image.IsAtomic() ? 1 : 0))) { |
| 446 | return false; | 436 | return false; |
| 447 | } | 437 | } |
| 448 | } | 438 | } |
| @@ -464,10 +454,6 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: | |||
| 464 | } | 454 | } |
| 465 | } | 455 | } |
| 466 | 456 | ||
| 467 | if (!SaveObjectToPrecompiled(entries.shader_viewport_layer_array)) { | ||
| 468 | return false; | ||
| 469 | } | ||
| 470 | |||
| 471 | if (!SaveObjectToPrecompiled(static_cast<u64>(entries.shader_length))) { | 457 | if (!SaveObjectToPrecompiled(static_cast<u64>(entries.shader_length))) { |
| 472 | return false; | 458 | return false; |
| 473 | } | 459 | } |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 4f135fe03..173b76c4e 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -97,6 +97,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format | |||
| 97 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U | 97 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U |
| 98 | {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S | 98 | {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S |
| 99 | {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI | 99 | {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI |
| 100 | {GL_RGB16F, GL_RGBA16, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBX16F | ||
| 100 | {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI | 101 | {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI |
| 101 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8 | 102 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8 |
| 102 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5 | 103 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5 |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 0bbbf6851..3c5acda3e 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -143,6 +143,7 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex | |||
| 143 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // RG8U | 143 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // RG8U |
| 144 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // RG8S | 144 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // RG8S |
| 145 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // RG32UI | 145 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // RG32UI |
| 146 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // RGBX16F | ||
| 146 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // R32UI | 147 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // R32UI |
| 147 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // ASTC_2D_8X8 | 148 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // ASTC_2D_8X8 |
| 148 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // ASTC_2D_8X5 | 149 | {vk::Format::eUndefined, ComponentType::Invalid, false}, // ASTC_2D_8X5 |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index f7fbbb6e4..77fc58f25 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include "video_core/engines/shader_header.h" | 19 | #include "video_core/engines/shader_header.h" |
| 20 | #include "video_core/renderer_vulkan/vk_device.h" | 20 | #include "video_core/renderer_vulkan/vk_device.h" |
| 21 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" | 21 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" |
| 22 | #include "video_core/shader/node.h" | ||
| 22 | #include "video_core/shader/shader_ir.h" | 23 | #include "video_core/shader/shader_ir.h" |
| 23 | 24 | ||
| 24 | namespace Vulkan::VKShader { | 25 | namespace Vulkan::VKShader { |
| @@ -939,22 +940,17 @@ private: | |||
| 939 | return {}; | 940 | return {}; |
| 940 | } | 941 | } |
| 941 | 942 | ||
| 942 | Id ImageStore(Operation operation) { | 943 | Id ImageLoad(Operation operation) { |
| 943 | UNIMPLEMENTED(); | ||
| 944 | return {}; | ||
| 945 | } | ||
| 946 | |||
| 947 | Id AtomicImageAdd(Operation operation) { | ||
| 948 | UNIMPLEMENTED(); | 944 | UNIMPLEMENTED(); |
| 949 | return {}; | 945 | return {}; |
| 950 | } | 946 | } |
| 951 | 947 | ||
| 952 | Id AtomicImageMin(Operation operation) { | 948 | Id ImageStore(Operation operation) { |
| 953 | UNIMPLEMENTED(); | 949 | UNIMPLEMENTED(); |
| 954 | return {}; | 950 | return {}; |
| 955 | } | 951 | } |
| 956 | 952 | ||
| 957 | Id AtomicImageMax(Operation operation) { | 953 | Id AtomicImageAdd(Operation operation) { |
| 958 | UNIMPLEMENTED(); | 954 | UNIMPLEMENTED(); |
| 959 | return {}; | 955 | return {}; |
| 960 | } | 956 | } |
| @@ -1440,10 +1436,9 @@ private: | |||
| 1440 | &SPIRVDecompiler::TextureQueryLod, | 1436 | &SPIRVDecompiler::TextureQueryLod, |
| 1441 | &SPIRVDecompiler::TexelFetch, | 1437 | &SPIRVDecompiler::TexelFetch, |
| 1442 | 1438 | ||
| 1439 | &SPIRVDecompiler::ImageLoad, | ||
| 1443 | &SPIRVDecompiler::ImageStore, | 1440 | &SPIRVDecompiler::ImageStore, |
| 1444 | &SPIRVDecompiler::AtomicImageAdd, | 1441 | &SPIRVDecompiler::AtomicImageAdd, |
| 1445 | &SPIRVDecompiler::AtomicImageMin, | ||
| 1446 | &SPIRVDecompiler::AtomicImageMax, | ||
| 1447 | &SPIRVDecompiler::AtomicImageAnd, | 1442 | &SPIRVDecompiler::AtomicImageAnd, |
| 1448 | &SPIRVDecompiler::AtomicImageOr, | 1443 | &SPIRVDecompiler::AtomicImageOr, |
| 1449 | &SPIRVDecompiler::AtomicImageXor, | 1444 | &SPIRVDecompiler::AtomicImageXor, |
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp index d54fb88c9..95ec1cdd9 100644 --- a/src/video_core/shader/decode/image.cpp +++ b/src/video_core/shader/decode/image.cpp | |||
| @@ -41,11 +41,46 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | |||
| 41 | const Instruction instr = {program_code[pc]}; | 41 | const Instruction instr = {program_code[pc]}; |
| 42 | const auto opcode = OpCode::Decode(instr); | 42 | const auto opcode = OpCode::Decode(instr); |
| 43 | 43 | ||
| 44 | const auto GetCoordinates = [this, instr](Tegra::Shader::ImageType image_type) { | ||
| 45 | std::vector<Node> coords; | ||
| 46 | const std::size_t num_coords{GetImageTypeNumCoordinates(image_type)}; | ||
| 47 | coords.reserve(num_coords); | ||
| 48 | for (std::size_t i = 0; i < num_coords; ++i) { | ||
| 49 | coords.push_back(GetRegister(instr.gpr8.Value() + i)); | ||
| 50 | } | ||
| 51 | return coords; | ||
| 52 | }; | ||
| 53 | |||
| 44 | switch (opcode->get().GetId()) { | 54 | switch (opcode->get().GetId()) { |
| 55 | case OpCode::Id::SULD: { | ||
| 56 | UNIMPLEMENTED_IF(instr.suldst.mode != Tegra::Shader::SurfaceDataMode::P); | ||
| 57 | UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store != | ||
| 58 | Tegra::Shader::OutOfBoundsStore::Ignore); | ||
| 59 | |||
| 60 | const auto type{instr.suldst.image_type}; | ||
| 61 | auto& image{instr.suldst.is_immediate ? GetImage(instr.image, type) | ||
| 62 | : GetBindlessImage(instr.gpr39, type)}; | ||
| 63 | image.MarkRead(); | ||
| 64 | |||
| 65 | u32 indexer = 0; | ||
| 66 | for (u32 element = 0; element < 4; ++element) { | ||
| 67 | if (!instr.suldst.IsComponentEnabled(element)) { | ||
| 68 | continue; | ||
| 69 | } | ||
| 70 | MetaImage meta{image, {}, element}; | ||
| 71 | Node value = Operation(OperationCode::ImageLoad, meta, GetCoordinates(type)); | ||
| 72 | SetTemporary(bb, indexer++, std::move(value)); | ||
| 73 | } | ||
| 74 | for (u32 i = 0; i < indexer; ++i) { | ||
| 75 | SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i)); | ||
| 76 | } | ||
| 77 | break; | ||
| 78 | } | ||
| 45 | case OpCode::Id::SUST: { | 79 | case OpCode::Id::SUST: { |
| 46 | UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P); | 80 | UNIMPLEMENTED_IF(instr.suldst.mode != Tegra::Shader::SurfaceDataMode::P); |
| 47 | UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore); | 81 | UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store != |
| 48 | UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store | 82 | Tegra::Shader::OutOfBoundsStore::Ignore); |
| 83 | UNIMPLEMENTED_IF(instr.suldst.component_mask_selector != 0xf); // Ensure we have RGBA | ||
| 49 | 84 | ||
| 50 | std::vector<Node> values; | 85 | std::vector<Node> values; |
| 51 | constexpr std::size_t hardcoded_size{4}; | 86 | constexpr std::size_t hardcoded_size{4}; |
| @@ -53,58 +88,51 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | |||
| 53 | values.push_back(GetRegister(instr.gpr0.Value() + i)); | 88 | values.push_back(GetRegister(instr.gpr0.Value() + i)); |
| 54 | } | 89 | } |
| 55 | 90 | ||
| 56 | std::vector<Node> coords; | 91 | const auto type{instr.suldst.image_type}; |
| 57 | const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)}; | 92 | auto& image{instr.suldst.is_immediate ? GetImage(instr.image, type) |
| 58 | for (std::size_t i = 0; i < num_coords; ++i) { | 93 | : GetBindlessImage(instr.gpr39, type)}; |
| 59 | coords.push_back(GetRegister(instr.gpr8.Value() + i)); | ||
| 60 | } | ||
| 61 | |||
| 62 | const auto type{instr.sust.image_type}; | ||
| 63 | auto& image{instr.sust.is_immediate ? GetImage(instr.image, type) | ||
| 64 | : GetBindlessImage(instr.gpr39, type)}; | ||
| 65 | image.MarkWrite(); | 94 | image.MarkWrite(); |
| 66 | 95 | ||
| 67 | MetaImage meta{image, values}; | 96 | MetaImage meta{image, std::move(values)}; |
| 68 | bb.push_back(Operation(OperationCode::ImageStore, meta, std::move(coords))); | 97 | bb.push_back(Operation(OperationCode::ImageStore, meta, GetCoordinates(type))); |
| 69 | break; | 98 | break; |
| 70 | } | 99 | } |
| 71 | case OpCode::Id::SUATOM: { | 100 | case OpCode::Id::SUATOM: { |
| 72 | UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0); | 101 | UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0); |
| 73 | 102 | ||
| 74 | Node value = GetRegister(instr.gpr0); | ||
| 75 | |||
| 76 | std::vector<Node> coords; | ||
| 77 | const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)}; | ||
| 78 | for (std::size_t i = 0; i < num_coords; ++i) { | ||
| 79 | coords.push_back(GetRegister(instr.gpr8.Value() + i)); | ||
| 80 | } | ||
| 81 | |||
| 82 | const OperationCode operation_code = [instr] { | 103 | const OperationCode operation_code = [instr] { |
| 83 | switch (instr.suatom_d.operation) { | 104 | switch (instr.suatom_d.operation_type) { |
| 84 | case Tegra::Shader::ImageAtomicOperation::Add: | 105 | case Tegra::Shader::ImageAtomicOperationType::S32: |
| 85 | return OperationCode::AtomicImageAdd; | 106 | case Tegra::Shader::ImageAtomicOperationType::U32: |
| 86 | case Tegra::Shader::ImageAtomicOperation::Min: | 107 | switch (instr.suatom_d.operation) { |
| 87 | return OperationCode::AtomicImageMin; | 108 | case Tegra::Shader::ImageAtomicOperation::Add: |
| 88 | case Tegra::Shader::ImageAtomicOperation::Max: | 109 | return OperationCode::AtomicImageAdd; |
| 89 | return OperationCode::AtomicImageMax; | 110 | case Tegra::Shader::ImageAtomicOperation::And: |
| 90 | case Tegra::Shader::ImageAtomicOperation::And: | 111 | return OperationCode::AtomicImageAnd; |
| 91 | return OperationCode::AtomicImageAnd; | 112 | case Tegra::Shader::ImageAtomicOperation::Or: |
| 92 | case Tegra::Shader::ImageAtomicOperation::Or: | 113 | return OperationCode::AtomicImageOr; |
| 93 | return OperationCode::AtomicImageOr; | 114 | case Tegra::Shader::ImageAtomicOperation::Xor: |
| 94 | case Tegra::Shader::ImageAtomicOperation::Xor: | 115 | return OperationCode::AtomicImageXor; |
| 95 | return OperationCode::AtomicImageXor; | 116 | case Tegra::Shader::ImageAtomicOperation::Exch: |
| 96 | case Tegra::Shader::ImageAtomicOperation::Exch: | 117 | return OperationCode::AtomicImageExchange; |
| 97 | return OperationCode::AtomicImageExchange; | 118 | } |
| 98 | default: | 119 | default: |
| 99 | UNIMPLEMENTED_MSG("Unimplemented operation={}", | 120 | break; |
| 100 | static_cast<u32>(instr.suatom_d.operation.Value())); | ||
| 101 | return OperationCode::AtomicImageAdd; | ||
| 102 | } | 121 | } |
| 122 | UNIMPLEMENTED_MSG("Unimplemented operation={} type={}", | ||
| 123 | static_cast<u64>(instr.suatom_d.operation.Value()), | ||
| 124 | static_cast<u64>(instr.suatom_d.operation_type.Value())); | ||
| 125 | return OperationCode::AtomicImageAdd; | ||
| 103 | }(); | 126 | }(); |
| 104 | 127 | ||
| 105 | const auto& image{GetImage(instr.image, instr.suatom_d.image_type, instr.suatom_d.size)}; | 128 | Node value = GetRegister(instr.gpr0); |
| 129 | |||
| 130 | const auto type = instr.suatom_d.image_type; | ||
| 131 | auto& image = GetImage(instr.image, type); | ||
| 132 | image.MarkAtomic(); | ||
| 133 | |||
| 106 | MetaImage meta{image, {std::move(value)}}; | 134 | MetaImage meta{image, {std::move(value)}}; |
| 107 | SetRegister(bb, instr.gpr0, Operation(operation_code, meta, std::move(coords))); | 135 | SetRegister(bb, instr.gpr0, Operation(operation_code, meta, GetCoordinates(type))); |
| 108 | break; | 136 | break; |
| 109 | } | 137 | } |
| 110 | default: | 138 | default: |
| @@ -114,35 +142,32 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | |||
| 114 | return pc; | 142 | return pc; |
| 115 | } | 143 | } |
| 116 | 144 | ||
| 117 | Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type, | 145 | Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) { |
| 118 | std::optional<Tegra::Shader::ImageAtomicSize> size) { | ||
| 119 | const auto offset{static_cast<std::size_t>(image.index.Value())}; | 146 | const auto offset{static_cast<std::size_t>(image.index.Value())}; |
| 120 | if (const auto image = TryUseExistingImage(offset, type, size)) { | 147 | if (const auto image = TryUseExistingImage(offset, type)) { |
| 121 | return *image; | 148 | return *image; |
| 122 | } | 149 | } |
| 123 | 150 | ||
| 124 | const std::size_t next_index{used_images.size()}; | 151 | const std::size_t next_index{used_images.size()}; |
| 125 | return used_images.emplace(offset, Image{offset, next_index, type, size}).first->second; | 152 | return used_images.emplace(offset, Image{offset, next_index, type}).first->second; |
| 126 | } | 153 | } |
| 127 | 154 | ||
| 128 | Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type, | 155 | Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) { |
| 129 | std::optional<Tegra::Shader::ImageAtomicSize> size) { | ||
| 130 | const Node image_register{GetRegister(reg)}; | 156 | const Node image_register{GetRegister(reg)}; |
| 131 | const auto [base_image, cbuf_index, cbuf_offset]{ | 157 | const auto [base_image, cbuf_index, cbuf_offset]{ |
| 132 | TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; | 158 | TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; |
| 133 | const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; | 159 | const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; |
| 134 | 160 | ||
| 135 | if (const auto image = TryUseExistingImage(cbuf_key, type, size)) { | 161 | if (const auto image = TryUseExistingImage(cbuf_key, type)) { |
| 136 | return *image; | 162 | return *image; |
| 137 | } | 163 | } |
| 138 | 164 | ||
| 139 | const std::size_t next_index{used_images.size()}; | 165 | const std::size_t next_index{used_images.size()}; |
| 140 | return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type, size}) | 166 | return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type}) |
| 141 | .first->second; | 167 | .first->second; |
| 142 | } | 168 | } |
| 143 | 169 | ||
| 144 | Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, | 170 | Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type) { |
| 145 | std::optional<Tegra::Shader::ImageAtomicSize> size) { | ||
| 146 | auto it = used_images.find(offset); | 171 | auto it = used_images.find(offset); |
| 147 | if (it == used_images.end()) { | 172 | if (it == used_images.end()) { |
| 148 | return nullptr; | 173 | return nullptr; |
| @@ -150,14 +175,6 @@ Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, | |||
| 150 | auto& image = it->second; | 175 | auto& image = it->second; |
| 151 | ASSERT(image.GetType() == type); | 176 | ASSERT(image.GetType() == type); |
| 152 | 177 | ||
| 153 | if (size) { | ||
| 154 | // We know the size, if it's known it has to be the same as before, otherwise we can set it. | ||
| 155 | if (image.IsSizeKnown()) { | ||
| 156 | ASSERT(image.GetSize() == size); | ||
| 157 | } else { | ||
| 158 | image.SetSize(*size); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | return ℑ | 178 | return ℑ |
| 162 | } | 179 | } |
| 163 | 180 | ||
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index abf2cb1ab..338bab17c 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h | |||
| @@ -149,10 +149,10 @@ enum class OperationCode { | |||
| 149 | TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 | 149 | TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 |
| 150 | TexelFetch, /// (MetaTexture, int[N], int) -> float4 | 150 | TexelFetch, /// (MetaTexture, int[N], int) -> float4 |
| 151 | 151 | ||
| 152 | ImageStore, /// (MetaImage, int[N] values) -> void | 152 | ImageLoad, /// (MetaImage, int[N] coords) -> void |
| 153 | ImageStore, /// (MetaImage, int[N] coords) -> void | ||
| 154 | |||
| 153 | AtomicImageAdd, /// (MetaImage, int[N] coords) -> void | 155 | AtomicImageAdd, /// (MetaImage, int[N] coords) -> void |
| 154 | AtomicImageMin, /// (MetaImage, int[N] coords) -> void | ||
| 155 | AtomicImageMax, /// (MetaImage, int[N] coords) -> void | ||
| 156 | AtomicImageAnd, /// (MetaImage, int[N] coords) -> void | 156 | AtomicImageAnd, /// (MetaImage, int[N] coords) -> void |
| 157 | AtomicImageOr, /// (MetaImage, int[N] coords) -> void | 157 | AtomicImageOr, /// (MetaImage, int[N] coords) -> void |
| 158 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void | 158 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void |
| @@ -294,21 +294,18 @@ private: | |||
| 294 | 294 | ||
| 295 | class Image final { | 295 | class Image final { |
| 296 | public: | 296 | public: |
| 297 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, | 297 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type) |
| 298 | std::optional<Tegra::Shader::ImageAtomicSize> size) | 298 | : offset{offset}, index{index}, type{type}, is_bindless{false} {} |
| 299 | : offset{offset}, index{index}, type{type}, is_bindless{false}, size{size} {} | ||
| 300 | 299 | ||
| 301 | constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, | 300 | constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, |
| 302 | Tegra::Shader::ImageType type, | 301 | Tegra::Shader::ImageType type) |
| 303 | std::optional<Tegra::Shader::ImageAtomicSize> size) | ||
| 304 | : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, | 302 | : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, |
| 305 | is_bindless{true}, size{size} {} | 303 | is_bindless{true} {} |
| 306 | 304 | ||
| 307 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, | 305 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, |
| 308 | bool is_bindless, bool is_written, bool is_read, | 306 | bool is_bindless, bool is_written, bool is_read, bool is_atomic) |
| 309 | std::optional<Tegra::Shader::ImageAtomicSize> size) | ||
| 310 | : offset{offset}, index{index}, type{type}, is_bindless{is_bindless}, | 307 | : offset{offset}, index{index}, type{type}, is_bindless{is_bindless}, |
| 311 | is_written{is_written}, is_read{is_read}, size{size} {} | 308 | is_written{is_written}, is_read{is_read}, is_atomic{is_atomic} {} |
| 312 | 309 | ||
| 313 | void MarkWrite() { | 310 | void MarkWrite() { |
| 314 | is_written = true; | 311 | is_written = true; |
| @@ -318,8 +315,10 @@ public: | |||
| 318 | is_read = true; | 315 | is_read = true; |
| 319 | } | 316 | } |
| 320 | 317 | ||
| 321 | void SetSize(Tegra::Shader::ImageAtomicSize size_) { | 318 | void MarkAtomic() { |
| 322 | size = size_; | 319 | MarkWrite(); |
| 320 | MarkRead(); | ||
| 321 | is_atomic = true; | ||
| 323 | } | 322 | } |
| 324 | 323 | ||
| 325 | constexpr std::size_t GetOffset() const { | 324 | constexpr std::size_t GetOffset() const { |
| @@ -346,21 +345,17 @@ public: | |||
| 346 | return is_read; | 345 | return is_read; |
| 347 | } | 346 | } |
| 348 | 347 | ||
| 349 | constexpr std::pair<u32, u32> GetBindlessCBuf() const { | 348 | constexpr bool IsAtomic() const { |
| 350 | return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; | 349 | return is_atomic; |
| 351 | } | 350 | } |
| 352 | 351 | ||
| 353 | constexpr bool IsSizeKnown() const { | 352 | constexpr std::pair<u32, u32> GetBindlessCBuf() const { |
| 354 | return size.has_value(); | 353 | return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; |
| 355 | } | ||
| 356 | |||
| 357 | constexpr Tegra::Shader::ImageAtomicSize GetSize() const { | ||
| 358 | return size.value(); | ||
| 359 | } | 354 | } |
| 360 | 355 | ||
| 361 | constexpr bool operator<(const Image& rhs) const { | 356 | constexpr bool operator<(const Image& rhs) const { |
| 362 | return std::tie(offset, index, type, size, is_bindless) < | 357 | return std::tie(offset, index, type, is_bindless) < |
| 363 | std::tie(rhs.offset, rhs.index, rhs.type, rhs.size, rhs.is_bindless); | 358 | std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless); |
| 364 | } | 359 | } |
| 365 | 360 | ||
| 366 | private: | 361 | private: |
| @@ -370,7 +365,7 @@ private: | |||
| 370 | bool is_bindless{}; | 365 | bool is_bindless{}; |
| 371 | bool is_written{}; | 366 | bool is_written{}; |
| 372 | bool is_read{}; | 367 | bool is_read{}; |
| 373 | std::optional<Tegra::Shader::ImageAtomicSize> size{}; | 368 | bool is_atomic{}; |
| 374 | }; | 369 | }; |
| 375 | 370 | ||
| 376 | struct GlobalMemoryBase { | 371 | struct GlobalMemoryBase { |
| @@ -402,6 +397,7 @@ struct MetaTexture { | |||
| 402 | struct MetaImage { | 397 | struct MetaImage { |
| 403 | const Image& image; | 398 | const Image& image; |
| 404 | std::vector<Node> values; | 399 | std::vector<Node> values; |
| 400 | u32 element{}; | ||
| 405 | }; | 401 | }; |
| 406 | 402 | ||
| 407 | /// Parameters that modify an operation but are not part of any particular operand | 403 | /// Parameters that modify an operation but are not part of any particular operand |
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index bbbab0bca..2c357f310 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp | |||
| @@ -114,6 +114,18 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff | |||
| 114 | break; | 114 | break; |
| 115 | } | 115 | } |
| 116 | } | 116 | } |
| 117 | if (index == Attribute::Index::TessCoordInstanceIDVertexID) { | ||
| 118 | switch (element) { | ||
| 119 | case 2: | ||
| 120 | uses_instance_id = true; | ||
| 121 | break; | ||
| 122 | case 3: | ||
| 123 | uses_vertex_id = true; | ||
| 124 | break; | ||
| 125 | default: | ||
| 126 | break; | ||
| 127 | } | ||
| 128 | } | ||
| 117 | if (index == Attribute::Index::ClipDistances0123 || | 129 | if (index == Attribute::Index::ClipDistances0123 || |
| 118 | index == Attribute::Index::ClipDistances4567) { | 130 | index == Attribute::Index::ClipDistances4567) { |
| 119 | const auto clip_index = | 131 | const auto clip_index = |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 6aed9bb84..6f666ee30 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -124,6 +124,14 @@ public: | |||
| 124 | return uses_point_size; | 124 | return uses_point_size; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | bool UsesInstanceId() const { | ||
| 128 | return uses_instance_id; | ||
| 129 | } | ||
| 130 | |||
| 131 | bool UsesVertexId() const { | ||
| 132 | return uses_vertex_id; | ||
| 133 | } | ||
| 134 | |||
| 127 | bool HasPhysicalAttributes() const { | 135 | bool HasPhysicalAttributes() const { |
| 128 | return uses_physical_attributes; | 136 | return uses_physical_attributes; |
| 129 | } | 137 | } |
| @@ -276,16 +284,13 @@ private: | |||
| 276 | bool is_shadow); | 284 | bool is_shadow); |
| 277 | 285 | ||
| 278 | /// Accesses an image. | 286 | /// Accesses an image. |
| 279 | Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type, | 287 | Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); |
| 280 | std::optional<Tegra::Shader::ImageAtomicSize> size = {}); | ||
| 281 | 288 | ||
| 282 | /// Access a bindless image sampler. | 289 | /// Access a bindless image sampler. |
| 283 | Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type, | 290 | Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type); |
| 284 | std::optional<Tegra::Shader::ImageAtomicSize> size = {}); | ||
| 285 | 291 | ||
| 286 | /// Tries to access an existing image, updating it's state as needed | 292 | /// Tries to access an existing image, updating it's state as needed |
| 287 | Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, | 293 | Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type); |
| 288 | std::optional<Tegra::Shader::ImageAtomicSize> size); | ||
| 289 | 294 | ||
| 290 | /// Extracts a sequence of bits from a node | 295 | /// Extracts a sequence of bits from a node |
| 291 | Node BitfieldExtract(Node value, u32 offset, u32 bits); | 296 | Node BitfieldExtract(Node value, u32 offset, u32 bits); |
| @@ -373,6 +378,8 @@ private: | |||
| 373 | bool uses_viewport_index{}; | 378 | bool uses_viewport_index{}; |
| 374 | bool uses_point_size{}; | 379 | bool uses_point_size{}; |
| 375 | bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes | 380 | bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes |
| 381 | bool uses_instance_id{}; | ||
| 382 | bool uses_vertex_id{}; | ||
| 376 | 383 | ||
| 377 | Tegra::Shader::Header header; | 384 | Tegra::Shader::Header header; |
| 378 | }; | 385 | }; |
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 53d0142cb..250afc6d6 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp | |||
| @@ -159,6 +159,8 @@ PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) | |||
| 159 | return PixelFormat::R32UI; | 159 | return PixelFormat::R32UI; |
| 160 | case Tegra::RenderTargetFormat::RG32_UINT: | 160 | case Tegra::RenderTargetFormat::RG32_UINT: |
| 161 | return PixelFormat::RG32UI; | 161 | return PixelFormat::RG32UI; |
| 162 | case Tegra::RenderTargetFormat::RGBX16_FLOAT: | ||
| 163 | return PixelFormat::RGBX16F; | ||
| 162 | default: | 164 | default: |
| 163 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | 165 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); |
| 164 | UNREACHABLE(); | 166 | UNREACHABLE(); |
| @@ -415,6 +417,7 @@ ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) { | |||
| 415 | case Tegra::RenderTargetFormat::RG8_SNORM: | 417 | case Tegra::RenderTargetFormat::RG8_SNORM: |
| 416 | return ComponentType::SNorm; | 418 | return ComponentType::SNorm; |
| 417 | case Tegra::RenderTargetFormat::RGBA16_FLOAT: | 419 | case Tegra::RenderTargetFormat::RGBA16_FLOAT: |
| 420 | case Tegra::RenderTargetFormat::RGBX16_FLOAT: | ||
| 418 | case Tegra::RenderTargetFormat::R11G11B10_FLOAT: | 421 | case Tegra::RenderTargetFormat::R11G11B10_FLOAT: |
| 419 | case Tegra::RenderTargetFormat::RGBA32_FLOAT: | 422 | case Tegra::RenderTargetFormat::RGBA32_FLOAT: |
| 420 | case Tegra::RenderTargetFormat::RG32_FLOAT: | 423 | case Tegra::RenderTargetFormat::RG32_FLOAT: |
diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 19268b7cd..1e1c432a5 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h | |||
| @@ -57,36 +57,37 @@ enum class PixelFormat { | |||
| 57 | RG8U = 39, | 57 | RG8U = 39, |
| 58 | RG8S = 40, | 58 | RG8S = 40, |
| 59 | RG32UI = 41, | 59 | RG32UI = 41, |
| 60 | R32UI = 42, | 60 | RGBX16F = 42, |
| 61 | ASTC_2D_8X8 = 43, | 61 | R32UI = 43, |
| 62 | ASTC_2D_8X5 = 44, | 62 | ASTC_2D_8X8 = 44, |
| 63 | ASTC_2D_5X4 = 45, | 63 | ASTC_2D_8X5 = 45, |
| 64 | BGRA8_SRGB = 46, | 64 | ASTC_2D_5X4 = 46, |
| 65 | DXT1_SRGB = 47, | 65 | BGRA8_SRGB = 47, |
| 66 | DXT23_SRGB = 48, | 66 | DXT1_SRGB = 48, |
| 67 | DXT45_SRGB = 49, | 67 | DXT23_SRGB = 49, |
| 68 | BC7U_SRGB = 50, | 68 | DXT45_SRGB = 50, |
| 69 | ASTC_2D_4X4_SRGB = 51, | 69 | BC7U_SRGB = 51, |
| 70 | ASTC_2D_8X8_SRGB = 52, | 70 | ASTC_2D_4X4_SRGB = 52, |
| 71 | ASTC_2D_8X5_SRGB = 53, | 71 | ASTC_2D_8X8_SRGB = 53, |
| 72 | ASTC_2D_5X4_SRGB = 54, | 72 | ASTC_2D_8X5_SRGB = 54, |
| 73 | ASTC_2D_5X5 = 55, | 73 | ASTC_2D_5X4_SRGB = 55, |
| 74 | ASTC_2D_5X5_SRGB = 56, | 74 | ASTC_2D_5X5 = 56, |
| 75 | ASTC_2D_10X8 = 57, | 75 | ASTC_2D_5X5_SRGB = 57, |
| 76 | ASTC_2D_10X8_SRGB = 58, | 76 | ASTC_2D_10X8 = 58, |
| 77 | ASTC_2D_10X8_SRGB = 59, | ||
| 77 | 78 | ||
| 78 | MaxColorFormat, | 79 | MaxColorFormat, |
| 79 | 80 | ||
| 80 | // Depth formats | 81 | // Depth formats |
| 81 | Z32F = 59, | 82 | Z32F = 60, |
| 82 | Z16 = 60, | 83 | Z16 = 61, |
| 83 | 84 | ||
| 84 | MaxDepthFormat, | 85 | MaxDepthFormat, |
| 85 | 86 | ||
| 86 | // DepthStencil formats | 87 | // DepthStencil formats |
| 87 | Z24S8 = 61, | 88 | Z24S8 = 62, |
| 88 | S8Z24 = 62, | 89 | S8Z24 = 63, |
| 89 | Z32FS8 = 63, | 90 | Z32FS8 = 64, |
| 90 | 91 | ||
| 91 | MaxDepthStencilFormat, | 92 | MaxDepthStencilFormat, |
| 92 | 93 | ||
| @@ -166,6 +167,7 @@ constexpr std::array<u32, MaxPixelFormat> compression_factor_shift_table = {{ | |||
| 166 | 0, // RG8U | 167 | 0, // RG8U |
| 167 | 0, // RG8S | 168 | 0, // RG8S |
| 168 | 0, // RG32UI | 169 | 0, // RG32UI |
| 170 | 0, // RGBX16F | ||
| 169 | 0, // R32UI | 171 | 0, // R32UI |
| 170 | 2, // ASTC_2D_8X8 | 172 | 2, // ASTC_2D_8X8 |
| 171 | 2, // ASTC_2D_8X5 | 173 | 2, // ASTC_2D_8X5 |
| @@ -249,6 +251,7 @@ constexpr std::array<u32, MaxPixelFormat> block_width_table = {{ | |||
| 249 | 1, // RG8U | 251 | 1, // RG8U |
| 250 | 1, // RG8S | 252 | 1, // RG8S |
| 251 | 1, // RG32UI | 253 | 1, // RG32UI |
| 254 | 1, // RGBX16F | ||
| 252 | 1, // R32UI | 255 | 1, // R32UI |
| 253 | 8, // ASTC_2D_8X8 | 256 | 8, // ASTC_2D_8X8 |
| 254 | 8, // ASTC_2D_8X5 | 257 | 8, // ASTC_2D_8X5 |
| @@ -324,6 +327,7 @@ constexpr std::array<u32, MaxPixelFormat> block_height_table = {{ | |||
| 324 | 1, // RG8U | 327 | 1, // RG8U |
| 325 | 1, // RG8S | 328 | 1, // RG8S |
| 326 | 1, // RG32UI | 329 | 1, // RG32UI |
| 330 | 1, // RGBX16F | ||
| 327 | 1, // R32UI | 331 | 1, // R32UI |
| 328 | 8, // ASTC_2D_8X8 | 332 | 8, // ASTC_2D_8X8 |
| 329 | 5, // ASTC_2D_8X5 | 333 | 5, // ASTC_2D_8X5 |
| @@ -399,6 +403,7 @@ constexpr std::array<u32, MaxPixelFormat> bpp_table = {{ | |||
| 399 | 16, // RG8U | 403 | 16, // RG8U |
| 400 | 16, // RG8S | 404 | 16, // RG8S |
| 401 | 64, // RG32UI | 405 | 64, // RG32UI |
| 406 | 64, // RGBX16F | ||
| 402 | 32, // R32UI | 407 | 32, // R32UI |
| 403 | 128, // ASTC_2D_8X8 | 408 | 128, // ASTC_2D_8X8 |
| 404 | 128, // ASTC_2D_8X5 | 409 | 128, // ASTC_2D_8X5 |
| @@ -489,6 +494,7 @@ constexpr std::array<SurfaceCompression, MaxPixelFormat> compression_type_table | |||
| 489 | SurfaceCompression::None, // RG8U | 494 | SurfaceCompression::None, // RG8U |
| 490 | SurfaceCompression::None, // RG8S | 495 | SurfaceCompression::None, // RG8S |
| 491 | SurfaceCompression::None, // RG32UI | 496 | SurfaceCompression::None, // RG32UI |
| 497 | SurfaceCompression::None, // RGBX16F | ||
| 492 | SurfaceCompression::None, // R32UI | 498 | SurfaceCompression::None, // R32UI |
| 493 | SurfaceCompression::Converted, // ASTC_2D_8X8 | 499 | SurfaceCompression::Converted, // ASTC_2D_8X8 |
| 494 | SurfaceCompression::Converted, // ASTC_2D_8X5 | 500 | SurfaceCompression::Converted, // ASTC_2D_8X5 |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index dc6fa07fc..ff1c1d985 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -66,6 +66,9 @@ add_executable(yuzu | |||
| 66 | configuration/configure_profile_manager.cpp | 66 | configuration/configure_profile_manager.cpp |
| 67 | configuration/configure_profile_manager.h | 67 | configuration/configure_profile_manager.h |
| 68 | configuration/configure_profile_manager.ui | 68 | configuration/configure_profile_manager.ui |
| 69 | configuration/configure_service.cpp | ||
| 70 | configuration/configure_service.h | ||
| 71 | configuration/configure_service.ui | ||
| 69 | configuration/configure_system.cpp | 72 | configuration/configure_system.cpp |
| 70 | configuration/configure_system.h | 73 | configuration/configure_system.h |
| 71 | configuration/configure_system.ui | 74 | configuration/configure_system.ui |
| @@ -186,6 +189,10 @@ if (YUZU_USE_QT_WEB_ENGINE) | |||
| 186 | target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) | 189 | target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) |
| 187 | endif () | 190 | endif () |
| 188 | 191 | ||
| 192 | if (YUZU_ENABLE_BOXCAT) | ||
| 193 | target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_BOXCAT) | ||
| 194 | endif () | ||
| 195 | |||
| 189 | if(UNIX AND NOT APPLE) | 196 | if(UNIX AND NOT APPLE) |
| 190 | install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") | 197 | install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") |
| 191 | endif() | 198 | endif() |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 92d9fb161..4cb27ddb2 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -525,6 +525,17 @@ void Config::ReadDebuggingValues() { | |||
| 525 | qt_config->endGroup(); | 525 | qt_config->endGroup(); |
| 526 | } | 526 | } |
| 527 | 527 | ||
| 528 | void Config::ReadServiceValues() { | ||
| 529 | qt_config->beginGroup(QStringLiteral("Services")); | ||
| 530 | Settings::values.bcat_backend = | ||
| 531 | ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("boxcat")) | ||
| 532 | .toString() | ||
| 533 | .toStdString(); | ||
| 534 | Settings::values.bcat_boxcat_local = | ||
| 535 | ReadSetting(QStringLiteral("bcat_boxcat_local"), false).toBool(); | ||
| 536 | qt_config->endGroup(); | ||
| 537 | } | ||
| 538 | |||
| 528 | void Config::ReadDisabledAddOnValues() { | 539 | void Config::ReadDisabledAddOnValues() { |
| 529 | const auto size = qt_config->beginReadArray(QStringLiteral("DisabledAddOns")); | 540 | const auto size = qt_config->beginReadArray(QStringLiteral("DisabledAddOns")); |
| 530 | 541 | ||
| @@ -769,6 +780,7 @@ void Config::ReadValues() { | |||
| 769 | ReadMiscellaneousValues(); | 780 | ReadMiscellaneousValues(); |
| 770 | ReadDebuggingValues(); | 781 | ReadDebuggingValues(); |
| 771 | ReadWebServiceValues(); | 782 | ReadWebServiceValues(); |
| 783 | ReadServiceValues(); | ||
| 772 | ReadDisabledAddOnValues(); | 784 | ReadDisabledAddOnValues(); |
| 773 | ReadUIValues(); | 785 | ReadUIValues(); |
| 774 | } | 786 | } |
| @@ -866,6 +878,7 @@ void Config::SaveValues() { | |||
| 866 | SaveMiscellaneousValues(); | 878 | SaveMiscellaneousValues(); |
| 867 | SaveDebuggingValues(); | 879 | SaveDebuggingValues(); |
| 868 | SaveWebServiceValues(); | 880 | SaveWebServiceValues(); |
| 881 | SaveServiceValues(); | ||
| 869 | SaveDisabledAddOnValues(); | 882 | SaveDisabledAddOnValues(); |
| 870 | SaveUIValues(); | 883 | SaveUIValues(); |
| 871 | } | 884 | } |
| @@ -963,6 +976,14 @@ void Config::SaveDebuggingValues() { | |||
| 963 | qt_config->endGroup(); | 976 | qt_config->endGroup(); |
| 964 | } | 977 | } |
| 965 | 978 | ||
| 979 | void Config::SaveServiceValues() { | ||
| 980 | qt_config->beginGroup(QStringLiteral("Services")); | ||
| 981 | WriteSetting(QStringLiteral("bcat_backend"), | ||
| 982 | QString::fromStdString(Settings::values.bcat_backend), QStringLiteral("null")); | ||
| 983 | WriteSetting(QStringLiteral("bcat_boxcat_local"), Settings::values.bcat_boxcat_local, false); | ||
| 984 | qt_config->endGroup(); | ||
| 985 | } | ||
| 986 | |||
| 966 | void Config::SaveDisabledAddOnValues() { | 987 | void Config::SaveDisabledAddOnValues() { |
| 967 | qt_config->beginWriteArray(QStringLiteral("DisabledAddOns")); | 988 | qt_config->beginWriteArray(QStringLiteral("DisabledAddOns")); |
| 968 | 989 | ||
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 6b523ecdd..ba6888004 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h | |||
| @@ -42,6 +42,7 @@ private: | |||
| 42 | void ReadCoreValues(); | 42 | void ReadCoreValues(); |
| 43 | void ReadDataStorageValues(); | 43 | void ReadDataStorageValues(); |
| 44 | void ReadDebuggingValues(); | 44 | void ReadDebuggingValues(); |
| 45 | void ReadServiceValues(); | ||
| 45 | void ReadDisabledAddOnValues(); | 46 | void ReadDisabledAddOnValues(); |
| 46 | void ReadMiscellaneousValues(); | 47 | void ReadMiscellaneousValues(); |
| 47 | void ReadPathValues(); | 48 | void ReadPathValues(); |
| @@ -65,6 +66,7 @@ private: | |||
| 65 | void SaveCoreValues(); | 66 | void SaveCoreValues(); |
| 66 | void SaveDataStorageValues(); | 67 | void SaveDataStorageValues(); |
| 67 | void SaveDebuggingValues(); | 68 | void SaveDebuggingValues(); |
| 69 | void SaveServiceValues(); | ||
| 68 | void SaveDisabledAddOnValues(); | 70 | void SaveDisabledAddOnValues(); |
| 69 | void SaveMiscellaneousValues(); | 71 | void SaveMiscellaneousValues(); |
| 70 | void SavePathValues(); | 72 | void SavePathValues(); |
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index 49fadd0ef..372427ae2 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui | |||
| @@ -98,6 +98,11 @@ | |||
| 98 | <string>Web</string> | 98 | <string>Web</string> |
| 99 | </attribute> | 99 | </attribute> |
| 100 | </widget> | 100 | </widget> |
| 101 | <widget class="ConfigureService" name="serviceTab"> | ||
| 102 | <attribute name="title"> | ||
| 103 | <string>Services</string> | ||
| 104 | </attribute> | ||
| 105 | </widget> | ||
| 101 | </widget> | 106 | </widget> |
| 102 | </item> | 107 | </item> |
| 103 | </layout> | 108 | </layout> |
| @@ -178,6 +183,12 @@ | |||
| 178 | <header>configuration/configure_hotkeys.h</header> | 183 | <header>configuration/configure_hotkeys.h</header> |
| 179 | <container>1</container> | 184 | <container>1</container> |
| 180 | </customwidget> | 185 | </customwidget> |
| 186 | <customwidget> | ||
| 187 | <class>ConfigureService</class> | ||
| 188 | <extends>QWidget</extends> | ||
| 189 | <header>configuration/configure_service.h</header> | ||
| 190 | <container>1</container> | ||
| 191 | </customwidget> | ||
| 181 | </customwidgets> | 192 | </customwidgets> |
| 182 | <resources/> | 193 | <resources/> |
| 183 | <connections> | 194 | <connections> |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 7c875ae87..25b2e1b05 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -44,6 +44,7 @@ void ConfigureDialog::ApplyConfiguration() { | |||
| 44 | ui->audioTab->ApplyConfiguration(); | 44 | ui->audioTab->ApplyConfiguration(); |
| 45 | ui->debugTab->ApplyConfiguration(); | 45 | ui->debugTab->ApplyConfiguration(); |
| 46 | ui->webTab->ApplyConfiguration(); | 46 | ui->webTab->ApplyConfiguration(); |
| 47 | ui->serviceTab->ApplyConfiguration(); | ||
| 47 | Settings::Apply(); | 48 | Settings::Apply(); |
| 48 | Settings::LogSettings(); | 49 | Settings::LogSettings(); |
| 49 | } | 50 | } |
| @@ -74,7 +75,8 @@ Q_DECLARE_METATYPE(QList<QWidget*>); | |||
| 74 | void ConfigureDialog::PopulateSelectionList() { | 75 | void ConfigureDialog::PopulateSelectionList() { |
| 75 | const std::array<std::pair<QString, QList<QWidget*>>, 4> items{ | 76 | const std::array<std::pair<QString, QList<QWidget*>>, 4> items{ |
| 76 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}}, | 77 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}}, |
| 77 | {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->filesystemTab, ui->audioTab}}, | 78 | {tr("System"), |
| 79 | {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab, ui->audioTab}}, | ||
| 78 | {tr("Graphics"), {ui->graphicsTab}}, | 80 | {tr("Graphics"), {ui->graphicsTab}}, |
| 79 | {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, | 81 | {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, |
| 80 | }; | 82 | }; |
| @@ -108,6 +110,7 @@ void ConfigureDialog::UpdateVisibleTabs() { | |||
| 108 | {ui->webTab, tr("Web")}, | 110 | {ui->webTab, tr("Web")}, |
| 109 | {ui->gameListTab, tr("Game List")}, | 111 | {ui->gameListTab, tr("Game List")}, |
| 110 | {ui->filesystemTab, tr("Filesystem")}, | 112 | {ui->filesystemTab, tr("Filesystem")}, |
| 113 | {ui->serviceTab, tr("Services")}, | ||
| 111 | }; | 114 | }; |
| 112 | 115 | ||
| 113 | [[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget); | 116 | [[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget); |
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index b49446be9..98bc9b391 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <QCheckBox> | ||
| 5 | #include <QSpinBox> | 6 | #include <QSpinBox> |
| 6 | #include "core/core.h" | 7 | #include "core/core.h" |
| 7 | #include "core/settings.h" | 8 | #include "core/settings.h" |
diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_service.cpp new file mode 100644 index 000000000..81c9e933f --- /dev/null +++ b/src/yuzu/configuration/configure_service.cpp | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QGraphicsItem> | ||
| 6 | #include <QtConcurrent/QtConcurrent> | ||
| 7 | #include "core/hle/service/bcat/backend/boxcat.h" | ||
| 8 | #include "core/settings.h" | ||
| 9 | #include "ui_configure_service.h" | ||
| 10 | #include "yuzu/configuration/configure_service.h" | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | QString FormatEventStatusString(const Service::BCAT::EventStatus& status) { | ||
| 14 | QString out; | ||
| 15 | |||
| 16 | if (status.header.has_value()) { | ||
| 17 | out += QStringLiteral("<i>%1</i><br>").arg(QString::fromStdString(*status.header)); | ||
| 18 | } | ||
| 19 | |||
| 20 | if (status.events.size() == 1) { | ||
| 21 | out += QStringLiteral("%1<br>").arg(QString::fromStdString(status.events.front())); | ||
| 22 | } else { | ||
| 23 | for (const auto& event : status.events) { | ||
| 24 | out += QStringLiteral("- %1<br>").arg(QString::fromStdString(event)); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | if (status.footer.has_value()) { | ||
| 29 | out += QStringLiteral("<i>%1</i><br>").arg(QString::fromStdString(*status.footer)); | ||
| 30 | } | ||
| 31 | |||
| 32 | return out; | ||
| 33 | } | ||
| 34 | } // Anonymous namespace | ||
| 35 | |||
| 36 | ConfigureService::ConfigureService(QWidget* parent) | ||
| 37 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureService>()) { | ||
| 38 | ui->setupUi(this); | ||
| 39 | |||
| 40 | ui->bcat_source->addItem(QStringLiteral("None")); | ||
| 41 | ui->bcat_empty_label->setHidden(true); | ||
| 42 | ui->bcat_empty_header->setHidden(true); | ||
| 43 | |||
| 44 | #ifdef YUZU_ENABLE_BOXCAT | ||
| 45 | ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat")); | ||
| 46 | #endif | ||
| 47 | |||
| 48 | connect(ui->bcat_source, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | ||
| 49 | &ConfigureService::OnBCATImplChanged); | ||
| 50 | |||
| 51 | this->SetConfiguration(); | ||
| 52 | } | ||
| 53 | |||
| 54 | ConfigureService::~ConfigureService() = default; | ||
| 55 | |||
| 56 | void ConfigureService::ApplyConfiguration() { | ||
| 57 | Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString(); | ||
| 58 | } | ||
| 59 | |||
| 60 | void ConfigureService::RetranslateUi() { | ||
| 61 | ui->retranslateUi(this); | ||
| 62 | } | ||
| 63 | |||
| 64 | void ConfigureService::SetConfiguration() { | ||
| 65 | const int index = | ||
| 66 | ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend)); | ||
| 67 | ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index); | ||
| 68 | } | ||
| 69 | |||
| 70 | std::pair<QString, QString> ConfigureService::BCATDownloadEvents() { | ||
| 71 | std::optional<std::string> global; | ||
| 72 | std::map<std::string, Service::BCAT::EventStatus> map; | ||
| 73 | const auto res = Service::BCAT::Boxcat::GetStatus(global, map); | ||
| 74 | |||
| 75 | switch (res) { | ||
| 76 | case Service::BCAT::Boxcat::StatusResult::Offline: | ||
| 77 | return {QString{}, | ||
| 78 | tr("The boxcat service is offline or you are not connected to the internet.")}; | ||
| 79 | case Service::BCAT::Boxcat::StatusResult::ParseError: | ||
| 80 | return {QString{}, | ||
| 81 | tr("There was an error while processing the boxcat event data. Contact the yuzu " | ||
| 82 | "developers.")}; | ||
| 83 | case Service::BCAT::Boxcat::StatusResult::BadClientVersion: | ||
| 84 | return {QString{}, | ||
| 85 | tr("The version of yuzu you are using is either too new or too old for the server. " | ||
| 86 | "Try updating to the latest official release of yuzu.")}; | ||
| 87 | } | ||
| 88 | |||
| 89 | if (map.empty()) { | ||
| 90 | return {QStringLiteral("Current Boxcat Events"), | ||
| 91 | tr("There are currently no events on boxcat.")}; | ||
| 92 | } | ||
| 93 | |||
| 94 | QString out; | ||
| 95 | |||
| 96 | if (global.has_value()) { | ||
| 97 | out += QStringLiteral("%1<br>").arg(QString::fromStdString(*global)); | ||
| 98 | } | ||
| 99 | |||
| 100 | for (const auto& [key, value] : map) { | ||
| 101 | out += QStringLiteral("%1<b>%2</b><br>%3") | ||
| 102 | .arg(out.isEmpty() ? QString{} : QStringLiteral("<br>")) | ||
| 103 | .arg(QString::fromStdString(key)) | ||
| 104 | .arg(FormatEventStatusString(value)); | ||
| 105 | } | ||
| 106 | return {QStringLiteral("Current Boxcat Events"), std::move(out)}; | ||
| 107 | } | ||
| 108 | |||
| 109 | void ConfigureService::OnBCATImplChanged() { | ||
| 110 | #ifdef YUZU_ENABLE_BOXCAT | ||
| 111 | const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat"); | ||
| 112 | ui->bcat_empty_header->setHidden(!boxcat); | ||
| 113 | ui->bcat_empty_label->setHidden(!boxcat); | ||
| 114 | ui->bcat_empty_header->setText(QString{}); | ||
| 115 | ui->bcat_empty_label->setText(tr("Yuzu is retrieving the latest boxcat status...")); | ||
| 116 | |||
| 117 | if (!boxcat) | ||
| 118 | return; | ||
| 119 | |||
| 120 | const auto future = QtConcurrent::run([this] { return BCATDownloadEvents(); }); | ||
| 121 | |||
| 122 | watcher.setFuture(future); | ||
| 123 | connect(&watcher, &QFutureWatcher<std::pair<QString, QString>>::finished, this, | ||
| 124 | [this] { OnUpdateBCATEmptyLabel(watcher.result()); }); | ||
| 125 | #endif | ||
| 126 | } | ||
| 127 | |||
| 128 | void ConfigureService::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) { | ||
| 129 | #ifdef YUZU_ENABLE_BOXCAT | ||
| 130 | const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat"); | ||
| 131 | if (boxcat) { | ||
| 132 | ui->bcat_empty_header->setText(string.first); | ||
| 133 | ui->bcat_empty_label->setText(string.second); | ||
| 134 | } | ||
| 135 | #endif | ||
| 136 | } | ||
diff --git a/src/yuzu/configuration/configure_service.h b/src/yuzu/configuration/configure_service.h new file mode 100644 index 000000000..f5c1b703a --- /dev/null +++ b/src/yuzu/configuration/configure_service.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <QFutureWatcher> | ||
| 9 | #include <QWidget> | ||
| 10 | |||
| 11 | namespace Ui { | ||
| 12 | class ConfigureService; | ||
| 13 | } | ||
| 14 | |||
| 15 | class ConfigureService : public QWidget { | ||
| 16 | Q_OBJECT | ||
| 17 | |||
| 18 | public: | ||
| 19 | explicit ConfigureService(QWidget* parent = nullptr); | ||
| 20 | ~ConfigureService() override; | ||
| 21 | |||
| 22 | void ApplyConfiguration(); | ||
| 23 | void RetranslateUi(); | ||
| 24 | |||
| 25 | private: | ||
| 26 | void SetConfiguration(); | ||
| 27 | |||
| 28 | std::pair<QString, QString> BCATDownloadEvents(); | ||
| 29 | void OnBCATImplChanged(); | ||
| 30 | void OnUpdateBCATEmptyLabel(std::pair<QString, QString> string); | ||
| 31 | |||
| 32 | std::unique_ptr<Ui::ConfigureService> ui; | ||
| 33 | QFutureWatcher<std::pair<QString, QString>> watcher{this}; | ||
| 34 | }; | ||
diff --git a/src/yuzu/configuration/configure_service.ui b/src/yuzu/configuration/configure_service.ui new file mode 100644 index 000000000..9668dd557 --- /dev/null +++ b/src/yuzu/configuration/configure_service.ui | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureService</class> | ||
| 4 | <widget class="QWidget" name="ConfigureService"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>433</width> | ||
| 10 | <height>561</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Form</string> | ||
| 15 | </property> | ||
| 16 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 17 | <item> | ||
| 18 | <layout class="QVBoxLayout" name="verticalLayout_3"> | ||
| 19 | <item> | ||
| 20 | <widget class="QGroupBox" name="groupBox"> | ||
| 21 | <property name="title"> | ||
| 22 | <string>BCAT</string> | ||
| 23 | </property> | ||
| 24 | <layout class="QGridLayout" name="gridLayout"> | ||
| 25 | <item row="1" column="1" colspan="2"> | ||
| 26 | <widget class="QLabel" name="label_2"> | ||
| 27 | <property name="maximumSize"> | ||
| 28 | <size> | ||
| 29 | <width>260</width> | ||
| 30 | <height>16777215</height> | ||
| 31 | </size> | ||
| 32 | </property> | ||
| 33 | <property name="text"> | ||
| 34 | <string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string> | ||
| 35 | </property> | ||
| 36 | <property name="wordWrap"> | ||
| 37 | <bool>true</bool> | ||
| 38 | </property> | ||
| 39 | </widget> | ||
| 40 | </item> | ||
| 41 | <item row="0" column="0"> | ||
| 42 | <widget class="QLabel" name="label"> | ||
| 43 | <property name="maximumSize"> | ||
| 44 | <size> | ||
| 45 | <width>16777215</width> | ||
| 46 | <height>16777215</height> | ||
| 47 | </size> | ||
| 48 | </property> | ||
| 49 | <property name="text"> | ||
| 50 | <string>BCAT Backend</string> | ||
| 51 | </property> | ||
| 52 | </widget> | ||
| 53 | </item> | ||
| 54 | <item row="3" column="1" colspan="2"> | ||
| 55 | <widget class="QLabel" name="bcat_empty_label"> | ||
| 56 | <property name="enabled"> | ||
| 57 | <bool>true</bool> | ||
| 58 | </property> | ||
| 59 | <property name="maximumSize"> | ||
| 60 | <size> | ||
| 61 | <width>260</width> | ||
| 62 | <height>16777215</height> | ||
| 63 | </size> | ||
| 64 | </property> | ||
| 65 | <property name="text"> | ||
| 66 | <string/> | ||
| 67 | </property> | ||
| 68 | <property name="alignment"> | ||
| 69 | <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> | ||
| 70 | </property> | ||
| 71 | <property name="wordWrap"> | ||
| 72 | <bool>true</bool> | ||
| 73 | </property> | ||
| 74 | </widget> | ||
| 75 | </item> | ||
| 76 | <item row="2" column="1" colspan="2"> | ||
| 77 | <widget class="QLabel" name="label_3"> | ||
| 78 | <property name="text"> | ||
| 79 | <string><html><head/><body><p><a href="https://yuzu-emu.org/help/feature/boxcat"><span style=" text-decoration: underline; color:#0000ff;">Learn more about BCAT, Boxcat, and Current Events</span></a></p></body></html></string> | ||
| 80 | </property> | ||
| 81 | <property name="openExternalLinks"> | ||
| 82 | <bool>true</bool> | ||
| 83 | </property> | ||
| 84 | </widget> | ||
| 85 | </item> | ||
| 86 | <item row="0" column="1" colspan="2"> | ||
| 87 | <widget class="QComboBox" name="bcat_source"/> | ||
| 88 | </item> | ||
| 89 | <item row="3" column="0"> | ||
| 90 | <widget class="QLabel" name="bcat_empty_header"> | ||
| 91 | <property name="text"> | ||
| 92 | <string/> | ||
| 93 | </property> | ||
| 94 | <property name="alignment"> | ||
| 95 | <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> | ||
| 96 | </property> | ||
| 97 | <property name="wordWrap"> | ||
| 98 | <bool>true</bool> | ||
| 99 | </property> | ||
| 100 | </widget> | ||
| 101 | </item> | ||
| 102 | </layout> | ||
| 103 | </widget> | ||
| 104 | </item> | ||
| 105 | </layout> | ||
| 106 | </item> | ||
| 107 | <item> | ||
| 108 | <spacer name="verticalSpacer"> | ||
| 109 | <property name="orientation"> | ||
| 110 | <enum>Qt::Vertical</enum> | ||
| 111 | </property> | ||
| 112 | <property name="sizeHint" stdset="0"> | ||
| 113 | <size> | ||
| 114 | <width>20</width> | ||
| 115 | <height>40</height> | ||
| 116 | </size> | ||
| 117 | </property> | ||
| 118 | </spacer> | ||
| 119 | </item> | ||
| 120 | </layout> | ||
| 121 | </widget> | ||
| 122 | <resources/> | ||
| 123 | <connections/> | ||
| 124 | </ui> | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f147044d9..2d82df739 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | #include "core/frontend/applets/general_frontend.h" | 22 | #include "core/frontend/applets/general_frontend.h" |
| 23 | #include "core/frontend/scope_acquire_window_context.h" | 23 | #include "core/frontend/scope_acquire_window_context.h" |
| 24 | #include "core/hle/service/acc/profile_manager.h" | 24 | #include "core/hle/service/acc/profile_manager.h" |
| 25 | #include "core/hle/service/am/applet_ae.h" | ||
| 26 | #include "core/hle/service/am/applet_oe.h" | ||
| 25 | #include "core/hle/service/am/applets/applets.h" | 27 | #include "core/hle/service/am/applets/applets.h" |
| 26 | #include "core/hle/service/hid/controllers/npad.h" | 28 | #include "core/hle/service/hid/controllers/npad.h" |
| 27 | #include "core/hle/service/hid/hid.h" | 29 | #include "core/hle/service/hid/hid.h" |
| @@ -83,6 +85,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 83 | #include "core/file_sys/submission_package.h" | 85 | #include "core/file_sys/submission_package.h" |
| 84 | #include "core/frontend/applets/software_keyboard.h" | 86 | #include "core/frontend/applets/software_keyboard.h" |
| 85 | #include "core/hle/kernel/process.h" | 87 | #include "core/hle/kernel/process.h" |
| 88 | #include "core/hle/service/am/am.h" | ||
| 86 | #include "core/hle/service/filesystem/filesystem.h" | 89 | #include "core/hle/service/filesystem/filesystem.h" |
| 87 | #include "core/hle/service/nfp/nfp.h" | 90 | #include "core/hle/service/nfp/nfp.h" |
| 88 | #include "core/hle/service/sm/sm.h" | 91 | #include "core/hle/service/sm/sm.h" |
| @@ -1674,6 +1677,11 @@ void GMainWindow::OnStartGame() { | |||
| 1674 | } | 1677 | } |
| 1675 | 1678 | ||
| 1676 | void GMainWindow::OnPauseGame() { | 1679 | void GMainWindow::OnPauseGame() { |
| 1680 | Core::System& system{Core::System::GetInstance()}; | ||
| 1681 | if (system.GetExitLock() && !ConfirmForceLockedExit()) { | ||
| 1682 | return; | ||
| 1683 | } | ||
| 1684 | |||
| 1677 | emu_thread->SetRunning(false); | 1685 | emu_thread->SetRunning(false); |
| 1678 | 1686 | ||
| 1679 | ui.action_Start->setEnabled(true); | 1687 | ui.action_Start->setEnabled(true); |
| @@ -1685,6 +1693,11 @@ void GMainWindow::OnPauseGame() { | |||
| 1685 | } | 1693 | } |
| 1686 | 1694 | ||
| 1687 | void GMainWindow::OnStopGame() { | 1695 | void GMainWindow::OnStopGame() { |
| 1696 | Core::System& system{Core::System::GetInstance()}; | ||
| 1697 | if (system.GetExitLock() && !ConfirmForceLockedExit()) { | ||
| 1698 | return; | ||
| 1699 | } | ||
| 1700 | |||
| 1688 | ShutdownGame(); | 1701 | ShutdownGame(); |
| 1689 | } | 1702 | } |
| 1690 | 1703 | ||
| @@ -2182,13 +2195,41 @@ bool GMainWindow::ConfirmChangeGame() { | |||
| 2182 | if (emu_thread == nullptr) | 2195 | if (emu_thread == nullptr) |
| 2183 | return true; | 2196 | return true; |
| 2184 | 2197 | ||
| 2185 | auto answer = QMessageBox::question( | 2198 | const auto answer = QMessageBox::question( |
| 2186 | this, tr("yuzu"), | 2199 | this, tr("yuzu"), |
| 2187 | tr("Are you sure you want to stop the emulation? Any unsaved progress will be lost."), | 2200 | tr("Are you sure you want to stop the emulation? Any unsaved progress will be lost."), |
| 2188 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | 2201 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); |
| 2189 | return answer != QMessageBox::No; | 2202 | return answer != QMessageBox::No; |
| 2190 | } | 2203 | } |
| 2191 | 2204 | ||
| 2205 | bool GMainWindow::ConfirmForceLockedExit() { | ||
| 2206 | if (emu_thread == nullptr) | ||
| 2207 | return true; | ||
| 2208 | |||
| 2209 | const auto answer = | ||
| 2210 | QMessageBox::question(this, tr("yuzu"), | ||
| 2211 | tr("The currently running application has requested yuzu to not " | ||
| 2212 | "exit.\n\nWould you like to bypass this and exit anyway?"), | ||
| 2213 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | ||
| 2214 | return answer != QMessageBox::No; | ||
| 2215 | } | ||
| 2216 | |||
| 2217 | void GMainWindow::RequestGameExit() { | ||
| 2218 | auto& sm{Core::System::GetInstance().ServiceManager()}; | ||
| 2219 | auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE"); | ||
| 2220 | auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE"); | ||
| 2221 | bool has_signalled = false; | ||
| 2222 | |||
| 2223 | if (applet_oe != nullptr) { | ||
| 2224 | applet_oe->GetMessageQueue()->RequestExit(); | ||
| 2225 | has_signalled = true; | ||
| 2226 | } | ||
| 2227 | |||
| 2228 | if (applet_ae != nullptr && !has_signalled) { | ||
| 2229 | applet_ae->GetMessageQueue()->RequestExit(); | ||
| 2230 | } | ||
| 2231 | } | ||
| 2232 | |||
| 2192 | void GMainWindow::filterBarSetChecked(bool state) { | 2233 | void GMainWindow::filterBarSetChecked(bool state) { |
| 2193 | ui.action_Show_Filter_Bar->setChecked(state); | 2234 | ui.action_Show_Filter_Bar->setChecked(state); |
| 2194 | emit(OnToggleFilterBar()); | 2235 | emit(OnToggleFilterBar()); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 7d16188cb..e942d1248 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -172,6 +172,8 @@ private: | |||
| 172 | */ | 172 | */ |
| 173 | bool ConfirmClose(); | 173 | bool ConfirmClose(); |
| 174 | bool ConfirmChangeGame(); | 174 | bool ConfirmChangeGame(); |
| 175 | bool ConfirmForceLockedExit(); | ||
| 176 | void RequestGameExit(); | ||
| 175 | void closeEvent(QCloseEvent* event) override; | 177 | void closeEvent(QCloseEvent* event) override; |
| 176 | 178 | ||
| 177 | private slots: | 179 | private slots: |
diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp index 7f7d247a3..43bad9678 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/yuzu/uisettings.cpp | |||
| @@ -9,6 +9,8 @@ namespace UISettings { | |||
| 9 | const Themes themes{{ | 9 | const Themes themes{{ |
| 10 | {"Default", "default"}, | 10 | {"Default", "default"}, |
| 11 | {"Dark", "qdarkstyle"}, | 11 | {"Dark", "qdarkstyle"}, |
| 12 | {"Colorful", "colorful"}, | ||
| 13 | {"Colorful Dark", "colorful_dark"}, | ||
| 12 | }}; | 14 | }}; |
| 13 | 15 | ||
| 14 | Values values = {}; | 16 | Values values = {}; |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index c57290006..a8eaf5f8c 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -24,7 +24,7 @@ struct Shortcut { | |||
| 24 | ContextualShortcut shortcut; | 24 | ContextualShortcut shortcut; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | using Themes = std::array<std::pair<const char*, const char*>, 2>; | 27 | using Themes = std::array<std::pair<const char*, const char*>, 4>; |
| 28 | extern const Themes themes; | 28 | extern const Themes themes; |
| 29 | 29 | ||
| 30 | struct GameDir { | 30 | struct GameDir { |
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index d82438502..1a812cb87 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -433,6 +433,11 @@ void Config::ReadValues() { | |||
| 433 | sdl2_config->Get("WebService", "web_api_url", "https://api.yuzu-emu.org"); | 433 | sdl2_config->Get("WebService", "web_api_url", "https://api.yuzu-emu.org"); |
| 434 | Settings::values.yuzu_username = sdl2_config->Get("WebService", "yuzu_username", ""); | 434 | Settings::values.yuzu_username = sdl2_config->Get("WebService", "yuzu_username", ""); |
| 435 | Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", ""); | 435 | Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", ""); |
| 436 | |||
| 437 | // Services | ||
| 438 | Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "boxcat"); | ||
| 439 | Settings::values.bcat_boxcat_local = | ||
| 440 | sdl2_config->GetBoolean("Services", "bcat_boxcat_local", false); | ||
| 436 | } | 441 | } |
| 437 | 442 | ||
| 438 | void Config::Reload() { | 443 | void Config::Reload() { |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index a6171c3ed..8d18a4a5a 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -251,6 +251,11 @@ web_api_url = https://api.yuzu-emu.org | |||
| 251 | yuzu_username = | 251 | yuzu_username = |
| 252 | yuzu_token = | 252 | yuzu_token = |
| 253 | 253 | ||
| 254 | [Services] | ||
| 255 | # The name of the backend to use for BCAT | ||
| 256 | # If this is set to 'boxcat' boxcat will be used, otherwise a null implementation will be used | ||
| 257 | bcat_backend = | ||
| 258 | |||
| 254 | [AddOns] | 259 | [AddOns] |
| 255 | # Used to disable add-ons | 260 | # Used to disable add-ons |
| 256 | # List of title IDs of games that will have add-ons disabled (separated by '|'): | 261 | # List of title IDs of games that will have add-ons disabled (separated by '|'): |