Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Savvanis SpyrosandClaude Opus 5.5 committed 2026-11-03 21:11:21 +02:00
commit 3c0ee17922
1068 files changed
+59831 -5025

No files matched your search

+43 -5
View File
@@ -32,7 +32,7 @@ permissions:
contents: read
concurrency:
group: build-${{ github.event_name }}-${{ github.event.pull_request.number || inputs.pr || github.ref }}
group: build-${{ github.event_name }}-${{ github.event.pull_request.number || inputs.pr || (github.event_name == 'push' && github.sha) || github.ref }}
cancel-in-progress: ${{ github.event_name != 'push' }}
env:
@@ -56,6 +56,7 @@ jobs:
relinker: ${{ steps.gate.outputs.relinker }}
register-context: ${{ steps.gate.outputs.register-context }}
write-watch: ${{ steps.gate.outputs.write-watch }}
edge-watch: ${{ steps.gate.outputs.edge-watch }}
mingw-host-tests: ${{ steps.gate.outputs.mingw-host-tests }}
full: ${{ steps.gate.outputs.full }}
relinker-hosts: ${{ steps.gate.outputs.relinker-hosts }}
@@ -139,6 +140,8 @@ jobs:
registerContext: edits('register-context') ||
touches('core/libs/tests/register_context/', 'core/libs/tests/RegisterContext.cpp', libc),
writeWatch: edits('write-watch') || touches('core/libs/tests/write_watch/', 'core/libs/tests/WriteWatch.cpp', libc),
edgeWatch: edits('edge-watch') || touches('core/libs/tests/edge_watch/', 'core/libs/tests/EdgeWatch.cpp',
'core/libs/prx/libkernel/Equeue/src/EdgeWatch.cpp', 'core/libs/prx/libkernel/Equeue/include/EdgeWatch.hpp', libc),
mingwHostTests: edits('eligibility') || edits('windows') || touches(
'core/CMakeLists.txt', 'core/libs/', 'cmake/', '3rdparty/', '.gitmodules', 'tools/build_mingw_host_only_tests.py',
'tools/build_changed_guest_tests.py', 'tools/configure_seed.py', 'tools/select_tests.py',
@@ -178,6 +181,7 @@ jobs:
core.setOutput('relinker', run.relinker);
core.setOutput('register-context', run.registerContext);
core.setOutput('write-watch', run.writeWatch);
core.setOutput('edge-watch', run.edgeWatch);
core.setOutput('mingw-host-tests', false);
core.setOutput('full', true);
core.setOutput('relinker-hosts', relinkerHosts(true, true));
@@ -268,6 +272,7 @@ jobs:
core.setOutput('relinker', relinker);
core.setOutput('register-context', registerContext);
core.setOutput('write-watch', writeWatch);
core.setOutput('edge-watch', run.edgeWatch);
core.setOutput('mingw-host-tests', !manual && run.mingwHostTests);
core.setOutput('full', full);
core.setOutput('relinker-hosts', relinkerHosts(full, linux));
@@ -328,10 +333,10 @@ jobs:
- if: runner.os == 'Windows'
run: echo 'C:\winlibs\mingw64\bin' >> "$GITHUB_PATH"
- if: ${{ matrix.architectures == 'x86_64' }}
run: sudo softwareupdate --install-rosetta --agree-to-license
run: arch -x86_64 /usr/bin/true || sudo softwareupdate --install-rosetta --agree-to-license
- run: cmake -S . -B build-relinker -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DANYPS5_RELINKER_ONLY=ON -DBUILD_TESTING=ON -DCMAKE_OSX_ARCHITECTURES=${{ matrix.architectures }}
- run: cmake --build build-relinker --parallel 3
- run: ctest --test-dir build-relinker --output-on-failure --timeout 120 --parallel 4
- run: ctest --test-dir build-relinker --output-on-failure --timeout 120 --parallel 4 --no-tests=error
relinker-asan:
needs: eligibility
@@ -648,7 +653,7 @@ jobs:
uses: actions/cache/restore@v6
with:
path: build/externals
key: ffmpeg-${{ runner.os }}-${{ steps.submodules.outputs.ffmpeg }}
key: ffmpeg-${{ runner.os }}-winlibs-${{ env.WINLIBS_ZIP }}-${{ steps.submodules.outputs.ffmpeg }}
- id: seed-cache
uses: actions/cache/restore@v6
with:
@@ -707,7 +712,7 @@ jobs:
- name: Build and run changed guest core/libs tests
if: github.event_name == 'pull_request'
shell: cmd
run: python tools/build_changed_guest_tests.py build changed.txt
run: python tools/build_changed_guest_tests.py build changed.txt --output-log ctest.log
- id: libs
if: github.event_name != 'pull_request'
shell: cmd
@@ -736,3 +741,36 @@ jobs:
awk '/Test +#[0-9]+: / && $NF == "sec" { for (i = 1; i <= NF; i++) if ($i ~ /^#[0-9]+:$/) name = $(i + 1); t = $(NF - 1) + 0; if (t > max[name]) max[name] = t }
END { for (name in max) if (max[name] > 30) printf "::warning title=Slow test::%s took %.1f s on %s; tests must finish in 30 s (CONTRIBUTING.md)\n", name, max[name], ENVIRON["RUNNER_OS"] }' ctest.log
edge-watch:
needs: eligibility
if: ${{ needs.eligibility.outputs.edge-watch == 'true' }}
strategy:
fail-fast: false
matrix:
os: [macos-15-intel, macos-15]
runs-on: ${{ matrix.os }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.eligibility.outputs.sha }}
persist-credentials: false
- name: Merge the pull request into main
if: ${{ needs.eligibility.outputs.head != '' }}
shell: bash
env:
PR_NUMBER: ${{ needs.eligibility.outputs.pr }}
PR_HEAD: ${{ needs.eligibility.outputs.head }}
run: |
read -ra numbers <<< "$PR_NUMBER"
read -ra heads <<< "$PR_HEAD"
refspecs=()
for number in "${numbers[@]}"; do refspecs+=("+refs/pull/$number/head:refs/remotes/pull/$number"); done
git fetch --no-tags --unshallow origin "${refspecs[@]}"
for i in "${!numbers[@]}"; do
if [ "$(git rev-parse "refs/remotes/pull/${numbers[i]}")" != "${heads[i]}" ]; then echo "::error::Pull request #${numbers[i]} has newer commits; start a new build"; exit 1; fi
if ! git -c user.name=ci -c user.email=ci@localhost merge --no-ff --no-edit "refs/remotes/pull/${numbers[i]}"; then echo "::error::Pull request #${numbers[i]} does not merge cleanly into main and the pull requests before it; rebase it first"; exit 1; fi
done
- run: cmake -S core/libs/tests/edge_watch -B build/edge-watch -DCMAKE_BUILD_TYPE=Release
- run: cmake --build build/edge-watch --parallel
- run: ctest --test-dir build/edge-watch --output-on-failure --repeat until-fail:3 --no-tests=error
+2 -2
View File
@@ -26,7 +26,7 @@ jobs:
run: |
cmake -S core/libs/tests/emscripten -B build-native -DCMAKE_BUILD_TYPE=Release
cmake --build build-native --parallel 2
ctest --test-dir build-native --output-on-failure
ctest --test-dir build-native --output-on-failure --no-tests=error
- uses: actions/setup-node@v6
with:
node-version: '26'
@@ -40,4 +40,4 @@ jobs:
source "$RUNNER_TEMP/emsdk/emsdk_env.sh"
emcmake cmake -S core/libs/tests/emscripten -B build-portable -DCMAKE_BUILD_TYPE=Release -DANYPS5_NODE="$ANYPS5_TEST_NODE"
cmake --build build-portable --parallel 2
ctest --test-dir build-portable --output-on-failure
ctest --test-dir build-portable --output-on-failure --no-tests=error
+1
View File
@@ -16,6 +16,7 @@ jobs:
steps:
- env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
gh pr list -R "$GITHUB_REPOSITORY" --label stale -L 1000 --json number,labels \
--jq '.[] | select(all(.labels[]; .name != "needs rebase")) | .number' |
+38
View File
@@ -0,0 +1,38 @@
name: Web release tools
on:
pull_request:
paths:
- .github/workflows/web-release-tools.yml
- demo/web/**
- tools/build_web.py
- tools/nid_names.py
- tools/package_headers.py
- tools/package_release.py
- tools/test_web.py
- tools/tests/test_build_web.py
- tools/tests/test_web_release.py
- core/relinker/relinker/tests/guest_import_fixtures.py
- core/relinker/relinker/tests/test_guest_intel_trampolines.py
- core/relinker/relinker/tests/test_guest_module_directories.py
- core/relinker/relinker/tests/test_linux_load_alignment.py
permissions:
contents: read
concurrency:
group: web-release-tools-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
release-tools:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Test web library assets
run: python3 tools/tests/test_build_web.py
- name: Test web release packaging
run: python3 tools/tests/test_web_release.py
+2
View File
@@ -35,6 +35,8 @@ jobs:
run: node demo/web/tests/archive-windows.test.mjs demo/web
- name: Test archive reserved names
run: node demo/web/tests/archive-reserved.test.mjs demo/web
- name: Test library manifest validation
run: node --test demo/web/tests/worker-manifest.test.mjs
- name: Check browser module syntax
run: |
node --check demo/web/app.mjs
+2 -2
View File
@@ -81,7 +81,7 @@ jobs:
uses: actions/cache/restore@v6
with:
path: build/externals
key: ffmpeg-${{ runner.os }}-${{ steps.submodules.outputs.ffmpeg }}
key: ffmpeg-${{ runner.os }}-msys2-${{ steps.submodules.outputs.ffmpeg }}
- shell: cmd
run: cmake -S . -B build %CONFIGURE% "-DANYPS5_AGC_EXECUTION_TESTS=F16ToF32Unpack;F64FmaSubnormals;RegistrationPrepareShutdown"
- if: steps.ffmpeg-cache.outputs.cache-hit != 'true'
@@ -99,7 +99,7 @@ jobs:
run: cmake --build build --target libs
- shell: cmd
working-directory: build
run: ctest --output-on-failure --timeout 120 --parallel 4 --output-log ctest.log --output-junit ctest.xml
run: ctest --output-on-failure --timeout 120 --parallel 4 --output-log ctest.log --output-junit ctest.xml --no-tests=error
- run: python tools/check_skips.py build/ctest.xml --job windows
- name: Report tests slower than 30 s
if: ${{ !cancelled() }}
+62 -1
View File
@@ -258,6 +258,8 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_unwrap_self.py)
add_test(NAME audit_dump COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_audit_dump.py)
add_test(NAME ffmpeg_cache_keys COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_ffmpeg_cache_keys.py)
foreach(shard RANGE 0 11)
if(shard EQUAL 0)
set(conventions_test_name conventions_function_bodies)
@@ -272,7 +274,18 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_performance_csv.py)
set_tests_properties(performance_csv PROPERTIES TIMEOUT 20)
add_test(NAME conventions_wrapped_declarations COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_wrapped_declarations.py)
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_wrapped_declarations.py WrappedDeclarationTests)
set_tests_properties(conventions_wrapped_declarations PROPERTIES TIMEOUT 30)
set(conventions_wrapped_declarations_source "${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_wrapped_declarations.py")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${conventions_wrapped_declarations_source}")
file(STRINGS "${conventions_wrapped_declarations_source}" conventions_wrapped_declarations_classes REGEX "^class [A-Za-z0-9_]*Tests\\(")
foreach(test_class IN LISTS conventions_wrapped_declarations_classes)
string(REGEX REPLACE "^class ([A-Za-z0-9_]+).*" "\\1" test_class "${test_class}")
if(NOT test_class STREQUAL "WrappedDeclarationTests")
add_test(NAME conventions_wrapped_declarations_${test_class} COMMAND ${Python3_EXECUTABLE} "${conventions_wrapped_declarations_source}" ${test_class})
set_tests_properties(conventions_wrapped_declarations_${test_class} PROPERTIES TIMEOUT 30)
endif()
endforeach()
add_test(NAME conventions_ci_gate COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_ci_gate.py)
add_test(NAME preview_pad_timeline COMMAND ${Python3_EXECUTABLE}
@@ -284,6 +297,8 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_base_ref.py)
add_test(NAME tools_configure_diff COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/tests/test_compare_configure_checks.py)
set_tests_properties(tools_configure_diff PROPERTIES TIMEOUT 20)
add_test(NAME ctest_no_tests_flag COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/tests/test_ctest_no_tests_flag.py)
set_tests_properties(ctest_no_tests_flag PROPERTIES TIMEOUT 20)
add_test(NAME conventions_doc_links COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_doc_links.py)
add_test(NAME conventions_unknown_nids COMMAND ${Python3_EXECUTABLE}
@@ -292,10 +307,18 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_debt_length.py)
add_test(NAME test_registration COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_test_registration.py)
add_test(NAME unbuilt_exports COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_unbuilt_exports.py)
add_test(NAME test_script_registration COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/check_test_registration.py --scripts)
add_test(NAME tools_sanitizer_json COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_sanitizer_json.py)
set_tests_properties(tools_sanitizer_json PROPERTIES TIMEOUT 20)
add_test(NAME build_eligibility COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_build_eligibility.py)
add_test(NAME tools_release_notes_check COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_release_notes_check.py)
set_tests_properties(tools_release_notes_check PROPERTIES TIMEOUT 20)
add_test(NAME check_skips_ctest COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_skips_ctest.py)
set_tests_properties(check_skips_ctest PROPERTIES TIMEOUT 30)
@@ -309,6 +332,8 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_relinker_fuzz_fixture_warnings.py)
add_test(NAME select_tests COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_select_tests.py)
add_test(NAME relinker_test_step COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_relinker_test_step.py)
add_test(NAME tools_self_inspect COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/tests/test_inspect_self.py)
set_tests_properties(tools_self_inspect PROPERTIES TIMEOUT 20)
add_test(NAME check_main_sync COMMAND ${Python3_EXECUTABLE}
@@ -372,6 +397,14 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_wrapped_exports.py)
add_test(NAME pr_overlap_own_branch COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_own_branch.py)
add_test(NAME main_sync_renames COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_main_sync_renames.py RenamedPathsTests.test_feature_rename_keeps_the_original_path)
set_tests_properties(main_sync_renames PROPERTIES TIMEOUT 20)
foreach(test_case IN ITEMS test_feature_rename_with_detection_disabled test_main_rename_keeps_the_original_path test_main_rename_with_detection_disabled)
add_test(NAME main_sync_renames_${test_case} COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_main_sync_renames.py RenamedPathsTests.${test_case})
set_tests_properties(main_sync_renames_${test_case} PROPERTIES TIMEOUT 20)
endforeach()
add_test(NAME pr_overlap_errors COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_errors.py)
add_test(NAME pr_overlap_branch_scan COMMAND ${Python3_EXECUTABLE}
@@ -397,6 +430,8 @@ if(BUILD_TESTING)
add_test(NAME pad_input COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pad_input.py)
set_tests_properties(pad_input PROPERTIES TIMEOUT 20)
add_test(NAME stale_conflicts_workflow COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_stale_conflicts_workflow.py)
add_test(NAME pad_timeline COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pad_timeline.py)
set_tests_properties(pad_timeline PROPERTIES TIMEOUT 20)
@@ -450,10 +485,16 @@ if(BUILD_TESTING)
"${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_env_reference.py" "EnvReferenceDiffTests.${test_case}")
set_tests_properties(conventions_env_reference_${test_case} PROPERTIES TIMEOUT 30)
endforeach()
add_test(NAME tools_annotation_symbols_json COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_annotation_symbols_json.py)
set_tests_properties(tools_annotation_symbols_json PROPERTIES TIMEOUT 20)
add_test(NAME conventions_body_bom COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_body_bom.py)
add_test(NAME conventions_blob_reads COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_blob_reads.py)
add_test(NAME ab_split_csv COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_ab_split_csv.py)
set_tests_properties(ab_split_csv PROPERTIES TIMEOUT 20)
add_test(NAME conventions_agent_files COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_agent_files.py)
add_test(NAME conventions_alignment COMMAND ${Python3_EXECUTABLE}
@@ -481,6 +522,26 @@ if(BUILD_TESTING)
endif()
endif()
endforeach()
set(unwrap_self_test_source "${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_unwrap_self.py")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${unwrap_self_test_source}")
file(STRINGS "${unwrap_self_test_source}" unwrap_self_cases REGEX "^class |^ def test_")
set(unwrap_self_first TRUE)
foreach(test_case IN LISTS unwrap_self_cases)
if(test_case MATCHES "^class ([A-Za-z0-9_]+)")
set(unwrap_self_class "${CMAKE_MATCH_1}")
else()
string(REGEX REPLACE "^ def (test_[A-Za-z0-9_]+).*" "\\1" test_case "${test_case}")
if(unwrap_self_first)
set_tests_properties(unwrap_self PROPERTIES
ENVIRONMENT "UNWRAP_SELF_TEST=${unwrap_self_class}.${test_case}" TIMEOUT 30)
set(unwrap_self_first FALSE)
else()
add_test(NAME unwrap_self_${unwrap_self_class}_${test_case} COMMAND ${Python3_EXECUTABLE}
"${unwrap_self_test_source}" "${unwrap_self_class}.${test_case}")
set_tests_properties(unwrap_self_${unwrap_self_class}_${test_case} PROPERTIES TIMEOUT 30)
endif()
endif()
endforeach()
add_test(NAME tools_headers_manifest COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/tests/test_public_headers_manifest.py)
set_tests_properties(tools_headers_manifest PROPERTIES TIMEOUT 20)
add_test(NAME conventions_pr_template COMMAND ${Python3_EXECUTABLE}
+1 -1
View File
@@ -1,4 +1,4 @@
**English** | [Português (Brasil)](docs/user/README.pt-BR.md) | [Español](docs/user/README.es.md) | [简体中文](docs/user/README.zh-CN.md) | [Русский](docs/user/README.ru.md)
**English** | [Português (Brasil)](docs/user/README.pt-BR.md) | [Español](docs/user/README.es.md) | [Italiano](docs/user/README.it.md) | [简体中文](docs/user/README.zh-CN.md) | [Русский](docs/user/README.ru.md)
# About
+46 -1
View File
@@ -302,6 +302,8 @@ include(prx/libSceFreeType/BuildInfo.cmake)
add_custom_target(libs DEPENDS ${PATCHED_OUTPUTS})
include(prx/libSceLibreSsl/ErrorQueue.cmake)
include(prx/libSceLibreSsl/MemoryBio.cmake)
include(prx/libSceLibreSsl/Cmac.cmake)
include(prx/libSceLibreSsl/ProtocolSelection.cmake)
@@ -361,6 +363,16 @@ if(BUILD_TESTING)
set_tests_properties(guest_kernel_sys_neo_mode PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel_sys>")
endif()
add_test_executable(guest_kernel_sys_constant_unknowns_tests tests/GuestKernelSysConstantUnknowns.cpp)
target_include_directories(guest_kernel_sys_constant_unknowns_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_kernel_sys_constant_unknowns_tests PRIVATE libkernel_sys libkernel libc)
configure_windows_unwind(guest_kernel_sys_constant_unknowns_tests)
add_test(NAME guest_kernel_sys_constant_unknowns COMMAND guest_kernel_sys_constant_unknowns_tests)
set_tests_properties(guest_kernel_sys_constant_unknowns PROPERTIES TIMEOUT 20)
if(WIN32)
set_tests_properties(guest_kernel_sys_constant_unknowns PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel_sys>")
endif()
add_test_executable(nid_buffer_validation_tests nid/tests/BufferValidation.cpp)
target_include_directories(nid_buffer_validation_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/nid/include)
target_compile_features(nid_buffer_validation_tests PRIVATE cxx_std_20)
@@ -687,6 +699,13 @@ if(BUILD_TESTING)
endif()
if(WIN32)
add_test_executable(windows_crash_thread_name_tests tests/WindowsCrashThreadName.cpp)
add_dependencies(windows_crash_thread_name_tests libc)
configure_host_test_executable(windows_crash_thread_name_tests)
add_test(NAME windows_crash_thread_name COMMAND windows_crash_thread_name_tests $<TARGET_FILE:libc>)
set_tests_properties(windows_crash_thread_name PROPERTIES TIMEOUT 20
PASS_REGULAR_EXPRESSION "on thread [0-9]+ 'a+Z'[^~]*thread [0-9]+ 'c+Y':"
FAIL_REGULAR_EXPRESSION "Zb|Yd|did not fault")
add_test_executable(windows_crash_text_tests tests/WindowsCrashText.cpp)
add_dependencies(windows_crash_text_tests libc)
if(MINGW)
@@ -696,6 +715,13 @@ if(BUILD_TESTING)
set_tests_properties(windows_crash_text PROPERTIES TIMEOUT 20
PASS_REGULAR_EXPRESSION "faulting[^~]*FATAL: unhandled exception 0xc0000005[^~]* \\[r12\\] \"allocation failed in the heap\"[\r\n]+ \\[r13\\] u\"LowLevelFatalError \\[File:Unknown\\] \\[Line: 42\\] Out of memory\"[\r\n]+ \\[r14\\] \"PAGE END\"[.][.][.]"
FAIL_REGULAR_EXPRESSION "\\[rbx\\] u?\"|did not fault")
add_test_executable(windows_integer_overflow_report_tests tests/WindowsIntegerOverflowReport.cpp)
add_dependencies(windows_integer_overflow_report_tests libc)
configure_host_test_executable(windows_integer_overflow_report_tests)
add_test(NAME windows_integer_overflow_report COMMAND windows_integer_overflow_report_tests $<TARGET_FILE:libc>)
set_tests_properties(windows_integer_overflow_report PROPERTIES TIMEOUT 20
PASS_REGULAR_EXPRESSION "dividing[^~]*FATAL: unhandled exception 0xc0000095"
FAIL_REGULAR_EXPRESSION "did not fault")
endif()
add_test_executable(guest_voice_port_attr_tests tests/GuestVoicePortAttr.cpp)
@@ -793,7 +819,7 @@ if(BUILD_TESTING)
target_include_directories(guest_np_common_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_np_common_tests PRIVATE libSceNpCommon libkernel libc)
configure_windows_unwind(guest_np_common_tests)
foreach(testCase IN ITEMS ids sync clock)
foreach(testCase IN ITEMS ids sync clock wake)
add_test(NAME guest_np_common_${testCase} COMMAND guest_np_common_tests ${testCase})
set_tests_properties(guest_np_common_${testCase} PROPERTIES TIMEOUT 20)
if(WIN32)
@@ -1116,6 +1142,16 @@ if(BUILD_TESTING)
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpCppWebApi>")
endif()
add_test_executable(guest_np_cpp_web_api_matches_tests tests/GuestNpCppWebApiMatches.cpp)
target_include_directories(guest_np_cpp_web_api_matches_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_np_cpp_web_api_matches_tests PRIVATE libSceNpCppWebApi libc)
configure_windows_unwind(guest_np_cpp_web_api_matches_tests)
add_test(NAME guest_np_cpp_web_api_matches COMMAND guest_np_cpp_web_api_matches_tests)
if(WIN32)
set_tests_properties(guest_np_cpp_web_api_matches PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpCppWebApi>")
endif()
add_test_executable(savedata_native_write_replacement_tests tests/SaveDataWriteReplacement.cpp)
target_include_directories(savedata_native_write_replacement_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(savedata_native_write_replacement_tests PRIVATE libSceSaveData.native)
@@ -1304,6 +1340,15 @@ if(BUILD_TESTING)
set_tests_properties(guest_gnm_neo_default_state PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceGnmDriverForNeoMode>")
endif()
add_test_executable(guest_division_prx_abi_tests tests/GuestDivisionPrxAbi.cpp nid/src/NidCompute.cpp nid/src/Sha1.cpp)
target_include_directories(guest_division_prx_abi_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/nid/include)
configure_host_test_executable(guest_division_prx_abi_tests)
target_link_libraries(guest_division_prx_abi_tests PRIVATE ${CMAKE_DL_LIBS})
add_custom_target(guest_division_prx_library DEPENDS ${LIBC_PATCHED})
add_dependencies(guest_division_prx_abi_tests guest_division_prx_library)
add_test(NAME guest_division_prx_abi COMMAND guest_division_prx_abi_tests $<TARGET_FILE:libc> ${PATCHED_DIR}/libc.prx)
set_tests_properties(guest_division_prx_abi PROPERTIES TIMEOUT 20)
endif()
include(prx/libSceFreeType/CurveBounds.cmake)
+36
View File
@@ -1820,6 +1820,8 @@ struct SaveDataEvent {
std::uint8_t reserved[40];
};
using SaveDataEventCallback = void (APS5_VABI *)(const SaveDataEvent* event, void* userdata);
struct SaveDataBackup {
std::int32_t user_id;
std::int32_t pad;
@@ -1829,6 +1831,40 @@ struct SaveDataBackup {
std::uint8_t reserved[32];
};
struct SaveDataCheckBackupData {
std::int32_t user_id;
std::int32_t pad;
const SceSaveDataTitleId* title_id;
const SceSaveDataDirName* dir_name;
SaveDataParam* param;
SaveDataIcon* icon;
std::uint8_t reserved[32];
};
struct SaveDataRestoreBackupData {
std::int32_t user_id;
std::int32_t pad;
const SceSaveDataTitleId* title_id;
const SceSaveDataDirName* dir_name;
const void* fingerprint;
std::uint32_t unused;
std::uint8_t reserved[32];
std::int32_t pad2;
};
static_assert(offsetof(SaveDataCheckBackupData, title_id) == 0x08);
static_assert(offsetof(SaveDataCheckBackupData, dir_name) == 0x10);
static_assert(offsetof(SaveDataCheckBackupData, param) == 0x18);
static_assert(offsetof(SaveDataCheckBackupData, icon) == 0x20);
static_assert(offsetof(SaveDataCheckBackupData, reserved) == 0x28);
static_assert(sizeof(SaveDataCheckBackupData) == 0x48);
static_assert(offsetof(SaveDataRestoreBackupData, title_id) == 0x08);
static_assert(offsetof(SaveDataRestoreBackupData, dir_name) == 0x10);
static_assert(offsetof(SaveDataRestoreBackupData, fingerprint) == 0x18);
static_assert(offsetof(SaveDataRestoreBackupData, unused) == 0x20);
static_assert(offsetof(SaveDataRestoreBackupData, reserved) == 0x24);
static_assert(offsetof(SaveDataRestoreBackupData, pad2) == 0x44);
static_assert(sizeof(SaveDataRestoreBackupData) == 0x48);
struct SaveDataConvert {
std::int32_t user_id;
std::int32_t pad;
+6 -3
View File
@@ -188,7 +188,10 @@ std::optional<TrieLocation> FindTrie(const std::vector<std::uint8_t>& binary, co
return found;
}
void ParseTrieNode(const std::vector<std::uint8_t>& data, std::size_t start, std::size_t end, std::size_t node, std::string& prefix, std::set<std::size_t>& visited, std::vector<MachOExport>& out) {
constexpr std::size_t kMaxExportTrieDepth = 1024;
void ParseTrieNode(const std::vector<std::uint8_t>& data, std::size_t start, std::size_t end, std::size_t node, std::string& prefix, std::set<std::size_t>& visited, std::vector<MachOExport>& out, std::size_t depth) {
if (depth > kMaxExportTrieDepth) throw std::runtime_error("export trie nesting too deep");
if (node >= end - start) throw std::runtime_error("export trie node out of bounds");
if (!visited.insert(node).second) throw std::runtime_error("export trie has a cycle");
std::size_t cursor = start + node;
@@ -216,7 +219,7 @@ void ParseTrieNode(const std::vector<std::uint8_t>& data, std::size_t start, std
const auto child = ReadUleb(data, cursor, end);
const auto length = prefix.size();
prefix += label;
ParseTrieNode(data, start, end, static_cast<std::size_t>(child), prefix, visited, out);
ParseTrieNode(data, start, end, static_cast<std::size_t>(child), prefix, visited, out, depth + 1);
prefix.resize(length);
}
}
@@ -227,7 +230,7 @@ std::vector<MachOExport> ParseTrie(const std::vector<std::uint8_t>& binary, std:
if (size == 0) return exports;
std::string prefix;
std::set<std::size_t> visited;
ParseTrieNode(binary, offset, std::size_t{offset} + size, 0, prefix, visited, exports);
ParseTrieNode(binary, offset, std::size_t{offset} + size, 0, prefix, visited, exports, 0);
return exports;
}
+3
View File
@@ -99,6 +99,9 @@ void PeNidPatcher::PatchNids(std::vector<std::uint8_t>& pe, const std::string& l
const std::size_t namesArrayOffset = RvaToOffset(pe, exportTable.AddressOfNames, peHeaderOffset, numberOfSections, sizeOfOptionalHeader);
const std::size_t ordinalsArrayOffset = RvaToOffset(pe, exportTable.AddressOfNameOrdinals, peHeaderOffset, numberOfSections, sizeOfOptionalHeader);
if (std::uint64_t{namesArrayOffset} + std::uint64_t{exportTable.NumberOfNames} * 4u > pe.size() ||
std::uint64_t{ordinalsArrayOffset} + std::uint64_t{exportTable.NumberOfNames} * 2u > pe.size())
throw std::runtime_error("export name tables out of file bounds");
std::vector<std::uint32_t> nameRvas(exportTable.NumberOfNames);
std::vector<std::string> names(exportTable.NumberOfNames);
+19 -2
View File
@@ -117,8 +117,8 @@ def dylib_command(path):
return struct.pack("<IIIIII", LC_LOAD_DYLIB, size, 24, 2, 0x10000, 0x10000) + name.ljust(size - 24, b"\0")
def build_dylib(exports, imports, signed=False, bind_opcodes=False):
trie = build_trie(exports)
def build_dylib(exports, imports, signed=False, bind_opcodes=False, trie=None):
trie = build_trie(exports) if trie is None else trie
fixups = build_fixups(imports)
linkedit = bytearray(trie + fixups)
trie_command = (struct.pack("<IIII", LC_DYLD_EXPORTS_TRIE, 16, PAGE, len(trie)))
@@ -270,6 +270,22 @@ def check_refusals(patcher, directory):
assert result.returncode != 0 and "signed Mach-O images cannot grow linkedit data" in result.stdout + result.stderr, (result.stdout, result.stderr)
def chain_trie(depth):
def fixed_uleb(value):
return bytes([((value >> (7 * index)) & 0x7F) | 0x80 for index in range(4)] + [(value >> 28) & 0x7F])
node_size = 9
nodes = [b"\x00\x01a\x00" + fixed_uleb(node_size * (index + 1)) for index in range(depth - 1)]
nodes.append(b"\x02\x00\x00\x00")
return b"".join(nodes) + bytes(-sum(map(len, nodes)) % 8)
def check_deep_trie(patcher, directory):
image = build_dylib([("_puts_nid_postfix", 0, 0x100)], [], trie=chain_trie(200000))
result, _ = patch(patcher, directory, "deep-trie.dylib", image)
assert result.returncode != 0 and "export trie nesting too deep" in result.stdout + result.stderr, (result.returncode, result.stdout, result.stderr)
def check_short_imports(patcher, directory):
imports = [("_sceXy", 1), ("_malloc", 2), ("_sceKernelFoo", 1), ("_sceNetRecv", 1)]
result, path = patch(patcher, directory, "short.dylib", build_dylib([("_puts_nid_postfix", 0, 0x100)], imports))
@@ -297,6 +313,7 @@ def main():
check_preserved(patcher, directory)
check_export_list(patcher, directory)
check_refusals(patcher, directory)
check_deep_trie(patcher, directory)
print("NID patcher Mach-O tests passed")
+13
View File
@@ -2,6 +2,7 @@ import struct
import subprocess
import sys
import tempfile
import time
import unittest
from pathlib import Path
from types import SimpleNamespace
@@ -564,6 +565,18 @@ class LibraryImportTests(unittest.TestCase):
self.assertIn("delay-loaded", result.stdout + result.stderr)
self.assertEqual(patched, image)
def test_huge_name_count_is_rejected_before_allocation(self):
for count in (0xFFFFFFFF, 0x40000000):
with self.subTest(count=count):
image = self.library(["puts"])
struct.pack_into("<I", image, 0x600 + 24, count)
start = time.monotonic()
result, patched = self.patch(image)
self.assertLess(time.monotonic() - start, 10)
self.assertNotEqual(result.returncode, 0)
self.assertIn("export name tables out of file bounds", result.stdout + result.stderr)
self.assertEqual(patched, image)
if __name__ == "__main__":
unittest.main()
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,272 @@
#pragma once
#include "SceTypes.hpp"
extern "C" {
int APS5_VABI libAacsUnknown__plus_0gHTNd4xs4_nid_no_patch();
int APS5_VABI libAacsUnknown__plus_3dyyKZMTyw_nid_no_patch();
int APS5_VABI libAacsUnknown__plus_7ZoZWbIhlE_nid_no_patch();
int APS5_VABI libAacsUnknown__plus_CiBKXuK8c8_nid_no_patch();
int APS5_VABI libAacsUnknown__plus_RinEsZfOmw_nid_no_patch();
int APS5_VABI libAacsUnknown__plus_XVwfwtkAi4_nid_no_patch();
int APS5_VABI libAacsUnknown__minus_2QNA1pCQqU_nid_no_patch();
int APS5_VABI libAacsUnknown__minus_kAJeMNy_minus_0E_nid_no_patch();
int APS5_VABI libAacsUnknown__minus_lknLNU2NAU_nid_no_patch();
int APS5_VABI libAacsUnknown__minus_xuQAxlUvmk_nid_no_patch();
int APS5_VABI libAacsUnknown_0bhkzdWU6Y4_nid_no_patch();
int APS5_VABI libAacsUnknown_0oisD9Dr3FI_nid_no_patch();
int APS5_VABI libAacsUnknown_12CP5PHvlgs_nid_no_patch();
int APS5_VABI libAacsUnknown_15QPrQC1usM_nid_no_patch();
int APS5_VABI libAacsUnknown_1CNq2v6hoig_nid_no_patch();
int APS5_VABI libAacsUnknown_1aMnfYcnn1I_nid_no_patch();
int APS5_VABI libAacsUnknown_1bzdduTshZ4_nid_no_patch();
int APS5_VABI libAacsUnknown_1eNkqOSGM_plus_A_nid_no_patch();
int APS5_VABI libAacsUnknown_1hyWLxCZ_minus_X8_nid_no_patch();
int APS5_VABI libAacsUnknown_1pvpAK9Rg1k_nid_no_patch();
int APS5_VABI libAacsUnknown_23BaEjHuFUA_nid_no_patch();
int APS5_VABI libAacsUnknown_2HaRuPcSWtE_nid_no_patch();
int APS5_VABI libAacsUnknown_2KQWcFTN8ZE_nid_no_patch();
int APS5_VABI libAacsUnknown_2YklE8dG4v8_nid_no_patch();
int APS5_VABI libAacsUnknown_38ZtQUT4lMs_nid_no_patch();
int APS5_VABI libAacsUnknown_3LFB_minus_Ey4DUk_nid_no_patch();
int APS5_VABI libAacsUnknown_3OYBQUy9yVI_nid_no_patch();
int APS5_VABI libAacsUnknown_3ZqZuNL3qrM_nid_no_patch();
int APS5_VABI libAacsUnknown_3odIlZa6t2I_nid_no_patch();
int APS5_VABI libAacsUnknown_4IQhgxl103g_nid_no_patch();
int APS5_VABI libAacsUnknown_4r3seYGdIK0_nid_no_patch();
int APS5_VABI AacsPermissionActivate();
int APS5_VABI libAacsUnknown_54hkTYBIxqs_nid_no_patch();
int APS5_VABI AacsBusDecrypt();
int APS5_VABI AacsModuleStop();
int APS5_VABI libAacsUnknown_6ToH2wFRWf4_nid_no_patch();
int APS5_VABI libAacsUnknown_6XcWJGADJeU_nid_no_patch();
int APS5_VABI libAacsUnknown_753FlqNkJlM_nid_no_patch();
int APS5_VABI libAacsUnknown_7ETkLi9auE0_nid_no_patch();
int APS5_VABI libAacsUnknown_7KCIejRxaB0_nid_no_patch();
int APS5_VABI AacsDecrypt();
int APS5_VABI libAacsUnknown_7eM7N1Anox4_nid_no_patch();
int APS5_VABI libAacsUnknown_7iLrHfVzuvs_nid_no_patch();
int APS5_VABI libAacsUnknown_7qIZfzr0Dgk_nid_no_patch();
int APS5_VABI libAacsUnknown_85kBXEP1moE_nid_no_patch();
int APS5_VABI libAacsUnknown_8Gj9M3o_minus_rrY_nid_no_patch();
int APS5_VABI libAacsUnknown_8TJlScPxUa8_nid_no_patch();
int APS5_VABI libAacsUnknown_8YaNJTuYU_plus_g_nid_no_patch();
int APS5_VABI libAacsUnknown_9S1fVMePqpI_nid_no_patch();
int APS5_VABI libAacsUnknown_9UJqpmNn494_nid_no_patch();
int APS5_VABI libAacsUnknown_9eTs6_minus_zAOJs_nid_no_patch();
int APS5_VABI libAacsUnknown_9rQgwWQB9NE_nid_no_patch();
int APS5_VABI libAacsUnknown_AVRC3P8reF0_nid_no_patch();
int APS5_VABI libAacsUnknown_Apl9mjDSCE0_nid_no_patch();
int APS5_VABI libAacsUnknown_B10mYlgLwMM_nid_no_patch();
int APS5_VABI libAacsUnknown_BFdZY3ocsJo_nid_no_patch();
int APS5_VABI libAacsUnknown_BO_plus_NBS2KrZc_nid_no_patch();
int APS5_VABI libAacsUnknown_BaMuhhCt_minus_dQ_nid_no_patch();
int APS5_VABI AacsPermissionCheck();
int APS5_VABI libAacsUnknown_DWJK8GjbNHo_nid_no_patch();
int APS5_VABI AacsModuleInit();
int APS5_VABI libAacsUnknown_EBGsSrhNRnM_nid_no_patch();
int APS5_VABI libAacsUnknown_EFpFjkHGewY_nid_no_patch();
int APS5_VABI libAacsUnknown_EIEQ4mWz5sU_nid_no_patch();
int APS5_VABI libAacsUnknown_ELsVqt8cS3Q_nid_no_patch();
int APS5_VABI libAacsUnknown_EQWDDRWfuOU_nid_no_patch();
int APS5_VABI libAacsUnknown_ESDneLy_plus_ExU_nid_no_patch();
int APS5_VABI libAacsUnknown_ETDNd_minus_CDbkc_nid_no_patch();
int APS5_VABI libAacsUnknown_EX5Y3UepfU4_nid_no_patch();
int APS5_VABI libAacsUnknown_EgaEREMnudw_nid_no_patch();
int APS5_VABI libAacsUnknown_FA1OyesdYiA_nid_no_patch();
int APS5_VABI libAacsUnknown_FEgD32GcLdM_nid_no_patch();
int APS5_VABI libAacsUnknown_FEi5mHUWB0M_nid_no_patch();
int APS5_VABI libAacsUnknown_FHWdAzU_minus_rRI_nid_no_patch();
int APS5_VABI libAacsUnknown_Fl0RrZ7B27g_nid_no_patch();
int APS5_VABI libAacsUnknown_G4zfSFYC1f8_nid_no_patch();
int APS5_VABI libAacsUnknown_GD6inRSAHfo_nid_no_patch();
int APS5_VABI libAacsUnknown_GWA91aXeU1Y_nid_no_patch();
int APS5_VABI libAacsUnknown_GXLnqJJ85dM_nid_no_patch();
int APS5_VABI libAacsUnknown_GpsjAdWq5hk_nid_no_patch();
int APS5_VABI libAacsUnknown_HXafooMuNTY_nid_no_patch();
int APS5_VABI libAacsUnknown_HhIFaBlod8A_nid_no_patch();
int APS5_VABI libAacsUnknown_HmdBrUh2Xz4_nid_no_patch();
int APS5_VABI libAacsUnknown_HuTXuHqMrVE_nid_no_patch();
int APS5_VABI libAacsUnknown_ILwfo94p_minus_ng_nid_no_patch();
int APS5_VABI libAacsUnknown_Iofb1lKwTNA_nid_no_patch();
int APS5_VABI libAacsUnknown_IxvgFI5JtxE_nid_no_patch();
int APS5_VABI libAacsUnknown_JXvlGrRcNlg_nid_no_patch();
int APS5_VABI libAacsUnknown_Jmviii0cDro_nid_no_patch();
int APS5_VABI libAacsUnknown_JolZPea7pio_nid_no_patch();
int APS5_VABI libAacsUnknown_JqeAwcly1Lc_nid_no_patch();
int APS5_VABI libAacsUnknown_JqrjeblDpqo_nid_no_patch();
int APS5_VABI libAacsUnknown_KG5C7s3p_plus_mM_nid_no_patch();
int APS5_VABI libAacsUnknown_KLxEGrIPbbo_nid_no_patch();
int APS5_VABI libAacsUnknown_L6tIkKT5Vdg_nid_no_patch();
int APS5_VABI libAacsUnknown_LFpG7wYNZ_plus_I_nid_no_patch();
int APS5_VABI libAacsUnknown_LT_minus_aek5dBRQ_nid_no_patch();
int APS5_VABI libAacsUnknown_LTIva3bGCXI_nid_no_patch();
int APS5_VABI libAacsUnknown_MCPkB4DYvAM_nid_no_patch();
int APS5_VABI libAacsUnknown_MILG1Bi10BQ_nid_no_patch();
int APS5_VABI libAacsUnknown_MLHm3u_minus_UfPk_nid_no_patch();
int APS5_VABI libAacsUnknown_MRMYIqUmmcQ_nid_no_patch();
int APS5_VABI libAacsUnknown_MVoCh7vg9Bk_nid_no_patch();
int APS5_VABI libAacsUnknown_NK6Ke_minus_y45cI_nid_no_patch();
int APS5_VABI libAacsUnknown_NL6gDScOFl8_nid_no_patch();
int APS5_VABI libAacsUnknown_NOWYNS5AnRg_nid_no_patch();
int APS5_VABI libAacsUnknown_NRv4EFuYq9I_nid_no_patch();
int APS5_VABI libAacsUnknown_NSph9LkyLmI_nid_no_patch();
int APS5_VABI libAacsUnknown_OI1om0rmEYk_nid_no_patch();
int APS5_VABI libAacsUnknown_OOrYw04s_plus_VU_nid_no_patch();
int APS5_VABI libAacsUnknown_ObJaLtAn3TM_nid_no_patch();
int APS5_VABI AacsModuleStart();
int APS5_VABI libAacsUnknown_Ozlqilsf3Tw_nid_no_patch();
int APS5_VABI libAacsUnknown_PHgHus4a3M0_nid_no_patch();
int APS5_VABI libAacsUnknown_PUDoXp1l_minus_Po_nid_no_patch();
int APS5_VABI libAacsUnknown_Q2eGSNdsRq0_nid_no_patch();
int APS5_VABI libAacsUnknown_Q3vOGHtSk9Y_nid_no_patch();
int APS5_VABI libAacsUnknown_Q74CET98b04_nid_no_patch();
int APS5_VABI libAacsUnknown_QCq8qc_plus_kt7g_nid_no_patch();
int APS5_VABI libAacsUnknown_QDc8xyN5AQw_nid_no_patch();
int APS5_VABI libAacsUnknown_QabaLwU3b9o_nid_no_patch();
int APS5_VABI libAacsUnknown_RI7fQrbtZko_nid_no_patch();
int APS5_VABI libAacsUnknown_RZFK7f3Oi24_nid_no_patch();
int APS5_VABI libAacsUnknown_RkkCme3dsyo_nid_no_patch();
int APS5_VABI libAacsUnknown_SJ9GmthhZDk_nid_no_patch();
int APS5_VABI libAacsUnknown_SjEjF5V5XHc_nid_no_patch();
int APS5_VABI libAacsUnknown_SjewOoJlr9c_nid_no_patch();
int APS5_VABI libAacsUnknown_TK5prfVU4b0_nid_no_patch();
int APS5_VABI libAacsUnknown_TQCLQjHkkW0_nid_no_patch();
int APS5_VABI libAacsUnknown_TuTNDTTOXHo_nid_no_patch();
int APS5_VABI libAacsUnknown_U2zlEU4AhRk_nid_no_patch();
int APS5_VABI libAacsUnknown_U6RAXYIdJJE_nid_no_patch();
int APS5_VABI libAacsUnknown_UArM6xy6B3g_nid_no_patch();
int APS5_VABI libAacsUnknown_UMZJ2F8Lr4o_nid_no_patch();
int APS5_VABI libAacsUnknown_UqqcPoUuAqE_nid_no_patch();
int APS5_VABI AacsPermissionGetNonce();
int APS5_VABI libAacsUnknown_VnixdJqGnjU_nid_no_patch();
int APS5_VABI libAacsUnknown_WOxxWZjZMfQ_nid_no_patch();
int APS5_VABI libAacsUnknown_WaOsDN_plus_9lZg_nid_no_patch();
int APS5_VABI libAacsUnknown_WknurdpKTqo_nid_no_patch();
int APS5_VABI libAacsUnknown_WrEjdzfOo2I_nid_no_patch();
int APS5_VABI libAacsUnknown_XQuTyX2WprY_nid_no_patch();
int APS5_VABI libAacsUnknown_XUL7r8v2Q3Y_nid_no_patch();
int APS5_VABI libAacsUnknown_XbP3p94ujkg_nid_no_patch();
int APS5_VABI libAacsUnknown_XhMh4CEdKGU_nid_no_patch();
int APS5_VABI libAacsUnknown_Xokc3inTVbM_nid_no_patch();
int APS5_VABI libAacsUnknown_XrkLs6PFhac_nid_no_patch();
int APS5_VABI libAacsUnknown_Xy748BBvB2w_nid_no_patch();
int APS5_VABI libAacsUnknown_YDl9jLvW_plus_SM_nid_no_patch();
int APS5_VABI libAacsUnknown_YOlHXj4rrzQ_nid_no_patch();
int APS5_VABI libAacsUnknown_Yqt0NzhE_minus_eU_nid_no_patch();
int APS5_VABI libAacsUnknown_Z9yhz8_plus_DS3k_nid_no_patch();
int APS5_VABI libAacsUnknown_ZCRVIAxld6o_nid_no_patch();
int APS5_VABI libAacsUnknown_ZEdbi75pkX0_nid_no_patch();
int APS5_VABI libAacsUnknown_ZUEIg4QZJ_plus_k_nid_no_patch();
int APS5_VABI libAacsUnknown_ZnJgSGpLzGs_nid_no_patch();
int APS5_VABI libAacsUnknown_a3D2_minus_Eh_minus_DW8_nid_no_patch();
int APS5_VABI libAacsUnknown_aOX5VPrNfqo_nid_no_patch();
int APS5_VABI libAacsUnknown_aXeMNVrwOTw_nid_no_patch();
int APS5_VABI libAacsUnknown_aZmsxlYbNes_nid_no_patch();
int APS5_VABI libAacsUnknown_aacj8q7PTFI_nid_no_patch();
int APS5_VABI libAacsUnknown_b0ZC6N9oQlU_nid_no_patch();
int APS5_VABI libAacsUnknown_bHqBriHrgXA_nid_no_patch();
int APS5_VABI libAacsUnknown_bQl9nHS7Jgg_nid_no_patch();
int APS5_VABI libAacsUnknown_bQmoqxNo0rE_nid_no_patch();
int APS5_VABI libAacsUnknown_c04ksdAcncM_nid_no_patch();
int APS5_VABI AacsSelectKeyFrom();
int APS5_VABI libAacsUnknown_c9tUe3nNpxo_nid_no_patch();
int APS5_VABI libAacsUnknown_cI0YmNGV22E_nid_no_patch();
int APS5_VABI libAacsUnknown_cnGJD38STwQ_nid_no_patch();
int APS5_VABI AacsModuleTerm();
int APS5_VABI libAacsUnknown_e_minus_SciZxh1HY_nid_no_patch();
int APS5_VABI libAacsUnknown_e_minus_yS_plus_nlBtlE_nid_no_patch();
int APS5_VABI libAacsUnknown_e0UQuzSUkI8_nid_no_patch();
int APS5_VABI libAacsUnknown_e5qwpKPf1aI_nid_no_patch();
int APS5_VABI libAacsUnknown_eRXHQokealY_nid_no_patch();
int APS5_VABI libAacsUnknown_egjNL_minus_sA_minus_s0_nid_no_patch();
int APS5_VABI libAacsUnknown_eoQNtjg5QyQ_nid_no_patch();
int APS5_VABI libAacsUnknown_f5FWQj_minus__minus_MwM_nid_no_patch();
int APS5_VABI libAacsUnknown_fWmfE_minus_A0k90_nid_no_patch();
int APS5_VABI libAacsUnknown_fkra1GmOMmQ_nid_no_patch();
int APS5_VABI libAacsUnknown_flzhCbf4xnw_nid_no_patch();
int APS5_VABI libAacsUnknown_gAV79zVGfzI_nid_no_patch();
int APS5_VABI libAacsUnknown_gPhz2sY_plus_lHM_nid_no_patch();
int APS5_VABI libAacsUnknown_gTXUpBIgmcg_nid_no_patch();
int APS5_VABI libAacsUnknown_gmOvd0UR6rk_nid_no_patch();
int APS5_VABI libAacsUnknown_h6JW5ZErMHE_nid_no_patch();
int APS5_VABI libAacsUnknown_hDCeckXsgIw_nid_no_patch();
int APS5_VABI libAacsUnknown_hFXdc25NmT4_nid_no_patch();
int APS5_VABI libAacsUnknown_hWhpklSoZ7g_nid_no_patch();
int APS5_VABI libAacsUnknown_hct40EnKHyM_nid_no_patch();
int APS5_VABI libAacsUnknown_i0ZMaUuKzkE_nid_no_patch();
int APS5_VABI libAacsUnknown_iIgtd05IlbA_nid_no_patch();
int APS5_VABI libAacsUnknown_iJ3zPE02P1w_nid_no_patch();
int APS5_VABI libAacsUnknown_iOLQbPwqsJU_nid_no_patch();
int APS5_VABI libAacsUnknown_igIuBDqdlZo_nid_no_patch();
int APS5_VABI libAacsUnknown_j0quzCtmBr4_nid_no_patch();
int APS5_VABI libAacsUnknown_jXZJmZu3ihs_nid_no_patch();
int APS5_VABI libAacsUnknown_jdd4KuD7bOg_nid_no_patch();
int APS5_VABI libAacsUnknown_jpKit8Qv76g_nid_no_patch();
int APS5_VABI AacsPermissionSet();
int APS5_VABI libAacsUnknown_kX1hCR9FDo0_nid_no_patch();
int APS5_VABI libAacsUnknown_kYQis7lBy_plus_U_nid_no_patch();
int APS5_VABI libAacsUnknown_kaxfKxeOvbU_nid_no_patch();
int APS5_VABI libAacsUnknown_keNMJVznBe0_nid_no_patch();
int APS5_VABI libAacsUnknown_kk8ELO4Y2Fo_nid_no_patch();
int APS5_VABI libAacsUnknown_l18OOzQPPKo_nid_no_patch();
int APS5_VABI libAacsUnknown_l8uscgUMuWE_nid_no_patch();
int APS5_VABI libAacsUnknown_ldkS5zx7P6s_nid_no_patch();
int APS5_VABI libAacsUnknown_llme91x0I_minus_k_nid_no_patch();
int APS5_VABI libAacsUnknown_lq8QnjYyTGQ_nid_no_patch();
int APS5_VABI libAacsUnknown_mExJcLz6QWE_nid_no_patch();
int APS5_VABI libAacsUnknown_mR3leJVBYbw_nid_no_patch();
int APS5_VABI libAacsUnknown_mbKaZoh30DM_nid_no_patch();
int APS5_VABI libAacsUnknown_mlZY17mBv9M_nid_no_patch();
int APS5_VABI libAacsUnknown_mnf5OTi_minus_urc_nid_no_patch();
int APS5_VABI libAacsUnknown_moU18PvmqEU_nid_no_patch();
int APS5_VABI AacsPermissionInit();
int APS5_VABI libAacsUnknown_o33b_plus_5keZic_nid_no_patch();
int APS5_VABI libAacsUnknown_oJobSSDssQw_nid_no_patch();
int APS5_VABI libAacsUnknown_oU59phxP5U4_nid_no_patch();
int APS5_VABI libAacsUnknown_oij_plus_E5v8qjM_nid_no_patch();
int APS5_VABI libAacsUnknown_p8Lv5g5o9pY_nid_no_patch();
int APS5_VABI libAacsUnknown_p9sZ84FK_minus_qw_nid_no_patch();
int APS5_VABI libAacsUnknown_ptrqNcGG0eM_nid_no_patch();
int APS5_VABI libAacsUnknown_qFchDSE1J3o_nid_no_patch();
int APS5_VABI libAacsUnknown_qGMyKAQhniM_nid_no_patch();
int APS5_VABI libAacsUnknown_qKmr8FI7Too_nid_no_patch();
int APS5_VABI libAacsUnknown_qPi2nzCUYiQ_nid_no_patch();
int APS5_VABI libAacsUnknown_qpebtLhTJBc_nid_no_patch();
int APS5_VABI libAacsUnknown_r960kCkFF3I_nid_no_patch();
int APS5_VABI libAacsUnknown_rMR6nG8LdyQ_nid_no_patch();
int APS5_VABI libAacsUnknown_rOM7gjFX3nM_nid_no_patch();
int APS5_VABI libAacsUnknown_raaoezfuSqY_nid_no_patch();
int APS5_VABI libAacsUnknown_ruidkq8amJE_nid_no_patch();
int APS5_VABI libAacsUnknown_s_plus_BvUCe_plus_t_plus_I_nid_no_patch();
int APS5_VABI libAacsUnknown_s6CgM5B_plus_8zc_nid_no_patch();
int APS5_VABI libAacsUnknown_sjNkMwi80Os_nid_no_patch();
int APS5_VABI libAacsUnknown_sv8IiSJQ0Mo_nid_no_patch();
int APS5_VABI libAacsUnknown_tPYLJSOXQ8k_nid_no_patch();
int APS5_VABI libAacsUnknown_tWHiNKLyUn4_nid_no_patch();
int APS5_VABI libAacsUnknown_uG7mSoxfjL0_nid_no_patch();
int APS5_VABI libAacsUnknown_ujgxfJSpLrc_nid_no_patch();
int APS5_VABI libAacsUnknown_ulInPmGONKo_nid_no_patch();
int APS5_VABI libAacsUnknown_uvJDUwXFtw0_nid_no_patch();
int APS5_VABI libAacsUnknown_uvLxjEqwYKk_nid_no_patch();
int APS5_VABI libAacsUnknown_v5IGfww3qSA_nid_no_patch();
int APS5_VABI libAacsUnknown_vM2spx6P6RU_nid_no_patch();
int APS5_VABI libAacsUnknown_vcFZSn_plus_m4_minus_o_nid_no_patch();
int APS5_VABI libAacsUnknown_w4Go9bJ_minus_JGQ_nid_no_patch();
int APS5_VABI libAacsUnknown_x34TWztyXy8_nid_no_patch();
int APS5_VABI libAacsUnknown_x82CfygyUPA_nid_no_patch();
int APS5_VABI libAacsUnknown_xQoCQNT3skQ_nid_no_patch();
int APS5_VABI libAacsUnknown_y56l_minus_E5S0Qs_nid_no_patch();
int APS5_VABI libAacsUnknown_y5OsRUqNoX4_nid_no_patch();
int APS5_VABI libAacsUnknown_yFNWXXeNxF0_nid_no_patch();
int APS5_VABI AacsUpdateKeyArea();
int APS5_VABI libAacsUnknown_yZjYlfcfEFE_nid_no_patch();
int APS5_VABI libAacsUnknown_yaNpz6jnOzE_nid_no_patch();
int APS5_VABI libAacsUnknown_yrqEHk366AM_nid_no_patch();
int APS5_VABI libAacsUnknown_z0b7NKDfWpo_nid_no_patch();
int APS5_VABI libAacsUnknown_zgZWaxsJGyM_nid_no_patch();
int APS5_VABI libAacsUnknown_zreU_plus_KU3nLw_nid_no_patch();
int APS5_VABI libAacsUnknown_zt4Xv_minus_4fjx0_nid_no_patch();
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "prx/libAacs/include/InventoryExports.hpp"
+328
View File
@@ -0,0 +1,328 @@
#include "prx/libCss/include/InventoryExports.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libc/include/general/ExportMacros.hpp"
extern "C" {
int APS5_VABI libCssUnknown__plus_zpMhCilHTQ_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("+zpMhCilHTQ", libCssUnknown__plus_zpMhCilHTQ_nid_no_patch);
int APS5_VABI libCssUnknown__minus_WR4_minus_J79nn0_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("-WR4-J79nn0", libCssUnknown__minus_WR4_minus_J79nn0_nid_no_patch);
int APS5_VABI libCssUnknown_45oyUIl85dg_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("45oyUIl85dg", libCssUnknown_45oyUIl85dg_nid_no_patch);
int APS5_VABI libCssUnknown_4qq5OHYaFU8_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("4qq5OHYaFU8", libCssUnknown_4qq5OHYaFU8_nid_no_patch);
int APS5_VABI libCssUnknown_6BDNwI1e59c_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("6BDNwI1e59c", libCssUnknown_6BDNwI1e59c_nid_no_patch);
int APS5_VABI libCssUnknown_6QhXfVttAyU_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("6QhXfVttAyU", libCssUnknown_6QhXfVttAyU_nid_no_patch);
int APS5_VABI libCssUnknown_74insBAQhg8_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("74insBAQhg8", libCssUnknown_74insBAQhg8_nid_no_patch);
int APS5_VABI libCssUnknown_7YdC9p2cTSQ_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("7YdC9p2cTSQ", libCssUnknown_7YdC9p2cTSQ_nid_no_patch);
int APS5_VABI libCssUnknown_81obgoH2X2g_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("81obgoH2X2g", libCssUnknown_81obgoH2X2g_nid_no_patch);
int APS5_VABI libCssUnknown_9T_minus_RYQ7HwqI_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("9T-RYQ7HwqI", libCssUnknown_9T_minus_RYQ7HwqI_nid_no_patch);
int APS5_VABI libCssUnknown_9wgr5dQqxyg_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("9wgr5dQqxyg", libCssUnknown_9wgr5dQqxyg_nid_no_patch);
int APS5_VABI libCssUnknown_AfC4Omb8svg_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("AfC4Omb8svg", libCssUnknown_AfC4Omb8svg_nid_no_patch);
int APS5_VABI libCssUnknown_B314wB_plus_fU6g_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("B314wB+fU6g", libCssUnknown_B314wB_plus_fU6g_nid_no_patch);
int APS5_VABI libCssUnknown_BpqeQbNU0qo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("BpqeQbNU0qo", libCssUnknown_BpqeQbNU0qo_nid_no_patch);
int APS5_VABI libCssUnknown_CnQiuTNrJcM_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("CnQiuTNrJcM", libCssUnknown_CnQiuTNrJcM_nid_no_patch);
int APS5_VABI libCssUnknown_E96QCyLgJ3o_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("E96QCyLgJ3o", libCssUnknown_E96QCyLgJ3o_nid_no_patch);
int APS5_VABI dvdAuthInitialize() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI DvdMac() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI libCssUnknown_FTFSIzVj7gE_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("FTFSIzVj7gE", libCssUnknown_FTFSIzVj7gE_nid_no_patch);
int APS5_VABI libCssUnknown_FsJO2R6pcFY_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("FsJO2R6pcFY", libCssUnknown_FsJO2R6pcFY_nid_no_patch);
int APS5_VABI libCssUnknown_HaAxhqb2xoM_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("HaAxhqb2xoM", libCssUnknown_HaAxhqb2xoM_nid_no_patch);
int APS5_VABI libCssUnknown_Hm2XEUlTjSk_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("Hm2XEUlTjSk", libCssUnknown_Hm2XEUlTjSk_nid_no_patch);
int APS5_VABI libCssUnknown_IcknOdMyfxQ_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("IcknOdMyfxQ", libCssUnknown_IcknOdMyfxQ_nid_no_patch);
int APS5_VABI libCssUnknown_J6BYqrHA5UM_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("J6BYqrHA5UM", libCssUnknown_J6BYqrHA5UM_nid_no_patch);
int APS5_VABI libCssUnknown_KUvq4G5VBPo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("KUvq4G5VBPo", libCssUnknown_KUvq4G5VBPo_nid_no_patch);
int APS5_VABI libCssUnknown_LAcpQCmLWwI_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("LAcpQCmLWwI", libCssUnknown_LAcpQCmLWwI_nid_no_patch);
int APS5_VABI libCssUnknown_MRbX1Lg7JPo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("MRbX1Lg7JPo", libCssUnknown_MRbX1Lg7JPo_nid_no_patch);
int APS5_VABI libCssUnknown_OM3ptXltjzo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("OM3ptXltjzo", libCssUnknown_OM3ptXltjzo_nid_no_patch);
int APS5_VABI libCssUnknown_Q4g0Ji0W5GY_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("Q4g0Ji0W5GY", libCssUnknown_Q4g0Ji0W5GY_nid_no_patch);
int APS5_VABI libCssUnknown_SRPTG7u8o98_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("SRPTG7u8o98", libCssUnknown_SRPTG7u8o98_nid_no_patch);
int APS5_VABI libCssUnknown_TJdtvWbNKhs_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("TJdtvWbNKhs", libCssUnknown_TJdtvWbNKhs_nid_no_patch);
int APS5_VABI libCssUnknown_UCT_minus_EFL9GlY_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("UCT-EFL9GlY", libCssUnknown_UCT_minus_EFL9GlY_nid_no_patch);
int APS5_VABI libCssUnknown_UlBK7McbIBI_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("UlBK7McbIBI", libCssUnknown_UlBK7McbIBI_nid_no_patch);
int APS5_VABI libCssUnknown_VLaRWTMO9U8_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("VLaRWTMO9U8", libCssUnknown_VLaRWTMO9U8_nid_no_patch);
int APS5_VABI libCssUnknown_VMBVlZevTLw_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("VMBVlZevTLw", libCssUnknown_VMBVlZevTLw_nid_no_patch);
int APS5_VABI libCssUnknown_Wdf6DHvrt4g_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("Wdf6DHvrt4g", libCssUnknown_Wdf6DHvrt4g_nid_no_patch);
int APS5_VABI libCssUnknown_X9dl5pCTGiE_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("X9dl5pCTGiE", libCssUnknown_X9dl5pCTGiE_nid_no_patch);
int APS5_VABI libCssUnknown_XWqQyI3K47s_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("XWqQyI3K47s", libCssUnknown_XWqQyI3K47s_nid_no_patch);
int APS5_VABI dvdAuthFinalize() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI libCssUnknown_bQpZTilHSL0_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("bQpZTilHSL0", libCssUnknown_bQpZTilHSL0_nid_no_patch);
int APS5_VABI libCssUnknown_cN12O1uQ6Fo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("cN12O1uQ6Fo", libCssUnknown_cN12O1uQ6Fo_nid_no_patch);
int APS5_VABI libCssUnknown_cTnMCeNpGqc_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("cTnMCeNpGqc", libCssUnknown_cTnMCeNpGqc_nid_no_patch);
int APS5_VABI libCssUnknown_czKT3U30FFE_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("czKT3U30FFE", libCssUnknown_czKT3U30FFE_nid_no_patch);
int APS5_VABI libCssUnknown_daklpMlbo00_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("daklpMlbo00", libCssUnknown_daklpMlbo00_nid_no_patch);
int APS5_VABI libCssUnknown_f7iq9LsamYo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("f7iq9LsamYo", libCssUnknown_f7iq9LsamYo_nid_no_patch);
int APS5_VABI libCssUnknown_gbja3RUMWJ4_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("gbja3RUMWJ4", libCssUnknown_gbja3RUMWJ4_nid_no_patch);
int APS5_VABI libCssUnknown_giIpEkyo9Hg_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("giIpEkyo9Hg", libCssUnknown_giIpEkyo9Hg_nid_no_patch);
int APS5_VABI libCssUnknown_hD3HhdNG_plus_xw_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("hD3HhdNG+xw", libCssUnknown_hD3HhdNG_plus_xw_nid_no_patch);
int APS5_VABI libCssUnknown_hbTTMmwE3lo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("hbTTMmwE3lo", libCssUnknown_hbTTMmwE3lo_nid_no_patch);
int APS5_VABI libCssUnknown_hbvafh9uQqY_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("hbvafh9uQqY", libCssUnknown_hbvafh9uQqY_nid_no_patch);
int APS5_VABI libCssUnknown_jYGAlLsijgw_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("jYGAlLsijgw", libCssUnknown_jYGAlLsijgw_nid_no_patch);
int APS5_VABI libCssUnknown_k1_plus_Z1AtnLYI_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("k1+Z1AtnLYI", libCssUnknown_k1_plus_Z1AtnLYI_nid_no_patch);
int APS5_VABI libCssUnknown_k5AW5Xs4aqg_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("k5AW5Xs4aqg", libCssUnknown_k5AW5Xs4aqg_nid_no_patch);
int APS5_VABI libCssUnknown_kc5B1ELiUv4_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("kc5B1ELiUv4", libCssUnknown_kc5B1ELiUv4_nid_no_patch);
int APS5_VABI libCssUnknown_nhK3hP3XL3Y_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("nhK3hP3XL3Y", libCssUnknown_nhK3hP3XL3Y_nid_no_patch);
int APS5_VABI libCssUnknown_ohRg1gu5G1w_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("ohRg1gu5G1w", libCssUnknown_ohRg1gu5G1w_nid_no_patch);
int APS5_VABI libCssUnknown_pTycImStaM4_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("pTycImStaM4", libCssUnknown_pTycImStaM4_nid_no_patch);
int APS5_VABI libCssUnknown_rylZqUytLj8_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("rylZqUytLj8", libCssUnknown_rylZqUytLj8_nid_no_patch);
int APS5_VABI libCssUnknown_szOnkd_plus_7b3U_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("szOnkd+7b3U", libCssUnknown_szOnkd_plus_7b3U_nid_no_patch);
int APS5_VABI libCssUnknown_utwkEaQy6D4_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("utwkEaQy6D4", libCssUnknown_utwkEaQy6D4_nid_no_patch);
int APS5_VABI libCssUnknown_wDe5E_minus_Nfd7E_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("wDe5E-Nfd7E", libCssUnknown_wDe5E_minus_Nfd7E_nid_no_patch);
int APS5_VABI libCssUnknown_xQX0HWKQKDA_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("xQX0HWKQKDA", libCssUnknown_xQX0HWKQKDA_nid_no_patch);
int APS5_VABI libCssUnknown_z4KQSeB3_plus_6U_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("z4KQSeB3+6U", libCssUnknown_z4KQSeB3_plus_6U_nid_no_patch);
int APS5_VABI CpsInitKey() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI libCssUnknown_zxv6uaL0lAs_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("zxv6uaL0lAs", libCssUnknown_zxv6uaL0lAs_nid_no_patch);
}
@@ -0,0 +1,73 @@
#pragma once
#include "SceTypes.hpp"
extern "C" {
int APS5_VABI libCssUnknown__plus_zpMhCilHTQ_nid_no_patch();
int APS5_VABI libCssUnknown__minus_WR4_minus_J79nn0_nid_no_patch();
int APS5_VABI libCssUnknown_45oyUIl85dg_nid_no_patch();
int APS5_VABI libCssUnknown_4qq5OHYaFU8_nid_no_patch();
int APS5_VABI libCssUnknown_6BDNwI1e59c_nid_no_patch();
int APS5_VABI libCssUnknown_6QhXfVttAyU_nid_no_patch();
int APS5_VABI libCssUnknown_74insBAQhg8_nid_no_patch();
int APS5_VABI libCssUnknown_7YdC9p2cTSQ_nid_no_patch();
int APS5_VABI libCssUnknown_81obgoH2X2g_nid_no_patch();
int APS5_VABI libCssUnknown_9T_minus_RYQ7HwqI_nid_no_patch();
int APS5_VABI libCssUnknown_9wgr5dQqxyg_nid_no_patch();
int APS5_VABI libCssUnknown_AfC4Omb8svg_nid_no_patch();
int APS5_VABI libCssUnknown_B314wB_plus_fU6g_nid_no_patch();
int APS5_VABI libCssUnknown_BpqeQbNU0qo_nid_no_patch();
int APS5_VABI libCssUnknown_CnQiuTNrJcM_nid_no_patch();
int APS5_VABI libCssUnknown_E96QCyLgJ3o_nid_no_patch();
int APS5_VABI dvdAuthInitialize();
int APS5_VABI DvdMac();
int APS5_VABI libCssUnknown_FTFSIzVj7gE_nid_no_patch();
int APS5_VABI libCssUnknown_FsJO2R6pcFY_nid_no_patch();
int APS5_VABI libCssUnknown_HaAxhqb2xoM_nid_no_patch();
int APS5_VABI libCssUnknown_Hm2XEUlTjSk_nid_no_patch();
int APS5_VABI libCssUnknown_IcknOdMyfxQ_nid_no_patch();
int APS5_VABI libCssUnknown_J6BYqrHA5UM_nid_no_patch();
int APS5_VABI libCssUnknown_KUvq4G5VBPo_nid_no_patch();
int APS5_VABI libCssUnknown_LAcpQCmLWwI_nid_no_patch();
int APS5_VABI libCssUnknown_MRbX1Lg7JPo_nid_no_patch();
int APS5_VABI libCssUnknown_OM3ptXltjzo_nid_no_patch();
int APS5_VABI libCssUnknown_Q4g0Ji0W5GY_nid_no_patch();
int APS5_VABI libCssUnknown_SRPTG7u8o98_nid_no_patch();
int APS5_VABI libCssUnknown_TJdtvWbNKhs_nid_no_patch();
int APS5_VABI libCssUnknown_UCT_minus_EFL9GlY_nid_no_patch();
int APS5_VABI libCssUnknown_UlBK7McbIBI_nid_no_patch();
int APS5_VABI libCssUnknown_VLaRWTMO9U8_nid_no_patch();
int APS5_VABI libCssUnknown_VMBVlZevTLw_nid_no_patch();
int APS5_VABI libCssUnknown_Wdf6DHvrt4g_nid_no_patch();
int APS5_VABI libCssUnknown_X9dl5pCTGiE_nid_no_patch();
int APS5_VABI libCssUnknown_XWqQyI3K47s_nid_no_patch();
int APS5_VABI dvdAuthFinalize();
int APS5_VABI libCssUnknown_bQpZTilHSL0_nid_no_patch();
int APS5_VABI libCssUnknown_cN12O1uQ6Fo_nid_no_patch();
int APS5_VABI libCssUnknown_cTnMCeNpGqc_nid_no_patch();
int APS5_VABI libCssUnknown_czKT3U30FFE_nid_no_patch();
int APS5_VABI libCssUnknown_daklpMlbo00_nid_no_patch();
int APS5_VABI libCssUnknown_f7iq9LsamYo_nid_no_patch();
int APS5_VABI libCssUnknown_gbja3RUMWJ4_nid_no_patch();
int APS5_VABI libCssUnknown_giIpEkyo9Hg_nid_no_patch();
int APS5_VABI libCssUnknown_hD3HhdNG_plus_xw_nid_no_patch();
int APS5_VABI libCssUnknown_hbTTMmwE3lo_nid_no_patch();
int APS5_VABI libCssUnknown_hbvafh9uQqY_nid_no_patch();
int APS5_VABI libCssUnknown_jYGAlLsijgw_nid_no_patch();
int APS5_VABI libCssUnknown_k1_plus_Z1AtnLYI_nid_no_patch();
int APS5_VABI libCssUnknown_k5AW5Xs4aqg_nid_no_patch();
int APS5_VABI libCssUnknown_kc5B1ELiUv4_nid_no_patch();
int APS5_VABI libCssUnknown_nhK3hP3XL3Y_nid_no_patch();
int APS5_VABI libCssUnknown_ohRg1gu5G1w_nid_no_patch();
int APS5_VABI libCssUnknown_pTycImStaM4_nid_no_patch();
int APS5_VABI libCssUnknown_rylZqUytLj8_nid_no_patch();
int APS5_VABI libCssUnknown_szOnkd_plus_7b3U_nid_no_patch();
int APS5_VABI libCssUnknown_utwkEaQy6D4_nid_no_patch();
int APS5_VABI libCssUnknown_wDe5E_minus_Nfd7E_nid_no_patch();
int APS5_VABI libCssUnknown_xQX0HWKQKDA_nid_no_patch();
int APS5_VABI libCssUnknown_z4KQSeB3_plus_6U_nid_no_patch();
int APS5_VABI CpsInitKey();
int APS5_VABI libCssUnknown_zxv6uaL0lAs_nid_no_patch();
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "prx/libCss/include/InventoryExports.hpp"
+10
View File
@@ -0,0 +1,10 @@
#include <cstddef>
#include <cstdint>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {
APS5_DUMMY_FUN
}
+1
View File
@@ -0,0 +1 @@
#pragma once
@@ -0,0 +1,251 @@
#include "prx/libc/include/general/ExportMacros.hpp"
#include "prx/libReactNative.Modules.Vsh.WebAppLauncher/include/InventoryExports.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {
int APS5_VABI CheckSystemEvents() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CommerceDialogBrowseCategory() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CommerceDialogBrowseProduct() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CommerceDialogInit() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CommerceDialogRedeemPromotionCode() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CommerceHidePsStoreIcon() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CommerceSetPsStoreIconLayout() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CommerceShowPsStoreIcon() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI DisableSystemMedia() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI ErrorDialogClose() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI ErrorDialogInit() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI ErrorDialogOpen() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetAccountAgeA() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetAccountCountryA() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetAccountIdA() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetAccountLanguage2() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetAuthorizationCode() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetClosedCaptionSettings() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetOnlineId() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetProcessTime() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetVideoOutputStatus() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetVideoOutputStatusInt() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI Hide() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI IsDebuggingSupported() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpWebAbortRequest() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpWebDeleteRequest() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpWebInitialize() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpWebReadData() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpWebTerminate() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI OpenClosedCaptionAdvancedSettings() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI OpenClosedCaptionSettings() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SoundInitialize() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SoundLoad() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SoundPlay() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SoundTerminate() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SpeechCancel() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SpeechClose() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SpeechInitialize() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SpeechSpeak() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SpeechStatus() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SpeechTerminate() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SystemDialogInit() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SystemDialogOpen() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SystemServiceParamGetInt() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI SystemServiceParamGetString() {
NotImplemented_nid_no_patch(__func__);
}
}
extern "C" {
int APS5_VABI libReactNativeWebAppLauncherInventory__plus_ucrAt9fI7c_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("+ucrAt9fI7c", libReactNativeWebAppLauncherInventory__plus_ucrAt9fI7c_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_06N_minus_dAyE_plus_HY_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("06N-dAyE+HY", libReactNativeWebAppLauncherInventory_06N_minus_dAyE_plus_HY_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_41blU2JCqLQ_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("41blU2JCqLQ", libReactNativeWebAppLauncherInventory_41blU2JCqLQ_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_BGgSEXB1Now_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("BGgSEXB1Now", libReactNativeWebAppLauncherInventory_BGgSEXB1Now_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_CAK_minus_S2JVdsk_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("CAK-S2JVdsk", libReactNativeWebAppLauncherInventory_CAK_minus_S2JVdsk_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_QxCdpkEsOgo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("QxCdpkEsOgo", libReactNativeWebAppLauncherInventory_QxCdpkEsOgo_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_Tjj_plus__plus_S2qvOU_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("Tjj++S2qvOU", libReactNativeWebAppLauncherInventory_Tjj_plus__plus_S2qvOU_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_f5NHqUziG_plus_4_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("f5NHqUziG+4", libReactNativeWebAppLauncherInventory_f5NHqUziG_plus_4_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_mI_minus_ltMuVN_plus_Q_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("mI-ltMuVN+Q", libReactNativeWebAppLauncherInventory_mI_minus_ltMuVN_plus_Q_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_vDup_plus_0mWZf8_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("vDup+0mWZf8", libReactNativeWebAppLauncherInventory_vDup_plus_0mWZf8_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_wR1ucKGDM9Q_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("wR1ucKGDM9Q", libReactNativeWebAppLauncherInventory_wR1ucKGDM9Q_nid_no_patch);
int APS5_VABI libReactNativeWebAppLauncherInventory_xPA_minus_tXzPGpc_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("xPA-tXzPGpc", libReactNativeWebAppLauncherInventory_xPA_minus_tXzPGpc_nid_no_patch);
}
@@ -0,0 +1,67 @@
#pragma once
#include "SceTypes.hpp"
extern "C" {
int APS5_VABI CheckSystemEvents();
int APS5_VABI CommerceDialogBrowseCategory();
int APS5_VABI CommerceDialogBrowseProduct();
int APS5_VABI CommerceDialogInit();
int APS5_VABI CommerceDialogRedeemPromotionCode();
int APS5_VABI CommerceHidePsStoreIcon();
int APS5_VABI CommerceSetPsStoreIconLayout();
int APS5_VABI CommerceShowPsStoreIcon();
int APS5_VABI DisableSystemMedia();
int APS5_VABI ErrorDialogClose();
int APS5_VABI ErrorDialogInit();
int APS5_VABI ErrorDialogOpen();
int APS5_VABI GetAccountAgeA();
int APS5_VABI GetAccountCountryA();
int APS5_VABI GetAccountIdA();
int APS5_VABI GetAccountLanguage2();
int APS5_VABI GetAuthorizationCode();
int APS5_VABI GetClosedCaptionSettings();
int APS5_VABI GetOnlineId();
int APS5_VABI GetProcessTime();
int APS5_VABI GetVideoOutputStatus();
int APS5_VABI GetVideoOutputStatusInt();
int APS5_VABI Hide();
int APS5_VABI IsDebuggingSupported();
int APS5_VABI NpWebAbortRequest();
int APS5_VABI NpWebDeleteRequest();
int APS5_VABI NpWebInitialize();
int APS5_VABI NpWebReadData();
int APS5_VABI NpWebTerminate();
int APS5_VABI OpenClosedCaptionAdvancedSettings();
int APS5_VABI OpenClosedCaptionSettings();
int APS5_VABI SoundInitialize();
int APS5_VABI SoundLoad();
int APS5_VABI SoundPlay();
int APS5_VABI SoundTerminate();
int APS5_VABI SpeechCancel();
int APS5_VABI SpeechClose();
int APS5_VABI SpeechInitialize();
int APS5_VABI SpeechSpeak();
int APS5_VABI SpeechStatus();
int APS5_VABI SpeechTerminate();
int APS5_VABI SystemDialogInit();
int APS5_VABI SystemDialogOpen();
int APS5_VABI SystemServiceParamGetInt();
int APS5_VABI SystemServiceParamGetString();
int APS5_VABI libReactNativeWebAppLauncherInventory__plus_ucrAt9fI7c_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_06N_minus_dAyE_plus_HY_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_41blU2JCqLQ_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_BGgSEXB1Now_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_CAK_minus_S2JVdsk_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_QxCdpkEsOgo_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_Tjj_plus__plus_S2qvOU_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_f5NHqUziG_plus_4_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_mI_minus_ltMuVN_plus_Q_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_vDup_plus_0mWZf8_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_wR1ucKGDM9Q_nid_no_patch();
int APS5_VABI libReactNativeWebAppLauncherInventory_xPA_minus_tXzPGpc_nid_no_patch();
}
@@ -0,0 +1,3 @@
#pragma once
#include "prx/libReactNative.Modules.Vsh.WebAppLauncher/include/InventoryExports.hpp"
@@ -0,0 +1,361 @@
#include "prx/libc/include/general/ExportMacros.hpp"
#include "prx/libReactNative.Modules.Vsh/include/InventoryExports.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {
int APS5_VABI CreateWebApiLibCtx() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CryptographyDecryptAES128CBC() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CryptographyDecryptAES128CBC_HS256() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CryptographyDecryptAES128GCM() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CryptographyEncryptAES128CBC() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CryptographyEncryptAES128GCM() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI CryptographyGenerateHmacSha256() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI DestroyWebApiLibCtx() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetLibHttpCtxId() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI GetPs4AppCategoryForTitleId() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI InetStatGetResultNative() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI InetStatGetStateNative() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI InetStatStartTestNative() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI InitializeNetLib() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI LoginMgrCreateUser() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI LoginMgrDestroyUser() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI LoginMgrInitialize() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI LoginMgrSetLoginFlag() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI LoginMgrSetUserStatus() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI LoginMgrTerminate() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpStateManagerRegisterCallback() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpStateManagerRtcSetTick() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpStateManagerStart() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpStateManagerStop() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI NpStateManagerUnregisterCallback() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI PSNowGetStatus() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI PSNowGetStreamingStatus() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI PSNowInitialize() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI PSNowReset() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI PSNowSendCommand() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI PSNowSetAuthCodes() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI PSNowSetSettings() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI PSNowTerminate() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayClearConnectHistory() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayConfirmDeviceRegist() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayDisconnect() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayGeneratePinCode() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayGetConnectHistory() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayGetConnectUserId() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayGetConnectionStatus() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayGetRemoteplayStatus() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayGetRpMode() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayIsRemotePlaying() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayNotifyCanWakeup() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayNotifyPinCodeError() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayNotifyUserDelete() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlayProhibitStreaming() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlaySetProhibition() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlaySetProhibitionForVsh() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RemotePlaySetRpMode() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RtcGetCurrentAdNetworkTickNative() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RtcGetCurrentDebugNetworkTickNative() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI RtcGetCurrentNetworkTickNative() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI TerminateNetLib() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI WebBrowserGetEnvelopeData() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientAddEventListener() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientAttachVirtualMicrophone() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientDetachVirtualMicrophone() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientGetClientStatus() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientInitialize() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientRemoveController() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientShowHomeScreen() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientStartMicCapture() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientStopMicCapture() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI sceRemotePlayClientTerminateStreaming() {
NotImplemented_nid_no_patch(__func__);
}
}
extern "C" {
int APS5_VABI libReactNativeModulesVshInventory__plus_I5sPs9FLXw_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("+I5sPs9FLXw", libReactNativeModulesVshInventory__plus_I5sPs9FLXw_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory__minus_9hYGDAsb4E_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("-9hYGDAsb4E", libReactNativeModulesVshInventory__minus_9hYGDAsb4E_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_BzJsgzD97LU_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("BzJsgzD97LU", libReactNativeModulesVshInventory_BzJsgzD97LU_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_IQNf2nnftNI_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("IQNf2nnftNI", libReactNativeModulesVshInventory_IQNf2nnftNI_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_N3mcm_minus_qDFR0_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("N3mcm-qDFR0", libReactNativeModulesVshInventory_N3mcm_minus_qDFR0_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_OME2Be_plus_FlwA_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("OME2Be+FlwA", libReactNativeModulesVshInventory_OME2Be_plus_FlwA_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_PLEe_minus_toB_minus_KE_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("PLEe-toB-KE", libReactNativeModulesVshInventory_PLEe_minus_toB_minus_KE_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_QGGsQrtLW9Y_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("QGGsQrtLW9Y", libReactNativeModulesVshInventory_QGGsQrtLW9Y_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_Rm_plus_rgnBoPIE_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("Rm+rgnBoPIE", libReactNativeModulesVshInventory_Rm_plus_rgnBoPIE_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_SJU_plus_qK_plus_8yrM_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("SJU+qK+8yrM", libReactNativeModulesVshInventory_SJU_plus_qK_plus_8yrM_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_T7dL_minus_hEySvU_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("T7dL-hEySvU", libReactNativeModulesVshInventory_T7dL_minus_hEySvU_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_b_plus_MJDz3HB6s_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("b+MJDz3HB6s", libReactNativeModulesVshInventory_b_plus_MJDz3HB6s_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_bbsP8_minus_e8GZA_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("bbsP8-e8GZA", libReactNativeModulesVshInventory_bbsP8_minus_e8GZA_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_fxEQAPDRhLw_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("fxEQAPDRhLw", libReactNativeModulesVshInventory_fxEQAPDRhLw_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_j917Pp4k_minus_CI_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("j917Pp4k-CI", libReactNativeModulesVshInventory_j917Pp4k_minus_CI_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_lZ_minus_JDEqB34k_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("lZ-JDEqB34k", libReactNativeModulesVshInventory_lZ_minus_JDEqB34k_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_tKy_minus_Qdg_plus_FRc_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("tKy-Qdg+FRc", libReactNativeModulesVshInventory_tKy_minus_Qdg_plus_FRc_nid_no_patch);
int APS5_VABI libReactNativeModulesVshInventory_uQfQgwm36L4_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("uQfQgwm36L4", libReactNativeModulesVshInventory_uQfQgwm36L4_nid_no_patch);
}
@@ -0,0 +1,93 @@
#pragma once
#include "SceTypes.hpp"
extern "C" {
int APS5_VABI CreateWebApiLibCtx();
int APS5_VABI CryptographyDecryptAES128CBC();
int APS5_VABI CryptographyDecryptAES128CBC_HS256();
int APS5_VABI CryptographyDecryptAES128GCM();
int APS5_VABI CryptographyEncryptAES128CBC();
int APS5_VABI CryptographyEncryptAES128GCM();
int APS5_VABI CryptographyGenerateHmacSha256();
int APS5_VABI DestroyWebApiLibCtx();
int APS5_VABI GetLibHttpCtxId();
int APS5_VABI GetPs4AppCategoryForTitleId();
int APS5_VABI InetStatGetResultNative();
int APS5_VABI InetStatGetStateNative();
int APS5_VABI InetStatStartTestNative();
int APS5_VABI InitializeNetLib();
int APS5_VABI LoginMgrCreateUser();
int APS5_VABI LoginMgrDestroyUser();
int APS5_VABI LoginMgrInitialize();
int APS5_VABI LoginMgrSetLoginFlag();
int APS5_VABI LoginMgrSetUserStatus();
int APS5_VABI LoginMgrTerminate();
int APS5_VABI NpStateManagerRegisterCallback();
int APS5_VABI NpStateManagerRtcSetTick();
int APS5_VABI NpStateManagerStart();
int APS5_VABI NpStateManagerStop();
int APS5_VABI NpStateManagerUnregisterCallback();
int APS5_VABI PSNowGetStatus();
int APS5_VABI PSNowGetStreamingStatus();
int APS5_VABI PSNowInitialize();
int APS5_VABI PSNowReset();
int APS5_VABI PSNowSendCommand();
int APS5_VABI PSNowSetAuthCodes();
int APS5_VABI PSNowSetSettings();
int APS5_VABI PSNowTerminate();
int APS5_VABI RemotePlayClearConnectHistory();
int APS5_VABI RemotePlayConfirmDeviceRegist();
int APS5_VABI RemotePlayDisconnect();
int APS5_VABI RemotePlayGeneratePinCode();
int APS5_VABI RemotePlayGetConnectHistory();
int APS5_VABI RemotePlayGetConnectUserId();
int APS5_VABI RemotePlayGetConnectionStatus();
int APS5_VABI RemotePlayGetRemoteplayStatus();
int APS5_VABI RemotePlayGetRpMode();
int APS5_VABI RemotePlayIsRemotePlaying();
int APS5_VABI RemotePlayNotifyCanWakeup();
int APS5_VABI RemotePlayNotifyPinCodeError();
int APS5_VABI RemotePlayNotifyUserDelete();
int APS5_VABI RemotePlayProhibitStreaming();
int APS5_VABI RemotePlaySetProhibition();
int APS5_VABI RemotePlaySetProhibitionForVsh();
int APS5_VABI RemotePlaySetRpMode();
int APS5_VABI RtcGetCurrentAdNetworkTickNative();
int APS5_VABI RtcGetCurrentDebugNetworkTickNative();
int APS5_VABI RtcGetCurrentNetworkTickNative();
int APS5_VABI TerminateNetLib();
int APS5_VABI WebBrowserGetEnvelopeData();
int APS5_VABI sceRemotePlayClientAddEventListener();
int APS5_VABI sceRemotePlayClientAttachVirtualMicrophone();
int APS5_VABI sceRemotePlayClientDetachVirtualMicrophone();
int APS5_VABI sceRemotePlayClientGetClientStatus();
int APS5_VABI sceRemotePlayClientInitialize();
int APS5_VABI sceRemotePlayClientRemoveController();
int APS5_VABI sceRemotePlayClientShowHomeScreen();
int APS5_VABI sceRemotePlayClientStartMicCapture();
int APS5_VABI sceRemotePlayClientStopMicCapture();
int APS5_VABI sceRemotePlayClientTerminateStreaming();
int APS5_VABI libReactNativeModulesVshInventory__plus_I5sPs9FLXw_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory__minus_9hYGDAsb4E_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_BzJsgzD97LU_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_IQNf2nnftNI_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_N3mcm_minus_qDFR0_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_OME2Be_plus_FlwA_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_PLEe_minus_toB_minus_KE_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_QGGsQrtLW9Y_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_Rm_plus_rgnBoPIE_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_SJU_plus_qK_plus_8yrM_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_T7dL_minus_hEySvU_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_b_plus_MJDz3HB6s_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_bbsP8_minus_e8GZA_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_fxEQAPDRhLw_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_j917Pp4k_minus_CI_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_lZ_minus_JDEqB34k_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_tKy_minus_Qdg_plus_FRc_nid_no_patch();
int APS5_VABI libReactNativeModulesVshInventory_uQfQgwm36L4_nid_no_patch();
}
@@ -0,0 +1,3 @@
#pragma once
#include "prx/libReactNative.Modules.Vsh/include/InventoryExports.hpp"
+111 -220
View File
@@ -1,3 +1,4 @@
#include "prx/libSceAbstractStorage/include/Api.hpp"
#include "prx/libSceAbstractStorage/include/LegacyExports.hpp"
#include "prx/libc/include/general/ExportMacros.hpp"
#include "prx/libSceAbstractStorage/include/InventoryExports.hpp"
@@ -9,555 +10,445 @@
extern "C" {
int APS5_VABI sceAbstractStorageUnknown_7RnkdybfYiQ_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage12Serializable12readExternalESt10shared_ptrINS_7ContentEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("7RnkdybfYiQ", sceAbstractStorageUnknown_7RnkdybfYiQ_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_gINcKTbrqk4_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage12Serializable13writeExternalESt10shared_ptrINS_7ContentEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("gINcKTbrqk4", sceAbstractStorageUnknown_gINcKTbrqk4_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_F6tunp5_4ZM_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage12SerializableC1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("F6tunp5+4ZM", sceAbstractStorageUnknown_F6tunp5_4ZM_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_QRnz_VjPrkY_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage12SerializableC2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("QRnz-VjPrkY", sceAbstractStorageUnknown_QRnz_VjPrkY_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_DkAGX6EPi_g_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage12SerializableD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("DkAGX6EPi+g", sceAbstractStorageUnknown_DkAGX6EPi_g_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_tDhVqVa_tvU_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage12SerializableD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("tDhVqVa-tvU", sceAbstractStorageUnknown_tDhVqVa_tvU_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_o9RD998mN8M_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent12readExternalESt10shared_ptrINS_7ContentEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("o9RD998mN8M", sceAbstractStorageUnknown_o9RD998mN8M_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_KAJD5gNtjzg_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent13writeExternalESt10shared_ptrINS_7ContentEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("KAJD5gNtjzg", sceAbstractStorageUnknown_KAJD5gNtjzg_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_jekg6a2C_KE_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent14CreateInstanceESbIcSt11char_traitsIcENS_8StlAllocIcEEEN3paf6common9SharedPtrINS6_6BufferEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("jekg6a2C-KE", sceAbstractStorageUnknown_jekg6a2C_KE_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_SPPYTszg6LQ_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent14CreateInstanceESbIcSt11char_traitsIcENS_8StlAllocIcEEEPvm() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("SPPYTszg6LQ", sceAbstractStorageUnknown_SPPYTszg6LQ_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_ppyod3XEauc_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent4OpenEit() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("ppyod3XEauc", sceAbstractStorageUnknown_ppyod3XEauc_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_FC7E1riolAM_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent4ReadEPvlPl() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("FC7E1riolAM", sceAbstractStorageUnknown_FC7E1riolAM_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_h64Ojqk4fbE_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent5CloseEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("h64Ojqk4fbE", sceAbstractStorageUnknown_h64Ojqk4fbE_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_L9n8X5qE3gI_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent5FlushEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("L9n8X5qE3gI", sceAbstractStorageUnknown_L9n8X5qE3gI_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_UqSO97fYNAs_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent5WriteEPKvlPl() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("UqSO97fYNAs", sceAbstractStorageUnknown_UqSO97fYNAs_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_nxefs8JHV5U_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent6RemoveEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("nxefs8JHV5U", sceAbstractStorageUnknown_nxefs8JHV5U_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_TI_djeSDh5s_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent8SeekByteEliPl() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("TI+djeSDh5s", sceAbstractStorageUnknown_TI_djeSDh5s_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_23QZTBt3E60_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContent8SeekTimeElPl() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("23QZTBt3E60", sceAbstractStorageUnknown_23QZTBt3E60_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_CgSbdJjHTyc_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContentC1ESbIcSt11char_traitsIcENS_8StlAllocIcEEEN3paf6common9SharedPtrINS6_6BufferEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("CgSbdJjHTyc", sceAbstractStorageUnknown_CgSbdJjHTyc_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_uhxDqVGiDTY_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContentC2ESbIcSt11char_traitsIcENS_8StlAllocIcEEEN3paf6common9SharedPtrINS6_6BufferEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("uhxDqVGiDTY", sceAbstractStorageUnknown_uhxDqVGiDTY_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_93IuLXtj1sc_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContentD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("93IuLXtj1sc", sceAbstractStorageUnknown_93IuLXtj1sc_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_6g_lsIudFQY_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContentD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("6g-lsIudFQY", sceAbstractStorageUnknown_6g_lsIudFQY_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_r_kkC2OXw10_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14MemfileContentD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("r+kkC2OXw10", sceAbstractStorageUnknown_r_kkC2OXw10_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_xeunZETVUSk_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager10GetStorageERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEPSt10shared_ptrINS_7StorageEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("xeunZETVUSk", sceAbstractStorageUnknown_xeunZETVUSk_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_k0BKafeYaUo_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager10InitializeEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("k0BKafeYaUo", sceAbstractStorageUnknown_k0BKafeYaUo_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_iAN_9pPHZSE_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager11GetInstanceERNS_12MemAllocatorEPv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("iAN-9pPHZSE", sceAbstractStorageUnknown_iAN_9pPHZSE_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_QbKmf_2_cR0_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager11GetInstanceEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("QbKmf+2+cR0", sceAbstractStorageUnknown_QbKmf_2_cR0_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_JWT7NbPA9Ds_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager12NotifyCreateERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEb() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("JWT7NbPA9Ds", sceAbstractStorageUnknown_JWT7NbPA9Ds_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown__fMkDXxU9E0_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager12NotifyRemoveERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEb() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("+fMkDXxU9E0", sceAbstractStorageUnknown__fMkDXxU9E0_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_sFN0uAZmk04_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager15ReleaseInstanceEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("sFN0uAZmk04", sceAbstractStorageUnknown_sFN0uAZmk04_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_wvDKH1RiZhU_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager16NotifyWriteCloseERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("wvDKH1RiZhU", sceAbstractStorageUnknown_wvDKH1RiZhU_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_FxOHF0FBNfU_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager16RegisterListenerEPNS_17ItemEventListenerE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("FxOHF0FBNfU", sceAbstractStorageUnknown_FxOHF0FBNfU_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_JvyLbYhVigM_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager16RegisterListenerEPNS_20StorageEventListenerE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("JvyLbYhVigM", sceAbstractStorageUnknown_JvyLbYhVigM_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_bb_T5NMDPck_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager16get_storage_nameERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("bb-T5NMDPck", sceAbstractStorageUnknown_bb_T5NMDPck_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_LPRr40DzhbA_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager17NotifySetMetadataERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("LPRr40DzhbA", sceAbstractStorageUnknown_LPRr40DzhbA_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_oIR7L2c6df8_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager18GetStorageNameListEPSt6vectorISbIcSt11char_traitsIcENS_8StlAllocIcEEESaIS6_EE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("oIR7L2c6df8", sceAbstractStorageUnknown_oIR7L2c6df8_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_mhLGIWhMLlk_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager18UnregisterListenerEPKNS_17ItemEventListenerE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("mhLGIWhMLlk", sceAbstractStorageUnknown_mhLGIWhMLlk_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_0Ydc18_XsSw_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager18UnregisterListenerEPKNS_20StorageEventListenerE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("0Ydc18+XsSw", sceAbstractStorageUnknown_0Ydc18_XsSw_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_piG6ktf2BTU_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager20get_service_instanceENS_11ServiceTypeE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("piG6ktf2BTU", sceAbstractStorageUnknown_piG6ktf2BTU_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_iLakkVdPya4_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager21NotifyStorageAttachedERKSbIcSt11char_traitsIcENS_8StlAllocIcEEENS_11ServiceTypeE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("iLakkVdPya4", sceAbstractStorageUnknown_iLakkVdPya4_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_1Ko_sKZgqqs_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager21NotifyStorageDetachedERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("1Ko+sKZgqqs", sceAbstractStorageUnknown_1Ko_sKZgqqs_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown__PYC3_W6yUE_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager4FreeEPv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("-PYC3+W6yUE", sceAbstractStorageUnknown__PYC3_W6yUE_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_3iP9Xa6Z3z0_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager4LoadENS_11ServiceTypeE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("3iP9Xa6Z3z0", sceAbstractStorageUnknown_3iP9Xa6Z3z0_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_JREmVpFIgEY_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager6MallocEm() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("JREmVpFIgEY", sceAbstractStorageUnknown_JREmVpFIgEY_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_kCX0k5t1v_w_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager6UnloadENS_11ServiceTypeE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("kCX0k5t1v-w", sceAbstractStorageUnknown_kCX0k5t1v_w_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_3Cp_nOwl47U_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager6UpdateENS_11ServiceTypeE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("3Cp-nOwl47U", sceAbstractStorageUnknown_3Cp_nOwl47U_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_v9CSqw6Ve0w_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManager9TerminateEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("v9CSqw6Ve0w", sceAbstractStorageUnknown_v9CSqw6Ve0w_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_KxTVuhlCL7o_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManagerC1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("KxTVuhlCL7o", sceAbstractStorageUnknown_KxTVuhlCL7o_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_YXXMdeJmxJw_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManagerC2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("YXXMdeJmxJw", sceAbstractStorageUnknown_YXXMdeJmxJw_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_2_S0J1RW2vQ_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManagerD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("2-S0J1RW2vQ", sceAbstractStorageUnknown_2_S0J1RW2vQ_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_K3qnBgQ0nC4_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage14StorageManagerD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("K3qnBgQ0nC4", sceAbstractStorageUnknown_K3qnBgQ0nC4_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_rHzXUC9OHh8_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage15HttpTransaction15SendHttpRequestERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEiRKSt3mapIS5_S5_St4lessIS5_ESaISt4pairIS6_S5_EEEmb() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("rHzXUC9OHh8", sceAbstractStorageUnknown_rHzXUC9OHh8_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_Dlri33kcH6o_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage15HttpTransaction4InitEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("Dlri33kcH6o", sceAbstractStorageUnknown_Dlri33kcH6o_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_lH57wXDczHk_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage15HttpTransaction4TermEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("lH57wXDczHk", sceAbstractStorageUnknown_lH57wXDczHk_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_xJbY3QNYIzM_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage15HttpTransaction8SendDataEPKvm() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("xJbY3QNYIzM", sceAbstractStorageUnknown_xJbY3QNYIzM_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_tbeA_hlRlHc_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage15HttpTransactionC1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("tbeA-hlRlHc", sceAbstractStorageUnknown_tbeA_hlRlHc_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_01BHTyfcbBs_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage15HttpTransactionC2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("01BHTyfcbBs", sceAbstractStorageUnknown_01BHTyfcbBs_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_1PrEoSKt3_w_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage15HttpTransactionD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("1PrEoSKt3-w", sceAbstractStorageUnknown_1PrEoSKt3_w_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_MoUJZiDoHMk_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage15HttpTransactionD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("MoUJZiDoHMk", sceAbstractStorageUnknown_MoUJZiDoHMk_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_I69kRgYrWmY_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4Item11GetPathNameEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("I69kRgYrWmY", sceAbstractStorageUnknown_I69kRgYrWmY_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_GCMRCWH3PU0_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4Item11SetMetadataEPN23sceMetadataReaderWriter8MetadataE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("GCMRCWH3PU0", sceAbstractStorageUnknown_GCMRCWH3PU0_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_SYb4Kmj0u88_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4Item13ParseMetadataEPN23sceMetadataReaderWriter8MetadataES3_() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("SYb4Kmj0u88", sceAbstractStorageUnknown_SYb4Kmj0u88_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_k2VonUL2gF8_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4Item14GetStorageNameEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("k2VonUL2gF8", sceAbstractStorageUnknown_k2VonUL2gF8_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_zkaNI1552m4_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4Item6RenameERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("zkaNI1552m4", sceAbstractStorageUnknown_zkaNI1552m4_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_KAtGZCifCMo_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4Item7GetNameERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("KAtGZCifCMo", sceAbstractStorageUnknown_KAtGZCifCMo_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown__sxz_ThMtGM_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4Item7GetNameEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("-sxz-ThMtGM", sceAbstractStorageUnknown__sxz_ThMtGM_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_wyEuZhFhbOE_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4Item8set_metaERN23sceMetadataReaderWriter8MetadataERKSbIcSt11char_traitsIcENS_8StlAllocIcEEESA_() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("wyEuZhFhbOE", sceAbstractStorageUnknown_wyEuZhFhbOE_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_F_Tz7UzYtJ4_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4Item8set_metaERN23sceMetadataReaderWriter8MetadataERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEm() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("F-Tz7UzYtJ4", sceAbstractStorageUnknown_F_Tz7UzYtJ4_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_zC_hnmcVEOw_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4ItemC2ERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("zC+hnmcVEOw", sceAbstractStorageUnknown_zC_hnmcVEOw_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_scYjSEuq2ik_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4ItemD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("scYjSEuq2ik", sceAbstractStorageUnknown_scYjSEuq2ik_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_QPNELEk9zkI_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4ItemD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("QPNELEk9zkI", sceAbstractStorageUnknown_QPNELEk9zkI_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_WnE1cxQELbY_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4ItemD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("WnE1cxQELbY", sceAbstractStorageUnknown_WnE1cxQELbY_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_Hg0GBcA80dk_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4ItemdlEPv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("Hg0GBcA80dk", sceAbstractStorageUnknown_Hg0GBcA80dk_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_gid_GlhKgJM_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage4ItemnwEm() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("gid+GlhKgJM", sceAbstractStorageUnknown_gid_GlhKgJM_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_oJSXws_cIv8_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage6FolderC2ERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("oJSXws+cIv8", sceAbstractStorageUnknown_oJSXws_cIv8_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_GgNWVxe_YSU_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage6FolderD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("GgNWVxe-YSU", sceAbstractStorageUnknown_GgNWVxe_YSU_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown__1PWHzoXWyU_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage6FolderD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("-1PWHzoXWyU", sceAbstractStorageUnknown__1PWHzoXWyU_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_sLg6rUpiYSM_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage6FolderD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("sLg6rUpiYSM", sceAbstractStorageUnknown_sLg6rUpiYSM_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_lYUGcgHYT7Y_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7AbsFreeEPv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("lYUGcgHYT7Y", sceAbstractStorageUnknown_lYUGcgHYT7Y_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_hQiPEotip7M_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Content12GetExtensionERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("hQiPEotip7M", sceAbstractStorageUnknown_hQiPEotip7M_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_pekT_IsAkQU_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Content12GetMimeTypesEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("pekT-IsAkQU", sceAbstractStorageUnknown_pekT_IsAkQU_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_xilbMn7q9qE_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Content6RenameERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("xilbMn7q9qE", sceAbstractStorageUnknown_xilbMn7q9qE_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_UZbuoykGKzE_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7ContentC2ERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("UZbuoykGKzE", sceAbstractStorageUnknown_UZbuoykGKzE_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_RenWwlxG9Tw_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7ContentD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("RenWwlxG9Tw", sceAbstractStorageUnknown_RenWwlxG9Tw_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_JZ3wKDjl0yQ_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7ContentD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("JZ3wKDjl0yQ", sceAbstractStorageUnknown_JZ3wKDjl0yQ_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_m7OSrfA7K_s_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7ContentD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("m7OSrfA7K+s", sceAbstractStorageUnknown_m7OSrfA7K_s_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_spsjzV2pTSc_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Service11NextStorageERSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("spsjzV2pTSc", sceAbstractStorageUnknown_spsjzV2pTSc_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_6Fp8jJ7A7CY_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Service13CreateStorageERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEPSt10shared_ptrINS_7StorageEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("6Fp8jJ7A7CY", sceAbstractStorageUnknown_6Fp8jJ7A7CY_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_wBaVZTLTjkg_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Service18clear_storage_listEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("wBaVZTLTjkg", sceAbstractStorageUnknown_wBaVZTLTjkg_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_DyerRilxWZ4_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Service4LoadENS_11ServiceTypeE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("DyerRilxWZ4", sceAbstractStorageUnknown_DyerRilxWZ4_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_jCKhrVa9MEU_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Service4StopEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("jCKhrVa9MEU", sceAbstractStorageUnknown_jCKhrVa9MEU_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_tIIRbXa2ZOk_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Service5StartEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("tIIRbXa2ZOk", sceAbstractStorageUnknown_tIIRbXa2ZOk_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_vatp8UwS_nE_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7Service6UnLoadEPS0_() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("vatp8UwS+nE", sceAbstractStorageUnknown_vatp8UwS_nE_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_CrZTHC5yd64_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7ServiceC2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("CrZTHC5yd64", sceAbstractStorageUnknown_CrZTHC5yd64_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_IoNgvbVSw24_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7ServiceD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("IoNgvbVSw24", sceAbstractStorageUnknown_IoNgvbVSw24_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_PEuuRn6zhF4_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7ServiceD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("PEuuRn6zhF4", sceAbstractStorageUnknown_PEuuRn6zhF4_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_Ngfl7wTF7M0_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7ServiceD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("Ngfl7wTF7M0", sceAbstractStorageUnknown_Ngfl7wTF7M0_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_tLtIJWgGINI_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7StorageC2ERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("tLtIJWgGINI", sceAbstractStorageUnknown_tLtIJWgGINI_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_4ns7J9OrJ5g_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7StorageD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("4ns7J9OrJ5g", sceAbstractStorageUnknown_4ns7J9OrJ5g_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_aKBqHZKouts_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7StorageD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("aKBqHZKouts", sceAbstractStorageUnknown_aKBqHZKouts_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_fydJOJjDxX4_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage7StorageD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("fydJOJjDxX4", sceAbstractStorageUnknown_fydJOJjDxX4_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_qtgEboQL0YE_nid_no_patch() {
int APS5_VABI _ZN15AbstractStorage9AbsMallocEm() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("qtgEboQL0YE", sceAbstractStorageUnknown_qtgEboQL0YE_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_XBlKK5ijWI8_nid_no_patch() {
int APS5_VABI _ZNK15AbstractStorage14MemfileContent10GetServiceEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("XBlKK5ijWI8", sceAbstractStorageUnknown_XBlKK5ijWI8_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_xP3aCoP48XI_nid_no_patch() {
int APS5_VABI _ZNK15AbstractStorage14MemfileContent13GetCapabilityEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("xP3aCoP48XI", sceAbstractStorageUnknown_xP3aCoP48XI_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_FCSUVvY_0RM_nid_no_patch() {
int APS5_VABI _ZNK15AbstractStorage14MemfileContent7GetStatEPNS_4StatE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("FCSUVvY-0RM", sceAbstractStorageUnknown_FCSUVvY_0RM_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_oc6n6hdUrEM_nid_no_patch() {
int APS5_VABI _ZNK15AbstractStorage4Item12GetThumbnailEPSt10shared_ptrINS_7ContentEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("oc6n6hdUrEM", sceAbstractStorageUnknown_oc6n6hdUrEM_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_Cb7xWd9_7tc_nid_no_patch() {
int APS5_VABI _ZNK15AbstractStorage4Item15CreateThumbnailEPvPSt10shared_ptrINS_7ContentEE() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("Cb7xWd9-7tc", sceAbstractStorageUnknown_Cb7xWd9_7tc_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_mv9rtQAknH4_nid_no_patch() {
int APS5_VABI _ZNK15AbstractStorage6Folder7GetTypeEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("mv9rtQAknH4", sceAbstractStorageUnknown_mv9rtQAknH4_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_ka5TVf37Akg_nid_no_patch() {
int APS5_VABI _ZNK15AbstractStorage7Content7GetTypeEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("ka5TVf37Akg", sceAbstractStorageUnknown_ka5TVf37Akg_nid_no_patch);
int APS5_VABI sceAbstractStorageUnknown_1uryzAWFUuA_nid_no_patch() {
int APS5_VABI _ZNK15AbstractStorage7Storage7GetTypeEv() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("1uryzAWFUuA", sceAbstractStorageUnknown_1uryzAWFUuA_nid_no_patch);
}
@@ -0,0 +1,118 @@
#pragma once
#include "SceTypes.hpp"
extern "C" {
int APS5_VABI _ZN15AbstractStorage12Serializable12readExternalESt10shared_ptrINS_7ContentEE();
int APS5_VABI _ZN15AbstractStorage12Serializable13writeExternalESt10shared_ptrINS_7ContentEE();
int APS5_VABI _ZN15AbstractStorage12SerializableC1Ev();
int APS5_VABI _ZN15AbstractStorage12SerializableC2Ev();
int APS5_VABI _ZN15AbstractStorage12SerializableD1Ev();
int APS5_VABI _ZN15AbstractStorage12SerializableD2Ev();
int APS5_VABI _ZN15AbstractStorage14MemfileContent12readExternalESt10shared_ptrINS_7ContentEE();
int APS5_VABI _ZN15AbstractStorage14MemfileContent13writeExternalESt10shared_ptrINS_7ContentEE();
int APS5_VABI _ZN15AbstractStorage14MemfileContent14CreateInstanceESbIcSt11char_traitsIcENS_8StlAllocIcEEEN3paf6common9SharedPtrINS6_6BufferEEE();
int APS5_VABI _ZN15AbstractStorage14MemfileContent14CreateInstanceESbIcSt11char_traitsIcENS_8StlAllocIcEEEPvm();
int APS5_VABI _ZN15AbstractStorage14MemfileContent4OpenEit();
int APS5_VABI _ZN15AbstractStorage14MemfileContent4ReadEPvlPl();
int APS5_VABI _ZN15AbstractStorage14MemfileContent5CloseEv();
int APS5_VABI _ZN15AbstractStorage14MemfileContent5FlushEv();
int APS5_VABI _ZN15AbstractStorage14MemfileContent5WriteEPKvlPl();
int APS5_VABI _ZN15AbstractStorage14MemfileContent6RemoveEv();
int APS5_VABI _ZN15AbstractStorage14MemfileContent8SeekByteEliPl();
int APS5_VABI _ZN15AbstractStorage14MemfileContent8SeekTimeElPl();
int APS5_VABI _ZN15AbstractStorage14MemfileContentC1ESbIcSt11char_traitsIcENS_8StlAllocIcEEEN3paf6common9SharedPtrINS6_6BufferEEE();
int APS5_VABI _ZN15AbstractStorage14MemfileContentC2ESbIcSt11char_traitsIcENS_8StlAllocIcEEEN3paf6common9SharedPtrINS6_6BufferEEE();
int APS5_VABI _ZN15AbstractStorage14MemfileContentD0Ev();
int APS5_VABI _ZN15AbstractStorage14MemfileContentD1Ev();
int APS5_VABI _ZN15AbstractStorage14MemfileContentD2Ev();
int APS5_VABI _ZN15AbstractStorage14StorageManager10GetStorageERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEPSt10shared_ptrINS_7StorageEE();
int APS5_VABI _ZN15AbstractStorage14StorageManager10InitializeEv();
int APS5_VABI _ZN15AbstractStorage14StorageManager11GetInstanceERNS_12MemAllocatorEPv();
int APS5_VABI _ZN15AbstractStorage14StorageManager11GetInstanceEv();
int APS5_VABI _ZN15AbstractStorage14StorageManager12NotifyCreateERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEb();
int APS5_VABI _ZN15AbstractStorage14StorageManager12NotifyRemoveERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEb();
int APS5_VABI _ZN15AbstractStorage14StorageManager15ReleaseInstanceEv();
int APS5_VABI _ZN15AbstractStorage14StorageManager16NotifyWriteCloseERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage14StorageManager16RegisterListenerEPNS_17ItemEventListenerE();
int APS5_VABI _ZN15AbstractStorage14StorageManager16RegisterListenerEPNS_20StorageEventListenerE();
int APS5_VABI _ZN15AbstractStorage14StorageManager16get_storage_nameERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage14StorageManager17NotifySetMetadataERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage14StorageManager18GetStorageNameListEPSt6vectorISbIcSt11char_traitsIcENS_8StlAllocIcEEESaIS6_EE();
int APS5_VABI _ZN15AbstractStorage14StorageManager18UnregisterListenerEPKNS_17ItemEventListenerE();
int APS5_VABI _ZN15AbstractStorage14StorageManager18UnregisterListenerEPKNS_20StorageEventListenerE();
int APS5_VABI _ZN15AbstractStorage14StorageManager20get_service_instanceENS_11ServiceTypeE();
int APS5_VABI _ZN15AbstractStorage14StorageManager21NotifyStorageAttachedERKSbIcSt11char_traitsIcENS_8StlAllocIcEEENS_11ServiceTypeE();
int APS5_VABI _ZN15AbstractStorage14StorageManager21NotifyStorageDetachedERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage14StorageManager4FreeEPv();
int APS5_VABI _ZN15AbstractStorage14StorageManager4LoadENS_11ServiceTypeE();
int APS5_VABI _ZN15AbstractStorage14StorageManager6MallocEm();
int APS5_VABI _ZN15AbstractStorage14StorageManager6UnloadENS_11ServiceTypeE();
int APS5_VABI _ZN15AbstractStorage14StorageManager6UpdateENS_11ServiceTypeE();
int APS5_VABI _ZN15AbstractStorage14StorageManager9TerminateEv();
int APS5_VABI _ZN15AbstractStorage14StorageManagerC1Ev();
int APS5_VABI _ZN15AbstractStorage14StorageManagerC2Ev();
int APS5_VABI _ZN15AbstractStorage14StorageManagerD1Ev();
int APS5_VABI _ZN15AbstractStorage14StorageManagerD2Ev();
int APS5_VABI _ZN15AbstractStorage15HttpTransaction15SendHttpRequestERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEiRKSt3mapIS5_S5_St4lessIS5_ESaISt4pairIS6_S5_EEEmb();
int APS5_VABI _ZN15AbstractStorage15HttpTransaction4InitEv();
int APS5_VABI _ZN15AbstractStorage15HttpTransaction4TermEv();
int APS5_VABI _ZN15AbstractStorage15HttpTransaction8SendDataEPKvm();
int APS5_VABI _ZN15AbstractStorage15HttpTransactionC1Ev();
int APS5_VABI _ZN15AbstractStorage15HttpTransactionC2Ev();
int APS5_VABI _ZN15AbstractStorage15HttpTransactionD1Ev();
int APS5_VABI _ZN15AbstractStorage15HttpTransactionD2Ev();
int APS5_VABI _ZN15AbstractStorage4Item11GetPathNameEv();
int APS5_VABI _ZN15AbstractStorage4Item11SetMetadataEPN23sceMetadataReaderWriter8MetadataE();
int APS5_VABI _ZN15AbstractStorage4Item13ParseMetadataEPN23sceMetadataReaderWriter8MetadataES3_();
int APS5_VABI _ZN15AbstractStorage4Item14GetStorageNameEv();
int APS5_VABI _ZN15AbstractStorage4Item6RenameERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage4Item7GetNameERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage4Item7GetNameEv();
int APS5_VABI _ZN15AbstractStorage4Item8set_metaERN23sceMetadataReaderWriter8MetadataERKSbIcSt11char_traitsIcENS_8StlAllocIcEEESA_();
int APS5_VABI _ZN15AbstractStorage4Item8set_metaERN23sceMetadataReaderWriter8MetadataERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEm();
int APS5_VABI _ZN15AbstractStorage4ItemC2ERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage4ItemD0Ev();
int APS5_VABI _ZN15AbstractStorage4ItemD1Ev();
int APS5_VABI _ZN15AbstractStorage4ItemD2Ev();
int APS5_VABI _ZN15AbstractStorage4ItemdlEPv();
int APS5_VABI _ZN15AbstractStorage4ItemnwEm();
int APS5_VABI _ZN15AbstractStorage6FolderC2ERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage6FolderD0Ev();
int APS5_VABI _ZN15AbstractStorage6FolderD1Ev();
int APS5_VABI _ZN15AbstractStorage6FolderD2Ev();
int APS5_VABI _ZN15AbstractStorage7AbsFreeEPv();
int APS5_VABI _ZN15AbstractStorage7Content12GetExtensionERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage7Content12GetMimeTypesEv();
int APS5_VABI _ZN15AbstractStorage7Content6RenameERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage7ContentC2ERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage7ContentD0Ev();
int APS5_VABI _ZN15AbstractStorage7ContentD1Ev();
int APS5_VABI _ZN15AbstractStorage7ContentD2Ev();
int APS5_VABI _ZN15AbstractStorage7Service11NextStorageERSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage7Service13CreateStorageERKSbIcSt11char_traitsIcENS_8StlAllocIcEEEPSt10shared_ptrINS_7StorageEE();
int APS5_VABI _ZN15AbstractStorage7Service18clear_storage_listEv();
int APS5_VABI _ZN15AbstractStorage7Service4LoadENS_11ServiceTypeE();
int APS5_VABI _ZN15AbstractStorage7Service4StopEv();
int APS5_VABI _ZN15AbstractStorage7Service5StartEv();
int APS5_VABI _ZN15AbstractStorage7Service6UnLoadEPS0_();
int APS5_VABI _ZN15AbstractStorage7ServiceC2Ev();
int APS5_VABI _ZN15AbstractStorage7ServiceD0Ev();
int APS5_VABI _ZN15AbstractStorage7ServiceD1Ev();
int APS5_VABI _ZN15AbstractStorage7ServiceD2Ev();
int APS5_VABI _ZN15AbstractStorage7StorageC2ERKSbIcSt11char_traitsIcENS_8StlAllocIcEEE();
int APS5_VABI _ZN15AbstractStorage7StorageD0Ev();
int APS5_VABI _ZN15AbstractStorage7StorageD1Ev();
int APS5_VABI _ZN15AbstractStorage7StorageD2Ev();
int APS5_VABI _ZN15AbstractStorage9AbsMallocEm();
int APS5_VABI _ZNK15AbstractStorage14MemfileContent10GetServiceEv();
int APS5_VABI _ZNK15AbstractStorage14MemfileContent13GetCapabilityEv();
int APS5_VABI _ZNK15AbstractStorage14MemfileContent7GetStatEPNS_4StatE();
int APS5_VABI _ZNK15AbstractStorage4Item12GetThumbnailEPSt10shared_ptrINS_7ContentEE();
int APS5_VABI _ZNK15AbstractStorage4Item15CreateThumbnailEPvPSt10shared_ptrINS_7ContentEE();
int APS5_VABI _ZNK15AbstractStorage6Folder7GetTypeEv();
int APS5_VABI _ZNK15AbstractStorage7Content7GetTypeEv();
int APS5_VABI _ZNK15AbstractStorage7Storage7GetTypeEv();
}
@@ -1,3 +1,4 @@
#pragma once
#include "prx/libSceAbstractStorage/include/Api.hpp"
#include "prx/libSceAbstractStorage/include/InventoryExports.hpp"
#include "prx/libSceAbstractStorage/include/LegacyExports.hpp"
@@ -1,3 +1,6 @@
#include "prx/libSceAbstractYoutube/include/LegacyExports.hpp"
#include "prx/libc/include/general/ExportMacros.hpp"
#include "prx/libSceAbstractYoutube/include/InventoryExports.hpp"
#include <cstddef>
#include <cstdint>
#include "SceTypes.hpp"
@@ -92,3 +95,267 @@ int APS5_VABI sceAbstractYoutubeUnknown_vJGnqFj6ygE_nid_no_patch() {
APS5_EXPORT("vJGnqFj6ygE", sceAbstractYoutubeUnknown_vJGnqFj6ygE_nid_no_patch);
}
extern "C" {
int APS5_VABI _ZN15AbstractStorage13YoutubeFolder6RemoveEb() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage13YoutubeFolderD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage13YoutubeFolderD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage13YoutubeFolderD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent11SetMetadataEPN23sceMetadataReaderWriter8MetadataE() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent13ParseMetadataEPN23sceMetadataReaderWriter8MetadataES3_() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent4OpenEit() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent4ReadEPvlPl() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent5CloseEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent5FlushEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent5WriteEPKvlPl() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent6RemoveEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent8SeekByteEliPl() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContent8SeekTimeElPl() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContentD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContentD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeContentD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeService13SearchStorageEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeService4StopEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeService5StartEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceC1Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceC2Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeStorage14GetStorageSizeEPlS1_S1_() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeStorageD0Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeStorageD1Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZN15AbstractStorage14YoutubeStorageD2Ev() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage13YoutubeFolder10GetServiceEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage13YoutubeFolder13GetCapabilityEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage13YoutubeFolder7GetStatEPNS_4StatE() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage14YoutubeContent10GetServiceEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage14YoutubeContent13GetCapabilityEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage14YoutubeContent7GetStatEPNS_4StatE() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage14YoutubeService14GetServiceTypeEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage14YoutubeStorage10GetServiceEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage14YoutubeStorage13GetCapabilityEv() {
NotImplemented_nid_no_patch(__func__);
}
int APS5_VABI _ZNK15AbstractStorage14YoutubeStorage7GetStatEPNS_4StatE() {
NotImplemented_nid_no_patch(__func__);
}
}
extern "C" {
int APS5_VABI abstractYoutubeLegacyUnknown__plus_XiOtdILEHI_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("+XiOtdILEHI", abstractYoutubeLegacyUnknown__plus_XiOtdILEHI_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_4orcGYZG2cE_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("4orcGYZG2cE", abstractYoutubeLegacyUnknown_4orcGYZG2cE_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_6svBaAI4Ggw_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("6svBaAI4Ggw", abstractYoutubeLegacyUnknown_6svBaAI4Ggw_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_CCv9CYanMNI_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("CCv9CYanMNI", abstractYoutubeLegacyUnknown_CCv9CYanMNI_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_EEx55k0zSLo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("EEx55k0zSLo", abstractYoutubeLegacyUnknown_EEx55k0zSLo_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_HYDApQYDgcI_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("HYDApQYDgcI", abstractYoutubeLegacyUnknown_HYDApQYDgcI_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_IGnFlGNW_plus_Vo_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("IGnFlGNW+Vo", abstractYoutubeLegacyUnknown_IGnFlGNW_plus_Vo_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_JzBDUIC5xok_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("JzBDUIC5xok", abstractYoutubeLegacyUnknown_JzBDUIC5xok_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_NPYN89qO2Ks_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("NPYN89qO2Ks", abstractYoutubeLegacyUnknown_NPYN89qO2Ks_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_P_plus_ZjKSLi5lg_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("P+ZjKSLi5lg", abstractYoutubeLegacyUnknown_P_plus_ZjKSLi5lg_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_RkaqMMDQJp4_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("RkaqMMDQJp4", abstractYoutubeLegacyUnknown_RkaqMMDQJp4_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_ZpVRh3D86UY_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("ZpVRh3D86UY", abstractYoutubeLegacyUnknown_ZpVRh3D86UY_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_ZwkYXHwQ7Mc_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("ZwkYXHwQ7Mc", abstractYoutubeLegacyUnknown_ZwkYXHwQ7Mc_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_cktbTmca48I_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("cktbTmca48I", abstractYoutubeLegacyUnknown_cktbTmca48I_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_fUXj4GBxyHs_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("fUXj4GBxyHs", abstractYoutubeLegacyUnknown_fUXj4GBxyHs_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_g58APdyJ_minus_5Y_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("g58APdyJ-5Y", abstractYoutubeLegacyUnknown_g58APdyJ_minus_5Y_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_hXCJIJZZ5MY_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("hXCJIJZZ5MY", abstractYoutubeLegacyUnknown_hXCJIJZZ5MY_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_kgeuOe7oln8_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("kgeuOe7oln8", abstractYoutubeLegacyUnknown_kgeuOe7oln8_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_pR9ULw2VrSs_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("pR9ULw2VrSs", abstractYoutubeLegacyUnknown_pR9ULw2VrSs_nid_no_patch);
int APS5_VABI abstractYoutubeLegacyUnknown_tjbj7QysZwk_nid_no_patch() {
NotImplemented_nid_no_patch(__func__);
}
APS5_EXPORT("tjbj7QysZwk", abstractYoutubeLegacyUnknown_tjbj7QysZwk_nid_no_patch);
}
@@ -0,0 +1,47 @@
#pragma once
#include "SceTypes.hpp"
extern "C" {
int APS5_VABI _ZN15AbstractStorage13YoutubeFolder6RemoveEb();
int APS5_VABI _ZN15AbstractStorage13YoutubeFolderD0Ev();
int APS5_VABI _ZN15AbstractStorage13YoutubeFolderD1Ev();
int APS5_VABI _ZN15AbstractStorage13YoutubeFolderD2Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent11SetMetadataEPN23sceMetadataReaderWriter8MetadataE();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent13ParseMetadataEPN23sceMetadataReaderWriter8MetadataES3_();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent4OpenEit();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent4ReadEPvlPl();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent5CloseEv();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent5FlushEv();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent5WriteEPKvlPl();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent6RemoveEv();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent8SeekByteEliPl();
int APS5_VABI _ZN15AbstractStorage14YoutubeContent8SeekTimeElPl();
int APS5_VABI _ZN15AbstractStorage14YoutubeContentD0Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeContentD1Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeContentD2Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeService13SearchStorageEv();
int APS5_VABI _ZN15AbstractStorage14YoutubeService4StopEv();
int APS5_VABI _ZN15AbstractStorage14YoutubeService5StartEv();
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceC1Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceC2Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceD0Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceD1Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeServiceD2Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeStorage14GetStorageSizeEPlS1_S1_();
int APS5_VABI _ZN15AbstractStorage14YoutubeStorageD0Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeStorageD1Ev();
int APS5_VABI _ZN15AbstractStorage14YoutubeStorageD2Ev();
int APS5_VABI _ZNK15AbstractStorage13YoutubeFolder10GetServiceEv();
int APS5_VABI _ZNK15AbstractStorage13YoutubeFolder13GetCapabilityEv();
int APS5_VABI _ZNK15AbstractStorage13YoutubeFolder7GetStatEPNS_4StatE();
int APS5_VABI _ZNK15AbstractStorage14YoutubeContent10GetServiceEv();
int APS5_VABI _ZNK15AbstractStorage14YoutubeContent13GetCapabilityEv();
int APS5_VABI _ZNK15AbstractStorage14YoutubeContent7GetStatEPNS_4StatE();
int APS5_VABI _ZNK15AbstractStorage14YoutubeService14GetServiceTypeEv();
int APS5_VABI _ZNK15AbstractStorage14YoutubeStorage10GetServiceEv();
int APS5_VABI _ZNK15AbstractStorage14YoutubeStorage13GetCapabilityEv();
int APS5_VABI _ZNK15AbstractStorage14YoutubeStorage7GetStatEPNS_4StatE();
}
@@ -0,0 +1,28 @@
#pragma once
#include "SceTypes.hpp"
extern "C" {
int APS5_VABI abstractYoutubeLegacyUnknown__plus_XiOtdILEHI_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_4orcGYZG2cE_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_6svBaAI4Ggw_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_CCv9CYanMNI_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_EEx55k0zSLo_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_HYDApQYDgcI_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_IGnFlGNW_plus_Vo_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_JzBDUIC5xok_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_NPYN89qO2Ks_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_P_plus_ZjKSLi5lg_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_RkaqMMDQJp4_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_ZpVRh3D86UY_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_ZwkYXHwQ7Mc_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_cktbTmca48I_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_fUXj4GBxyHs_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_g58APdyJ_minus_5Y_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_hXCJIJZZ5MY_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_kgeuOe7oln8_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_pR9ULw2VrSs_nid_no_patch();
int APS5_VABI abstractYoutubeLegacyUnknown_tjbj7QysZwk_nid_no_patch();
}
@@ -1 +1,3 @@
#pragma once
#include "prx/libSceAbstractYoutube/include/InventoryExports.hpp"
#include "prx/libSceAbstractYoutube/include/LegacyExports.hpp"
+13
View File
@@ -91,6 +91,19 @@ if(BUILD_TESTING)
endif()
endif()
add_test_executable(agc_draw_setup_tests EXCLUDE_FROM_ALL tests/DrawSetup.cpp)
target_include_directories(agc_draw_setup_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(agc_draw_setup_tests PRIVATE libSceAgc libc)
configure_windows_unwind(agc_draw_setup_tests)
if(BUILD_TESTING)
set_target_properties(agc_draw_setup_tests PROPERTIES EXCLUDE_FROM_ALL OFF)
add_test(NAME agc_draw_setup COMMAND agc_draw_setup_tests)
if(WIN32)
set_tests_properties(agc_draw_setup PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()
add_test_executable(agc_rewind_patch_tests EXCLUDE_FROM_ALL tests/RewindPatch.cpp)
target_include_directories(agc_rewind_patch_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(agc_rewind_patch_tests PRIVATE libSceAgc libc)
@@ -30,6 +30,8 @@
#include "prx/libSceAgc/Acb/include/Sync.hpp"
#include "prx/libSceAgc/Command/include/Packet.hpp"
#include "prx/libSceAgc/Command/include/Memory.hpp"
#include "prx/libSceAgc/Acb/include/Memory.hpp"
#include "prx/libSceAgc/DcbFlow/include/Memory.hpp"
#include "prx/libSceAgc/Command/include/RegisterDefaults.hpp"
#include "prx/libc/include/Shutdown.hpp"
@@ -835,6 +837,45 @@ void testAtomicGds() {
}
}
void testCopyDataAndComputeEvents() {
Storage graphics;
const auto* copy = sceAgcDcbCopyData(&graphics.buffer, 4, 1, 0x1122334450ull, 0xb, 2, 0x12345678u, 0, 1);
const std::array<std::uint32_t, 6> graphicsExpected{0xc0044000u, 0x42104205u, 0x12345678u, 0, 0x22334450u, 0x11u};
check(copy == graphics.words.data() && std::equal(graphicsExpected.begin(), graphicsExpected.end(), graphics.words.begin()), "graphics COPY_DATA packet mismatch");
Storage wide;
sceAgcDcbCopyData(&wide.buffer, 4, 0, 0x1000, 0xa, 0, 0x100000000ull, 1, 0);
check(wide.words[1] == 0x00010205u && wide.words[2] == 0 && wide.words[3] == 1, "a 64-bit immediate COPY_DATA lost its high word");
Storage compute;
sceAgcAcbCopyData(&compute.buffer, 2, 0, 0x4000, 5, 0, 7, 0, 0);
const std::array<std::uint32_t, 6> computeExpected{0xc0044000u, 0x205u, 7, 0, 0x4000u, 0};
check(std::equal(computeExpected.begin(), computeExpected.end(), compute.words.begin()), "compute COPY_DATA packet mismatch");
Storage rejected;
rejected.words.fill(0xa5a5a5a5u);
const auto rejectedWords = rejected.words;
const auto* rejectedCursor = rejected.buffer.cursor_up;
expectFailure([&] { sceAgcDcbCopyData(&rejected.buffer, 4, 4, 0x1000, 0xa, 0, 1, 0, 0); });
check(rejected.words == rejectedWords && rejected.buffer.cursor_up == rejectedCursor, "a refused packet changed the command buffer");
expectFailure([&] { sceAgcDcbCopyData(&rejected.buffer, 4, 0, 0x1000, 0xa, 4, 1, 0, 0); });
check(rejected.words == rejectedWords && rejected.buffer.cursor_up == rejectedCursor, "a refused packet changed the command buffer");
expectFailure([&] { sceAgcAcbCopyData(&rejected.buffer, 2, 0, 0x4000, 5, 0, 1, 2, 0); });
check(rejected.words == rejectedWords && rejected.buffer.cursor_up == rejectedCursor, "a refused packet changed the command buffer");
expectFailure([&] { sceAgcAcbCopyData(&rejected.buffer, 2, 0, 0x4000, 5, 0, 1, 0, 2); });
check(rejected.words == rejectedWords && rejected.buffer.cursor_up == rejectedCursor, "a refused packet changed the command buffer");
check(sceAgcDcbCopyDataGetSize() == 24 && sceAgcAcbCopyDataGetSize() == 24, "COPY_DATA packet sizes");
Storage events;
sceAgcAcbEventWrite(&events.buffer, 7, nullptr);
sceAgcAcbEventWrite(&events.buffer, 0x16, nullptr);
const std::array<std::uint32_t, 4> eventsExpected{0xc0004600u, 0x407u, 0xc0004600u, 0x16u};
check(std::equal(eventsExpected.begin(), eventsExpected.end(), events.words.begin()), "compute EVENT_WRITE packet mismatch");
Storage refused;
refused.words.fill(0xa5a5a5a5u);
const auto refusedWords = refused.words;
const auto* refusedCursor = refused.buffer.cursor_up;
expectFailure([&] { sceAgcAcbEventWrite(&refused.buffer, 0x40, nullptr); });
check(refused.words == refusedWords && refused.buffer.cursor_up == refusedCursor, "a refused packet changed the command buffer");
check(sceAgcAcbEventWriteGetSize(7) == 8, "compute EVENT_WRITE packet size");
}
void testDebugRaiseException() {
int result = -1;
try {
@@ -1080,6 +1121,7 @@ int main(int argc, char** argv) {
testEndOfPipePatches();
testAtomicGds();
testDebugRaiseException();
testCopyDataAndComputeEvents();
testDefaults();
testDefaultsTypes();
LibcRunShutdown_nid_postfix();
@@ -0,0 +1,88 @@
#include "prx/libSceAgc/Command/include/Packet.hpp"
#include "prx/libSceAgc/DcbDraw/include/DrawIndexed.hpp"
#include "prx/libSceAgc/DcbDraw/include/DrawNonIndexed.hpp"
#include "prx/libSceAgc/DcbDraw/include/IndexBuffer.hpp"
#include "prx/libSceAgc/DcbDraw/include/Instancing.hpp"
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstdio>
#include <stdexcept>
namespace {
struct Storage {
std::array<std::uint32_t, 64> words{};
CommandBuffer buffer{words.data(), words.data() + words.size(), words.data(), words.data() + words.size(), nullptr, nullptr, 0};
};
void check(bool condition, const char* message) {
if (!condition) throw std::runtime_error(message);
}
template <typename TAction>
void expectFailure(Storage& storage, TAction action, const char* message) {
const auto before = storage.words;
const auto* cursor = storage.buffer.cursor_up;
try {
action();
} catch (const std::runtime_error&) {
check(storage.words == before && storage.buffer.cursor_up == cursor, message);
return;
}
throw std::runtime_error(message);
}
template <std::size_t N>
void expectPacket(const Storage& storage, const std::uint32_t* packet, const std::uint32_t* start, const std::array<std::uint32_t, N>& expected, std::uint32_t size, const char* message) {
check(packet == start && std::equal(expected.begin(), expected.end(), packet), message);
check(storage.buffer.cursor_up == start + N, message);
check(size == N * sizeof(std::uint32_t), message);
}
void testNumInstances() {
Storage storage;
const auto* packet = sceAgcDcbSetNumInstances(&storage.buffer, 7);
expectPacket(storage, packet, storage.words.data(), std::array<std::uint32_t, 2>{0xc0002f00u, 7}, sceAgcDcbSetNumInstancesGetSize(), "NUM_INSTANCES packet mismatch");
}
void testIndexSize() {
Storage storage;
const auto* packet = sceAgcDcbSetIndexSize(&storage.buffer, 1, 2);
expectPacket(storage, packet, storage.words.data(), std::array<std::uint32_t, 3>{0xc0017a00u, 0x20000243u, 0x481u}, sceAgcDcbSetIndexSizeGetSize(), "index size packet mismatch");
const auto* objectId = sceAgcDcbSetIndexSize_0600(&storage.buffer, 2, 3, 1);
check(objectId == storage.words.data() + 3 && objectId[0] == 0xc0017a00u && objectId[1] == 0x20000243u && objectId[2] == (0x4c2u | 0x4000u), "index size packet with a per-instance object id mismatch");
expectFailure(storage, [&] { sceAgcDcbSetIndexSize(&storage.buffer, 3, 0); }, "an index size above 2 was accepted");
expectFailure(storage, [&] { sceAgcDcbSetIndexSize(&storage.buffer, 0, 4); }, "a cache policy above 3 was accepted");
expectFailure(storage, [&] { sceAgcDcbSetIndexSize_0600(&storage.buffer, 0, 0, 2); }, "a per-instance object id above 1 was accepted");
}
void testDrawIndexOffset() {
Storage storage;
const auto* packet = sceAgcDcbDrawIndexOffset(&storage.buffer, 12, 36, 0);
expectPacket(storage, packet, storage.words.data(), std::array<std::uint32_t, 5>{0xc0033500u, 36, 12, 36, 0}, sceAgcDcbDrawIndexOffsetGetSize(), "DRAW_INDEX_OFFSET_2 packet mismatch");
const auto* empty = sceAgcDcbDrawIndexOffset(&storage.buffer, 0, 0, 0);
check(empty == storage.words.data() + 5 && empty[1] == 1 && empty[3] == 0, "an empty indexed offset draw did not keep a maximum size of one");
}
void testDrawIndirect() {
Storage storage;
const auto* packet = sceAgcDcbDrawIndirect(&storage.buffer, 0x40, 0);
expectPacket(storage, packet, storage.words.data(), std::array<std::uint32_t, 5>{0xc0032400u, 0x40, 0x280, 0x280, 2}, sceAgcDcbDrawIndirectGetSize(), "DRAW_INDIRECT packet mismatch");
expectFailure(storage, [&] { sceAgcDcbDrawIndirect(&storage.buffer, 2, 0); }, "a misaligned indirect argument offset was accepted");
}
}
int main() {
try {
testNumInstances();
testIndexSize();
testDrawIndexOffset();
testDrawIndirect();
} catch (const std::exception& error) {
std::fprintf(stderr, "%s\n", error.what());
return 1;
}
}
+111 -2
View File
@@ -1,3 +1,24 @@
if(BUILD_TESTING)
add_test_executable(agc_preparation_inputs_tests
tests/PreparationInputs.cpp
Execution/src/Driver/Shaders/ShaderDiagnostics.cpp
${CMAKE_SOURCE_DIR}/core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp)
target_include_directories(agc_preparation_inputs_tests PRIVATE
${LIBS_INCLUDE_DIR}
$<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>
${ANYPS5_VULKAN_HEADERS_INCLUDE_DIR})
target_link_libraries(agc_preparation_inputs_tests PRIVATE libc)
configure_windows_unwind(agc_preparation_inputs_tests)
foreach(mode enabled disabled selected failure concurrent write-failure capture-write-failure)
add_test(NAME agc_preparation_inputs_${mode} COMMAND agc_preparation_inputs_tests ${mode})
set_tests_properties(agc_preparation_inputs_${mode} PROPERTIES TIMEOUT 20)
if(WIN32)
set_tests_properties(agc_preparation_inputs_${mode} PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endforeach()
endif()
function(ensure_agc_glslang)
if(TARGET glslang AND TARGET SPIRV AND TARGET glslang-standalone)
return()
@@ -31,6 +52,16 @@ endfunction()
ensure_agc_glslang()
if(BUILD_TESTING AND WIN32)
add_test_executable(agc_process_sampler_stack_tests tests/ProcessSamplerStack.cpp Execution/src/WorkerSampler.cpp)
target_include_directories(agc_process_sampler_stack_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(agc_process_sampler_stack_tests PRIVATE libc)
configure_windows_unwind(agc_process_sampler_stack_tests)
add_test(NAME agc_process_sampler_stack COMMAND agc_process_sampler_stack_tests)
set_tests_properties(agc_process_sampler_stack PROPERTIES TIMEOUT 20 ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
set(agcTextureDetileShaderSource ${CMAKE_CURRENT_SOURCE_DIR}/Graphics/shaders/TextureDetile.comp)
set(agcTextureDetileGeneratedRoot ${CMAKE_CURRENT_BINARY_DIR}/generated)
set(agcTextureDetileGeneratedDir ${agcTextureDetileGeneratedRoot}/prx/libSceAgcDriver/Graphics/shaders)
@@ -56,6 +87,28 @@ add_custom_command(
DEPENDS "${agcTextureDetileShaderSource}" glslang-standalone
VERBATIM
)
set(agcTextureDetileWordsShaderSpv ${agcTextureDetileGeneratedDir}/TextureDetileWords.spv)
set(agcTextureDetileWordsShaderHeader ${agcTextureDetileGeneratedDir}/TextureDetileWords_spv.h)
add_custom_command(
OUTPUT "${agcTextureDetileWordsShaderHeader}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${agcTextureDetileGeneratedDir}"
COMMAND "$<TARGET_FILE:glslang-standalone>" -V --target-env vulkan1.1 -DWORD_GROUPS=1 -o "${agcTextureDetileWordsShaderSpv}" "${agcTextureDetileShaderSource}"
COMMAND ${CMAKE_COMMAND} -DINPUT=${agcTextureDetileWordsShaderSpv} -DOUTPUT=${agcTextureDetileWordsShaderHeader}
-DSYMBOL=TEXTURE_DETILE_WORDS_SPV -P "${CMAKE_CURRENT_SOURCE_DIR}/embed_spirv.cmake"
DEPENDS "${agcTextureDetileShaderSource}" glslang-standalone
VERBATIM
)
set(agcTextureDetileImageWordsShaderSpv ${agcTextureDetileGeneratedDir}/TextureDetileImageWords.spv)
set(agcTextureDetileImageWordsShaderHeader ${agcTextureDetileGeneratedDir}/TextureDetileImageWords_spv.h)
add_custom_command(
OUTPUT "${agcTextureDetileImageWordsShaderHeader}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${agcTextureDetileGeneratedDir}"
COMMAND "$<TARGET_FILE:glslang-standalone>" -V --target-env vulkan1.1 -DLINEAR_IMAGE=1 -DWORD_GROUPS=1 -o "${agcTextureDetileImageWordsShaderSpv}" "${agcTextureDetileShaderSource}"
COMMAND ${CMAKE_COMMAND} -DINPUT=${agcTextureDetileImageWordsShaderSpv} -DOUTPUT=${agcTextureDetileImageWordsShaderHeader}
-DSYMBOL=TEXTURE_DETILE_IMAGE_WORDS_SPV -P "${CMAKE_CURRENT_SOURCE_DIR}/embed_spirv.cmake"
DEPENDS "${agcTextureDetileShaderSource}" glslang-standalone
VERBATIM
)
set(agcMeshArgumentsShaderSource ${CMAKE_CURRENT_SOURCE_DIR}/Graphics/shaders/MeshArguments.comp)
foreach(agcReadbackKind IN ITEMS Uint Depth)
@@ -103,6 +156,19 @@ add_custom_command(
VERBATIM
)
set(agcStagingCopyBackShaderSource ${CMAKE_CURRENT_SOURCE_DIR}/Graphics/shaders/StagingCopyBack.comp)
set(agcStagingCopyBackShaderSpv ${agcTextureDetileGeneratedDir}/StagingCopyBack.spv)
set(agcStagingCopyBackShaderHeader ${agcTextureDetileGeneratedDir}/StagingCopyBack_spv.h)
add_custom_command(
OUTPUT "${agcStagingCopyBackShaderHeader}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${agcTextureDetileGeneratedDir}"
COMMAND "$<TARGET_FILE:glslang-standalone>" -V --target-env vulkan1.1 -o "${agcStagingCopyBackShaderSpv}" "${agcStagingCopyBackShaderSource}"
COMMAND ${CMAKE_COMMAND} -DINPUT=${agcStagingCopyBackShaderSpv} -DOUTPUT=${agcStagingCopyBackShaderHeader}
-DSYMBOL=STAGING_COPY_BACK_SPV -P "${CMAKE_CURRENT_SOURCE_DIR}/embed_spirv.cmake"
DEPENDS "${agcStagingCopyBackShaderSource}" glslang-standalone
VERBATIM
)
set(agcCmaskClearShaderSource ${CMAKE_CURRENT_SOURCE_DIR}/Graphics/shaders/CmaskClear.comp)
set(agcCmaskClearShaderSpv ${agcTextureDetileGeneratedDir}/CmaskClear.spv)
set(agcCmaskClearShaderHeader ${agcTextureDetileGeneratedDir}/CmaskClear_spv.h)
@@ -167,6 +233,23 @@ add_custom_command(
DEPENDS "${agcSampleDumpsShaderSource}" glslang-standalone
VERBATIM
)
function(agc_embedded_shader SOURCE STEM SYMBOL OUT_LIST)
set(source "${CMAKE_CURRENT_SOURCE_DIR}/Graphics/shaders/${SOURCE}")
set(spv "${agcTextureDetileGeneratedDir}/${STEM}.spv")
set(header "${agcTextureDetileGeneratedDir}/${STEM}_spv.h")
add_custom_command(
OUTPUT "${header}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${agcTextureDetileGeneratedDir}"
COMMAND "$<TARGET_FILE:glslang-standalone>" -V --target-env vulkan1.1 -o "${spv}" "${source}"
COMMAND ${CMAKE_COMMAND} -DINPUT=${spv} -DOUTPUT=${header}
-DSYMBOL=${SYMBOL} -P "${CMAKE_CURRENT_SOURCE_DIR}/embed_spirv.cmake"
DEPENDS "${source}" glslang-standalone
VERBATIM
)
set(${OUT_LIST} ${${OUT_LIST}} "${header}" PARENT_SCOPE)
endfunction()
set(agcDepthTransferShaderHeaders)
agc_embedded_shader(DepthToStorage.comp DepthToStorage DEPTH_TO_STORAGE_SPV agcDepthTransferShaderHeaders)
foreach(agcPresentationStage IN ITEMS Vert Frag)
string(TOLOWER "${agcPresentationStage}" agcPresentationExtension)
string(TOUPPER "${agcPresentationStage}" agcPresentationSymbol)
@@ -372,12 +455,16 @@ set(agcDriverSources
${agcMultisampleUploadHeader}
${agcCmaskClearShaderHeader}
${agcMeshArgumentsShaderHeader}
${agcStagingCopyBackShaderHeader}
${agcTextureDetileImageShaderHeader}
${agcTextureRepackShaderHeader}
${agcDispatchArgumentsShaderHeader}
${agcTextureDetileWordsShaderHeader}
${agcTextureDetileImageWordsShaderHeader}
${agcSampleCounterShaderHeader}
${agcSampleDumpsShaderHeader}
${agcPresentationShaderHeaders}
${agcDepthTransferShaderHeaders}
${CMAKE_CURRENT_SOURCE_DIR}/Eq/src/Event.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Eq/src/Query.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Resource/src/Lifecycle.cpp
@@ -426,6 +513,10 @@ add_shader_recompiler(shader_recompiler_agc_driver libc
${agcShaderCacheGuardSources}
)
target_include_directories(libSceAgcDriver INTERFACE
$<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>
)
target_link_libraries(libSceAgcDriver PRIVATE
shader_recompiler_agc_driver
decoder_png
@@ -665,12 +756,14 @@ foreach(agcTestFragment IN LISTS agcTestFragments)
include(${agcTestFragment})
endforeach()
target_include_directories(agc_driver_gcn_compare_exec_writes_tests PRIVATE $<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>)
if(BUILD_TESTING)
set_tests_properties(agc_driver_msaa_dcc_state ${multisampledDccClearTests} PROPERTIES
ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1" TIMEOUT 30 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
set_tests_properties(${multisampledDccClearTests} PROPERTIES SKIP_RETURN_CODE 77)
if(WIN32)
set_tests_properties(agc_driver_dithered_alpha_to_coverage agc_driver_two_sample_dithered_alpha_to_coverage ${multisampledDccClearTests} PROPERTIES ENVIRONMENT_MODIFICATION
set_tests_properties(agc_driver_dithered_alpha_to_coverage agc_driver_two_sample_dithered_alpha_to_coverage agc_driver_alpha_to_coverage_sample_mask_export agc_driver_two_sample_alpha_to_coverage_sample_mask_export ${multisampledDccClearTests} PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()
@@ -734,7 +827,7 @@ if(BUILD_TESTING)
BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH "$ORIGIN")
endif()
foreach(partialStoreTest agc_driver_depth_plane_partial_store_unimported agc_driver_depth_plane_partial_store_buffer_copy)
foreach(partialStoreTest agc_driver_depth_plane_partial_store_unimported agc_driver_depth_plane_partial_store_image_copy agc_driver_depth_plane_partial_store_buffer_copy)
set_tests_properties(${partialStoreTest} PROPERTIES
ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1;APS5_NO_HOST_IMPORT=1" TIMEOUT 30 SKIP_RETURN_CODE 77 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
if(WIN32)
@@ -901,6 +994,22 @@ target_link_libraries(agc_compute_pipeline_replay PRIVATE libSceAgcDriver libc)
set_target_properties(agc_compute_pipeline_replay PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_compute_pipeline_replay)
add_library(agc_oracle_support STATIC tools/OracleCodeObject.cpp tools/OracleDispatch.cpp)
target_include_directories(agc_oracle_support PUBLIC
${LIBS_INCLUDE_DIR}
$<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>
${CMAKE_SOURCE_DIR}/core/shader/recompiler
${ANYPS5_VULKAN_HEADERS_INCLUDE_DIR}
${ANYPS5_SPIRV_HEADERS_INCLUDE_DIR}
)
target_link_libraries(agc_oracle_support PUBLIC libSceAgcDriver libc)
set_target_properties(agc_oracle_support PROPERTIES CXX_EXTENSIONS OFF)
add_executable(agc_oracle_runner EXCLUDE_FROM_ALL tools/OracleRunner.cpp)
target_link_libraries(agc_oracle_runner PRIVATE agc_oracle_support)
set_target_properties(agc_oracle_runner PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_oracle_runner)
if(BUILD_TESTING AND ANYPS5_ENABLE_SPIRV_TOOLS)
add_test(NAME agc_compute_pipeline_inspection COMMAND ${CMAKE_COMMAND}
-DREPLAY=$<TARGET_FILE:agc_compute_pipeline_replay>
+10 -3
View File
@@ -54,13 +54,14 @@ int AddEvent(KernelEqueue eq, std::uint32_t queue, std::uintptr_t ident, void* u
}
int DeleteEvent(KernelEqueue eq, std::uintptr_t ident, const char* caller) {
{
std::lock_guard lock(g_mutex);
std::erase_if(g_registrations, [&](const Registration& r) { return r.eq == eq && r.ident == ident; });
if (eq == 0 || !EqueuePin_nid_postfix(eq)) {
throw std::runtime_error(std::string(caller) + ": invalid event queue");
}
if (EqueueDeleteEvent_nid_postfix(eq, ident, EvfiltGraphicsCore) != EQUEUE_OK) {
throw std::runtime_error(std::string(caller) + ": event is not registered");
}
std::lock_guard lock(g_mutex);
std::erase_if(g_registrations, [&](const Registration& r) { return r.eq == eq && r.ident == ident; });
return 0;
}
@@ -85,10 +86,16 @@ bool AgcDriverDeliverEopInterrupt(std::uint32_t queue) {
extern "C" {
int APS5_VABI sceAgcDriverAddEqEvent(KernelEqueue eq, int id, void* udata) {
if (id < 0) {
throw std::runtime_error(std::string(__func__) + ": negative event id");
}
return AddEvent(eq, static_cast<std::uint32_t>(id), static_cast<std::uintptr_t>(id), udata, __func__);
}
int APS5_VABI sceAgcDriverDeleteEqEvent(KernelEqueue eq, int id) {
if (id < 0) {
throw std::runtime_error(std::string(__func__) + ": negative event id");
}
return DeleteEvent(eq, static_cast<std::uintptr_t>(id), __func__);
}
@@ -3,6 +3,8 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Shaders/ShaderRegistry.hpp"
#include "prx/libSceAgcDriver/Execution/include/Recipe.hpp"
#include "prx/libc/include/GuestAllocations.hpp"
#include "IntermediateRepresentation/IrMetadata/ResourcePlan.hpp"
#include <algorithm>
#include <array>
#include <atomic>
@@ -15,12 +17,34 @@
#include <memory>
#include <set>
#include <span>
#include <span>
#include <utility>
#include <vector>
#include "prx/libc/include/general/AtomicSharedPtr.hpp"
namespace AgcDriver::DriverDetail {
inline bool CaptureRegisteredViewsCurrent(std::span<const ShaderRecompiler::RegisteredImageView> views) {
if (views.empty()) return true;
for (std::uint32_t attempt = 0; attempt < 2u; ++attempt) {
const auto before = GuestAllocations::GuestAllocationsGeneration_nid_postfix();
bool current = true;
for (const auto& view : views) {
const auto range = GuestAllocations::GuestAllocationsLookup_nid_postfix(static_cast<std::uintptr_t>(view.address), false);
if (view.hasRange != (range != nullptr)) {
current = false;
break;
}
if (range != nullptr && (range->address != view.rangeAddress || range->bytes != view.rangeBytes || range->allocationAddress != view.allocationAddress || range->allocationBytes != view.allocationBytes || range->backingSerial != view.backingSerial || range->readable != view.readable || range->writable != view.writable || range->gpu != view.gpu)) {
current = false;
break;
}
}
if (before == GuestAllocations::GuestAllocationsGeneration_nid_postfix()) return current;
}
return false;
}
inline constexpr std::size_t MaxDispatchVariants = 8;
struct DispatchVariant {
@@ -30,6 +54,7 @@ struct DispatchVariant {
std::vector<SharedWords> shared;
std::uint64_t forgetSerial = 0;
std::shared_ptr<const ShaderRecompiler::RecompileResult> compiled;
std::shared_ptr<const std::vector<ShaderRecompiler::RegisteredImageView>> registeredViews;
std::array<std::uint32_t, 4> meshIndexDescriptor{};
std::shared_ptr<const ShaderSnapshot> shader;
@@ -124,6 +124,7 @@ enum class DrawVerdict { Drawn, Nothing, Rejected };
struct StageCapture {
std::shared_ptr<const ShaderRecompiler::RecompileResult> compiled;
std::shared_ptr<const ShaderRecompiler::ResourceCapture> capture;
std::shared_ptr<const std::vector<ShaderRecompiler::RegisteredImageView>> registeredViews;
std::vector<ShaderRecompiler::MemoryRegion> regions;
std::vector<std::shared_ptr<const ShaderRecompiler::SrtGuestWords>> supplied;
std::uint64_t forgetSerial = 0;
@@ -184,6 +184,7 @@ struct PreparedShaders : PreparedShaderState {
std::atomic<bool> demanded{false};
bool pending = false;
std::vector<std::size_t> convertedSamples;
std::vector<std::size_t> layerRowSamples;
};
class SharedCode {
@@ -302,7 +303,7 @@ struct ShaderSnapshot {
};
std::shared_ptr<const ShaderSnapshot> ReadRawShader(std::uint64_t address);
std::shared_ptr<const ShaderSnapshot> ReadRawShader(std::uint64_t address, const std::shared_ptr<const ShaderSnapshot>& retained = {});
std::shared_ptr<const ShaderSnapshot> ReadUserDataTailContinuation(std::span<const std::uint32_t> code, std::uint32_t userDataBase, std::span<const std::uint32_t> userData);
std::shared_ptr<const ShaderSnapshot> ProgramSnapshot(const ShaderRegistry& shaders, std::uint64_t address, std::initializer_list<std::uint8_t> types);
void NoteRawGraphicsDraw(const ShaderSnapshot& snapshot);
@@ -9,6 +9,10 @@ inline bool FragmentShaderBarycentricUsable(VkDriverId driver, bool reported) {
return reported && driver != VK_DRIVER_ID_MOLTENVK;
}
inline bool HostInterpolationPreferred(VkDriverId driver) {
return driver == VK_DRIVER_ID_MESA_RADV;
}
}
#endif
@@ -54,6 +54,7 @@ void Write(std::uint64_t address, std::span<const std::byte> source, std::size_t
void WriteChanged(std::uint64_t address, std::span<const std::byte> current, std::span<const std::byte> original);
void WriteChanged(std::uint64_t address, std::span<const std::byte> current, std::span<const std::byte> original, std::uint32_t byteStoreLimit);
std::uint32_t ChangedByteStoreLimit();
void WriteChangedKeepingGuest(std::uint64_t address, std::span<const std::byte> current, std::span<const std::byte> original);
// Write tracking. The guest arena is reserved with page write watching, so CollectWrites learns which
// pages of a range the CPU wrote since they were last collected, stamps their 64 KiB blocks with a new
@@ -126,6 +127,7 @@ std::uint64_t CollectWritesUncached(std::uint64_t address, std::size_t bytes);
// tracker mutex, so every collect that bumped before it has finished its walk and every later
// collect stamps newer.
std::uint64_t TrackerGeneration();
void AdvanceTrackerGenerationForTest(std::uint64_t generation);
std::uint64_t NewestStamp(std::uint64_t address, std::size_t bytes);
std::uint64_t UntrackedHint(std::uint64_t address, std::size_t bytes);
// Whether no CPU write touched the range since `generation`: an uncached resetting collect of the
@@ -51,6 +51,8 @@ struct KeyboardGlyphEntry {
};
inline constexpr char32_t KeyboardFallbackCode = 0xFFFD;
inline constexpr std::uint8_t KeyboardCompositionMark = 1;
inline constexpr std::uint8_t KeyboardSelectionMark = 2;
std::span<const KeyboardGlyphEntry> KeyboardGlyphTable();
bool KeyboardHasGlyph(char32_t code);
@@ -14,6 +14,11 @@ namespace AgcDriver::Pm4 {
constexpr std::size_t GdsBytes = 0x10000;
std::uint64_t GdsAddress();
void RequestImportableGds(bool requested);
bool ImportableGdsRequested();
bool GdsShared();
bool GdsImportable();
void RejectGdsImport();
struct DrawParameters {
std::uint64_t indexAddress;
@@ -91,6 +91,7 @@ public:
private:
std::shared_ptr<const ShaderRecompiler::ResourceCapture> capture(const ShaderRecompiler::RecompileRequest& request, const ShaderRecompiler::SourceHandle* handle, const ShaderRecompiler::PreparedShaderInvocation* invocation);
std::shared_ptr<const ShaderRecompiler::ResourceCapture> captureWaitingOnFailure(const ShaderRecompiler::RecompileRequest& request, const ShaderRecompiler::SourceHandle* handle, const ShaderRecompiler::PreparedShaderInvocation* invocation);
static constexpr std::size_t PageBytes = 4096;
static constexpr std::size_t PageWords = PageBytes / sizeof(std::uint32_t);
@@ -169,6 +170,8 @@ private:
std::size_t descriptorSpanBytes = 0;
std::uint64_t rawInvalidations = 0;
std::uint32_t forceSync = 0;
std::uint64_t branchReadsRefused = 0;
bool waitBranches = false;
};
// The positions, among a dispatch-cache variant's stored words, of the pure flat-SRT leaves a
@@ -301,19 +301,19 @@ public:
// records. Null when nothing is prepared: the resource cache may serve the dispatch (its
// Revalidate stays under the mutex), or APS5_LOCKED_BUILD=1 keeps the whole build under it as
// before. `shader` and `snapshots` must outlive the dispatch.
std::shared_ptr<PreparedDispatch> PrepareDispatch(const ShaderRecompiler::RecompileResult& shader, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t dispatchThreads = 0, std::uint64_t programAddress = 0, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear = std::nullopt);
std::shared_ptr<PreparedDispatch> PrepareDispatch(const ShaderRecompiler::RecompileResult& shader, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t dispatchThreads = 0, std::uint64_t programAddress = 0, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear = std::nullopt, const std::vector<ShaderRecompiler::RegisteredImageView>* registeredImageViews = nullptr);
// APS5_PROFILE_DRAW: the parts of a PrepareDispatch in milliseconds, in the order key, find,
// precollect, presync, stage A (the driver's 'prepare:' rows).
static std::span<const double, 5> PreparePhaseMs(const PreparedDispatch& prepared);
// `recipe`, when given, receives the Recipe a successful call built for its dispatch-cache
// variant (design_cpu_final M4): only when the resource cache served or took the object
// (reusable, cacheable) and recipes are on (APS5_NO_DISPATCH_RECIPE=1 builds none); else null.
void Dispatch(const ShaderRecompiler::RecompileResult& shader, std::uint32_t x, std::uint32_t y, std::uint32_t z, std::span<const Graphics::GuestMemorySnapshot> snapshots = {}, std::uint64_t programAddress = 0, std::shared_ptr<PreparedDispatch> prepared = nullptr, std::shared_ptr<const Recipe>* recipe = nullptr, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear = std::nullopt);
void Dispatch(const ShaderRecompiler::RecompileResult& shader, std::uint32_t x, std::uint32_t y, std::uint32_t z, std::span<const Graphics::GuestMemorySnapshot> snapshots = {}, std::uint64_t programAddress = 0, std::shared_ptr<PreparedDispatch> prepared = nullptr, std::shared_ptr<const Recipe>* recipe = nullptr, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear = std::nullopt, const std::vector<ShaderRecompiler::RegisteredImageView>* registeredImageViews = nullptr);
struct IndirectOutcome {
int cpuReason;
double argumentReadMs;
};
IndirectOutcome DispatchIndirect(const ShaderRecompiler::RecompileResult& shader, std::uint64_t arguments, std::span<const Graphics::GuestMemorySnapshot> snapshots = {}, std::uint64_t programAddress = 0, std::shared_ptr<PreparedDispatch> prepared = nullptr, std::shared_ptr<const Recipe>* recipe = nullptr, const std::array<std::uint32_t, 3>& threadGroup = {});
IndirectOutcome DispatchIndirect(const ShaderRecompiler::RecompileResult& shader, std::uint64_t arguments, std::span<const Graphics::GuestMemorySnapshot> snapshots = {}, std::uint64_t programAddress = 0, std::shared_ptr<PreparedDispatch> prepared = nullptr, std::shared_ptr<const Recipe>* recipe = nullptr, const std::array<std::uint32_t, 3>& threadGroup = {}, const std::vector<ShaderRecompiler::RegisteredImageView>* registeredImageViews = nullptr);
// A value-equal dispatch-cache hit with a recipe (design_cpu_final M4), in two steps.
// PrepareRecipe, WITHOUT GuestMemory::GpuMutex: the pre-checks (recipes on, the recipe's
// device is this one, its template and pipeline objects still alive), the template's
@@ -388,11 +388,12 @@ public:
private:
VulkanDevice(const PresentationWindow* window, bool compileOnly);
friend struct VulkanDeviceTestAccess;
std::pair<VkBuffer, std::uint64_t> scratchPoolHeader(const ShaderRecompiler::RecompileResult& shader) const;
VkPipeline splitComputePipeline(const Graphics::Context& context, const ShaderRecompiler::RecompileResult& shader, ComputePipelineObjects& objects, const std::array<std::uint32_t, 3>& base);
ShaderRecompiler::SpirvTarget buildTarget() const;
Graphics::Context buildContext() const;
// Body of Dispatch and DispatchIndirect: `arguments` 0 dispatches x, y, z groups.
IndirectOutcome dispatch(const ShaderRecompiler::RecompileResult& shader, std::uint32_t x, std::uint32_t y, std::uint32_t z, std::uint64_t arguments, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t programAddress, std::shared_ptr<PreparedDispatch> prepared, std::shared_ptr<const Recipe>* recipe, const std::array<std::uint32_t, 3>& threadGroup = {}, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear = std::nullopt);
IndirectOutcome dispatch(const ShaderRecompiler::RecompileResult& shader, std::uint32_t x, std::uint32_t y, std::uint32_t z, std::uint64_t arguments, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t programAddress, std::shared_ptr<PreparedDispatch> prepared, std::shared_ptr<const Recipe>* recipe, const std::array<std::uint32_t, 3>& threadGroup = {}, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear = std::nullopt, const std::vector<ShaderRecompiler::RegisteredImageView>* registeredImageViews = nullptr);
IndirectOutcome recordCompletedDispatch(const ShaderRecompiler::RecompileResult& shader, std::uint32_t x, std::uint32_t y, std::uint32_t z, std::uint64_t arguments, std::uint64_t programAddress, std::shared_ptr<const Recipe>* recipeOut, const std::array<std::uint32_t, 3>& threadGroup, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear, DispatchCompletion& completion);
// The stage-A pre-sync over `surfaces` (see PrepareDispatch): the serial waited for, 0 none.
std::uint64_t presync(std::span<const Graphics::PresyncSurface> surfaces);
@@ -8,6 +8,7 @@ namespace AgcDriver {
void StartWorkerSampler(std::uint32_t queue = 0);
void StartCommitterSampler();
void StopWorkerSampler();
bool ReadableStackRegion(std::uint64_t address, std::uint64_t& low, std::uint64_t& high);
}
@@ -307,7 +307,8 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
}
if (fromAhead) {
if (const auto hook = aheadAdoptHook.load(std::memory_order_acquire)) hook();
if (!CapturedCurrent(ahead.captured, snapshot)) {
const auto* aheadViews = ahead.capture != nullptr ? &ahead.capture->snapshot.registeredImages : ahead.keepVariant != nullptr && ahead.keepVariant->registeredViews != nullptr ? ahead.keepVariant->registeredViews.get() : nullptr;
if (!CapturedCurrent(ahead.captured, snapshot) || (aheadViews != nullptr && !CaptureRegisteredViewsCurrent(*aheadViews))) {
fromAhead = false;
++dispatchesRejectedAhead;
++groupStats.memoryMismatches;
@@ -427,6 +428,7 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
phaseTiming.Phase(PhaseRecompile);
if (!resolving) insertDispatch(address, key, noDispatchCache || !CacheableResult(*compiledResult), profile, registeredShader, forgetAtCapture, memory, shaderMemory, captured, capture, compiledResult, missedEntry, missedDiffering, attachVariant, phaseTiming);
}
const auto* registeredViews = capture != nullptr ? &capture->snapshot.registeredImages : keepVariant != nullptr && keepVariant->registeredViews != nullptr ? keepVariant->registeredViews.get() : nullptr;
if (resolving) {
auto& parked = resolvedAhead()[currentPacketOffset()];
parked = ResolvedDispatch{};
@@ -515,7 +517,7 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
const auto epoch = DrawPipeline::EpochToken().load(std::memory_order_relaxed);
const auto queueId = submission.queue;
itemCommits.fetch_add(1, std::memory_order_relaxed);
DrawPipeline::Queue0().Enqueue([this, localDevice = std::move(localDevice), result = compiledResult, snapshots = std::move(snapshots), liveWords = std::move(liveWords), groups, address, queueId, recipe, keepVariant, dataHit, epoch, htileClearCompletion, htileMask] {
DrawPipeline::Queue0().Enqueue([this, localDevice = std::move(localDevice), result = compiledResult, capture, registeredViews, snapshots = std::move(snapshots), liveWords = std::move(liveWords), groups, address, queueId, recipe, keepVariant, dataHit, epoch, htileClearCompletion, htileMask] {
DrawPipeline::FollowEpoch(epoch);
GuestMemory::SetCurrentPacket(0x15, queueId);
const auto& compiledCommit = *result;
@@ -526,7 +528,7 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
bool writersNoted = false;
for (;;) {
std::shared_ptr<PreparedDispatch> prepared;
if (recipeHit == nullptr || VulkanDevice::VerifyRecipes() || htileClearCompletion.has_value()) prepared = localDevice->PrepareDispatch(compiledCommit, snapshots, 0, address, htileClearCompletion);
if (recipeHit == nullptr || VulkanDevice::VerifyRecipes() || htileClearCompletion.has_value()) prepared = localDevice->PrepareDispatch(compiledCommit, snapshots, 0, address, htileClearCompletion, registeredViews);
GuestMemory::TagGpuLockSite(GuestMemory::GpuLockSite::Dispatch);
std::lock_guard gpuLock(GuestMemory::GpuMutex());
recordLabelsForPacket(localDevice.get(), queueId);
@@ -544,7 +546,7 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
continue;
}
} else {
localDevice->Dispatch(compiledCommit, groups[0], groups[1], groups[2], snapshots, address, std::move(prepared), htileClearCompletion.has_value() ? nullptr : &builtRecipe, htileClearCompletion);
localDevice->Dispatch(compiledCommit, groups[0], groups[1], groups[2], snapshots, address, std::move(prepared), htileClearCompletion.has_value() ? nullptr : &builtRecipe, htileClearCompletion, registeredViews);
}
if (htileMask.bytes != 0u) localDevice->NoteHtileMask(htileMask);
break;
@@ -601,7 +603,7 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
std::shared_ptr<PreparedDispatch> prepared;
if (recipeHit == nullptr || VulkanDevice::VerifyRecipes()) {
try {
prepared = localDevice->PrepareDispatch(compiled, snapshots, dispatchThreads, address, htileClearCompletion);
prepared = localDevice->PrepareDispatch(compiled, snapshots, dispatchThreads, address, htileClearCompletion, registeredViews);
} catch (const std::exception& error) {
if (rethrow(error)) return;
}
@@ -657,10 +659,10 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
}
if (indirectArguments != 0) countIndirect(outcome.cpuReason, outcome.argumentReadMs);
} else if (indirectArguments != 0) {
const auto outcome = localDevice->DispatchIndirect(compiled, indirectArguments, snapshots, address, std::move(prepared), attachTo != nullptr ? &builtRecipe : nullptr, threadGroup);
const auto outcome = localDevice->DispatchIndirect(compiled, indirectArguments, snapshots, address, std::move(prepared), attachTo != nullptr ? &builtRecipe : nullptr, threadGroup, registeredViews);
countIndirect(outcome.cpuReason, outcome.argumentReadMs);
} else {
localDevice->Dispatch(compiled, groups[0], groups[1], groups[2], snapshots, address, std::move(prepared), htileClearCompletion.has_value() ? nullptr : (attachTo != nullptr ? &builtRecipe : nullptr), htileClearCompletion);
localDevice->Dispatch(compiled, groups[0], groups[1], groups[2], snapshots, address, std::move(prepared), htileClearCompletion.has_value() ? nullptr : (attachTo != nullptr ? &builtRecipe : nullptr), htileClearCompletion, registeredViews);
}
} catch (const std::exception& error) {
if (rethrow(error)) return;
@@ -66,7 +66,7 @@ Driver::DispatchCacheFootprint Driver::DispatchCacheSize() {
std::uint64_t Driver::variantBytes(const DispatchVariant& variant) {
const auto held = [](const auto& values) { return static_cast<std::uint64_t>(values.capacity() * sizeof(values[0])); };
return sizeof(DispatchVariant) + held(variant.runs) + held(variant.words) + held(variant.shared) + held(variant.dataPositions) + held(variant.dataSlots) + held(variant.runBases) + held(variant.shaderDataPatches) + held(variant.captured) + held(variant.spans) + (variant.vertexInfo != nullptr ? sizeof(ShaderRecompiler::ShaderVertexStageInfo) : 0) + (variant.memory != nullptr ? variant.memory->Bytes() : 0);
return sizeof(DispatchVariant) + held(variant.runs) + held(variant.words) + held(variant.shared) + held(variant.dataPositions) + held(variant.dataSlots) + held(variant.runBases) + held(variant.shaderDataPatches) + held(variant.captured) + held(variant.spans) + (variant.registeredViews != nullptr ? held(*variant.registeredViews) : 0u) + (variant.vertexInfo != nullptr ? sizeof(ShaderRecompiler::ShaderVertexStageInfo) : 0) + (variant.memory != nullptr ? variant.memory->Bytes() : 0);
}
void Driver::accountVariant(const DispatchVariant& variant, bool added) {
@@ -18,6 +18,7 @@ void Driver::insertDispatch(std::uint64_t address, std::uint64_t key, bool noDis
if (!noDispatchCache) {
auto fresh = std::make_shared<DispatchVariant>();
fresh->compiled = compiledResult;
if (capture != nullptr && !capture->snapshot.registeredImages.empty()) fresh->registeredViews = std::make_shared<const std::vector<ShaderRecompiler::RegisteredImageView>>(capture->snapshot.registeredImages);
fresh->shader = registeredShader;
fresh->forgetSerial = forgetAtCapture;
@@ -1,5 +1,6 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include "Optimization/ResourceProgram.hpp"
#include <cstdlib>
namespace AgcDriver::DriverDetail {
@@ -37,6 +38,7 @@ void Driver::lookupDispatch(std::uint64_t address, const Submission& submission,
std::optional<SampledReadScope> sampling;
for (std::size_t i = 0; i < variants.size(); ++i) {
if (variants[i]->registeredViews != nullptr && !CaptureRegisteredViewsCurrent(*variants[i]->registeredViews)) continue;
regions.clear();
appendEntryRegions(*variants[i], regions);
++compared;
@@ -58,16 +60,20 @@ void Driver::lookupDispatch(std::uint64_t address, const Submission& submission,
current = variant != nullptr;
} else {
variant = variants.front();
compared = 1;
current = true;
for (const auto& [begin, bytes] : variant->spans) {
GuestMemory::CollectWrites(begin, bytes);
if (!GuestMemory::UnchangedSince(begin, bytes, generation)) {
current = false;
break;
current = variant->registeredViews == nullptr || CaptureRegisteredViewsCurrent(*variant->registeredViews);
if (!current) variant.reset();
if (variant != nullptr) {
compared = 1;
current = true;
for (const auto& [begin, bytes] : variant->spans) {
GuestMemory::CollectWrites(begin, bytes);
if (!GuestMemory::UnchangedSince(begin, bytes, generation)) {
current = false;
break;
}
}
}
if (!current) {
if (!current && variant != nullptr) {
std::uint64_t collected = 0;
for (const auto& [begin, bytes] : variant->spans) collected = std::max(collected, GuestMemory::CollectWrites(begin, bytes));
@@ -1,5 +1,6 @@
#include "prx/libSceAgcDriver/Execution/include/CaptureTrace.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp"
#include "Optimization/ResourceProgram.hpp"
#include "prx/libSceAgcDriver/Execution/include/CaptureTrace.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Diagnostics.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawPipeline.hpp"
@@ -657,6 +658,7 @@ DrawVerdict Driver::draw(QueueState& queue, std::span<const std::uint32_t> packe
throw;
}
for (std::size_t i = 0; i < matched.size(); ++i) {
if (matched[i] != nullptr) stageCaptures[i].registeredViews = matched[i]->registeredViews;
if (matched[i] == nullptr || (matched[i]->shaderDataPatches.empty() && matched[i]->descriptorPatches.empty())) continue;
applyShaderDataPatches(*matched[i]);
if (stageData[i].compiled != nullptr) stageData[i].compiled = patchDataWords(*matched[i], stageData[i].words);
@@ -923,6 +925,7 @@ DrawVerdict Driver::finishDraw(DrawTail& tail, PerformanceTimer& timing) {
const auto candidate = std::find_if(dataCandidates[i].begin(), dataCandidates[i].end(), [&](const auto& kept) { return kept.first->pushOffset == pushCursorBytes; });
if (candidate != dataCandidates[i].end() && !verifyDrawDataHits()) {
matched[i] = candidate->first;
stageCaptures[i].registeredViews = matched[i]->registeredViews;
matchedRegions[i] = std::move(candidate->second);
reused[i] = true;
programResults[i] = stageData[i].compiled != nullptr ? stageData[i].compiled.get() : matched[i]->compiled.get();
@@ -955,7 +958,7 @@ DrawVerdict Driver::finishDraw(DrawTail& tail, PerformanceTimer& timing) {
try {
const auto slotEnd = (pushCursorBytes / Graphics::PipelinePushSlotBytes + 1u) * Graphics::PipelinePushSlotBytes;
require(result.pushConstants.size() <= slotEnd - pushCursorBytes, "stage push constants exceed the pipeline push constant block");
stages.push_back({program.binary.stage, &result, result.pushConstants.empty() ? 0u : pushCursorBytes});
stages.push_back({program.binary.stage, &result, result.pushConstants.empty() ? 0u : pushCursorBytes, stageCaptures[i].registeredViews.get()});
pushCursorBytes += static_cast<std::uint32_t>(result.pushConstants.size());
} catch (...) {
TraceMaterializationFailure(trace.token, submission, packetOffset, "push-constant-validation", completedSubdraws, std::current_exception());
@@ -1058,6 +1061,7 @@ DrawVerdict Driver::finishDraw(DrawTail& tail, PerformanceTimer& timing) {
if (!rejected.empty()) return DrawVerdict::Rejected;
programResults[0] = compiledStages.back().get();
stages[0].program = programResults[0];
stages[0].registeredImageViews = stageCaptures[0].registeredViews.get();
require(programResults[0]->pushConstants.size() == pushBytes && programResults[0]->parameterExports == exports, "pairing the mesh program with its pixel shader changed the push constants or the parameter exports the pixel shader was built for");
}
require(programResults[0]->meshBarycentrics == meshBarycentrics, "the mesh program was compiled for a different barycentric layout than its pixel shader");
@@ -1175,6 +1179,7 @@ DrawVerdict Driver::finishDraw(DrawTail& tail, PerformanceTimer& timing) {
const auto pushBytes = result.pushConstants.size();
decodeVertexInfo(programIndex);
result = *materializeDrawStage(programIndex, pushOffsets[programIndex], queue, submission, packetOffset, trace.token, programs, graphics, pixel, vertexInfos, memory, linked, programs[programIndex].binary.stage == Stage::TessellationControl || programs[programIndex].binary.stage == Stage::TessellationEvaluation ? direct : drawParameters, localDevice, *shaderMemory, stageCaptures, recompiled, drawHit, matched, matchedRegions, profile, dumpTarget, dumpSlot1, captures, phaseTiming, phaseMs, rejected, meshBarycentrics);
for (auto& stage : stages) if (stage.program == &result) stage.registeredImageViews = stageCaptures[programIndex].registeredViews.get();
if (!rejected.empty()) return DrawVerdict::Rejected;
require(result.pushConstants.size() == pushBytes, "patched program changed its push constant layout");
}
@@ -227,8 +227,8 @@ void Driver::eraseDrawEntry(std::uint64_t key, const std::shared_ptr<DrawEntry>&
bool DecodeProgramsCurrent(const DrawDecode& decode, const ShaderRegistry&) {
return std::all_of(decode.programs.begin(), decode.programs.end(), [&](const DrawProgram& program) {
if (!program.snapshot->header.empty()) return true;
return ReadRawShader(program.snapshot->codeAddress + program.codeOffset * sizeof(std::uint32_t)) == program.snapshot &&
(program.tailContinuation == nullptr || ReadRawShader(program.tailContinuation->codeAddress) == program.tailContinuation);
return ReadRawShader(program.snapshot->codeAddress + program.codeOffset * sizeof(std::uint32_t), program.snapshot) == program.snapshot &&
(program.tailContinuation == nullptr || ReadRawShader(program.tailContinuation->codeAddress, program.tailContinuation) == program.tailContinuation);
});
}
@@ -117,6 +117,7 @@ std::shared_ptr<const ShaderRecompiler::RecompileResult> Driver::materializeDraw
stageCapture.regions = shaderMemory.TakeRecentRegions();
stageCapture.supplied = shaderMemory.SuppliedBlocks();
stageCapture.userDataUse = capture->userDataUse;
stageCapture.registeredViews = std::make_shared<const std::vector<ShaderRecompiler::RegisteredImageView>>(capture->snapshot.registeredImages);
recompiled[i] = true;
memory = shaderMemory.Regions();
@@ -225,6 +226,7 @@ void Driver::cacheDrawStages(bool useDrawEntries, bool drawHit, const Pm4::DrawP
if (stageCapture.compiled == nullptr || !CacheableResult(*stageCapture.compiled)) continue;
auto variant = std::make_shared<DispatchVariant>();
variant->compiled = stageCapture.compiled;
variant->registeredViews = stageCapture.registeredViews;
if (programs[i].binary.stage == ShaderRecompiler::ShaderStage::Mesh) {
std::copy_n(programs[i].userData.begin() + ShaderRecompiler::MeshIndexBufferUserWord, variant->meshIndexDescriptor.size(), variant->meshIndexDescriptor.begin());
}
@@ -1,6 +1,7 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Diagnostics.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include "Optimization/ResourceProgram.hpp"
#include <algorithm>
#include <bit>
@@ -141,6 +142,7 @@ void Driver::lookupDraw(const Submission& submission, const std::shared_ptr<Vulk
bool anyLayout = false;
for (std::size_t rank = 0; rank < variants.size(); ++rank) {
const auto& variant = variants[rank];
if (variant->registeredViews != nullptr && !CaptureRegisteredViewsCurrent(*variant->registeredViews)) continue;
if (variant->pushOffset != cursor) continue;
if (programs[i].binary.stage == ShaderRecompiler::ShaderStage::Mesh && !std::equal(variant->meshIndexDescriptor.begin(), variant->meshIndexDescriptor.end(), programs[i].userData.begin() + ShaderRecompiler::MeshIndexBufferUserWord)) {
if (!anyLayout) outcome = EntryOutcome::Differing;
@@ -249,6 +251,7 @@ void Driver::lookupDraw(const Submission& submission, const std::shared_ptr<Vulk
const auto& was = dataEntry->decode->programs[i].userData;
auto& candidates = dataCandidates[i];
for (const auto& variant : dataEntry->stages[i]) {
if (variant->registeredViews != nullptr && !CaptureRegisteredViewsCurrent(*variant->registeredViews)) continue;
bool usedEqual = true;
for (std::size_t w = 0; w < now.size() && usedEqual; ++w) {
if (now[w] != was[w] && (w >= 64u || ((variant->userDataMask >> w) & 1u) != 0)) usedEqual = false;
@@ -415,6 +415,7 @@ void Driver::execute(const Submission& submission) {
CheckFailure();
std::uint64_t batchesAtFlip = 0, unsignaledAtFlip = 0;
bool flipInterruptDeferred = false;
Graphics::StorageTexture::NoteFlip();
if (!drains) {
GuestMemory::TagGpuLockSite(GuestMemory::GpuLockSite::Flush);
@@ -16,16 +16,40 @@
#include <cstdlib>
#include <cstring>
#include <limits>
#include <optional>
namespace AgcDriver::DriverDetail {
namespace {
bool gdsWritesPending(std::span<const std::uint32_t> packet) {
bool gdsWritesPending(std::span<const std::uint32_t> packet, const VulkanDevice* localDevice) {
const auto address = Pm4::GdsAddress() + packet[4];
const auto bytes = static_cast<std::size_t>(Pm4::DmaBytes(packet));
const std::array<std::pair<std::uint64_t, std::uint64_t>, 1> range{{{address, address + bytes}}};
return Graphics::Recorder::SnapshotWriteOverlaps(address, bytes) || Graphics::StorageTexture::AnyPendingOverlaps(range) || Graphics::AnyShadowedOverlaps(address, bytes);
if (Graphics::Recorder::SnapshotWriteOverlaps(address, bytes) || Graphics::StorageTexture::AnyPendingOverlaps(range) || Graphics::AnyShadowedOverlaps(address, bytes)) return true;
if (localDevice == nullptr || !Pm4::GdsImportable()) return false;
std::lock_guard gpuLock(GuestMemory::GpuMutex());
return localDevice->StoresPendingOver(address, bytes);
}
std::uint64_t dmaAddress(std::uint32_t low, std::uint32_t high) {
return low | (static_cast<std::uint64_t>(high) << 32u);
}
bool gdsSpan(std::uint64_t offset, std::size_t bytes) {
return offset <= Pm4::GdsBytes && bytes <= Pm4::GdsBytes - offset;
}
std::optional<Pm4::MemoryCopy> decodeCopy(std::span<const std::uint32_t> packet) {
if (auto copy = Pm4::DecodeMemoryCopy(packet)) return copy;
if (packet.size() != 7 || !Pm4::GdsImportable()) return std::nullopt;
const auto source = Pm4::DmaSource(packet);
const auto destination = Pm4::DmaDestination(packet);
const std::size_t bytes = Pm4::DmaBytes(packet);
if (bytes == 0) return std::nullopt;
if (source == Pm4::DmaSelectGds && (destination == 0 || destination == 3) && gdsSpan(packet[2], bytes)) return Pm4::MemoryCopy{Pm4::GdsAddress() + packet[2], dmaAddress(packet[4], packet[5]), bytes};
if ((source == 0 || source == 3) && destination == Pm4::DmaSelectGds && gdsSpan(packet[4], bytes)) return Pm4::MemoryCopy{dmaAddress(packet[2], packet[3]), Pm4::GdsAddress() + packet[4], bytes};
return std::nullopt;
}
}
@@ -130,7 +154,7 @@ bool Driver::preparePacketMemory(const Submission& submission, QueueState& queue
if (!drainAll && !cpuStores && (opcode == 0x40 || opcode == 0x50 || opcode == 0x83)) {
constexpr std::size_t gpuStoreLimit = 65536;
bool drained = true;
const auto copy = opcode == 0x50 ? Pm4::DecodeMemoryCopy(packet) : std::nullopt;
const auto copy = opcode == 0x50 ? decodeCopy(packet) : std::nullopt;
const auto copyBehindPendingSource = [&] {
if (!copy.has_value() || copy->bytes > gpuStoreLimit || !GuestMemory::Accessible(reinterpret_cast<const void*>(copy->source), copy->bytes) || !GuestMemory::Accessible(reinterpret_cast<const void*>(copy->destination), copy->bytes, true)) return false;
const auto end = copy->source + copy->bytes;
@@ -148,16 +172,16 @@ bool Driver::preparePacketMemory(const Submission& submission, QueueState& queue
if (outcome.path != 1 && outcome.path != 3) throw std::runtime_error("AGC driver: a DMA_DATA copy of up to 64 KiB that GpuCopyPossible accepted took copy path " + std::to_string(outcome.path));
return true;
};
if (opcode == 0x50 && packet.size() >= 7 && Pm4::DmaDestination(packet) == Pm4::DmaSelectGds) {
if (!gdsWritesPending(packet)) {
orderedAlready = true;
drained = false;
}
} else if (copyBehindPendingSource()) {
const bool gdsDestination = opcode == 0x50 && packet.size() >= 7 && Pm4::DmaDestination(packet) == Pm4::DmaSelectGds;
const bool gdsOnGpu = gdsDestination && Pm4::GdsImportable();
if ((!gdsDestination || gdsOnGpu) && copyBehindPendingSource()) {
++copiesBehindPendingSources;
wroteOnGpu = true;
drained = false;
} else if (const auto store = Pm4::ResolveStore(packet, queue, gpuStoreLimit)) {
} else if (gdsDestination && !gdsWritesPending(packet, device.Load().get())) {
orderedAlready = true;
drained = false;
} else if (const auto store = gdsDestination && !gdsOnGpu ? std::nullopt : Pm4::ResolveStore(packet, queue, gpuStoreLimit)) {
const auto bytes = store->Bytes();
if (bytes.empty()) {
@@ -313,7 +337,7 @@ void Driver::dumpSampleCounters(std::uint64_t address) {
bool Driver::enqueueDmaPacket(std::span<const std::uint32_t> packet, std::uint32_t opcode, std::uint32_t queue, const QueueState& state) {
if (opcode != 0x50 || queue != 0 || packet.size() < 7 || !DrawPipeline::Active() || !deferredLabels().labels.empty()) return false;
const auto source = ((packet[1] >> 29u) & 3u) | ((packet[6] >> 24u) & 4u) | ((packet[6] >> 25u) & 8u);
if (Pm4::DmaDestination(packet) == Pm4::DmaSelectGds && gdsWritesPending(packet)) return false;
if (Pm4::DmaDestination(packet) == Pm4::DmaSelectGds && gdsWritesPending(packet, device.Load().get())) return false;
constexpr std::size_t immediateLimit = std::size_t{16} << 20u;
constexpr std::size_t gpuStoreLimit = 65536;
if (source == 2 && Pm4::DmaBytes(packet) > gpuStoreLimit && Pm4::DmaDestination(packet) != Pm4::DmaSelectGds) {
@@ -227,8 +227,7 @@ void Driver::run(std::uint32_t id) noexcept {
const auto idleEpochAtWait = idleEpoch.load(std::memory_order_acquire);
changed.wait(lock, [&] { return ready() || (id == 0 && (idleEpoch.load(std::memory_order_acquire) != idleEpochAtWait || completionsPending())); });
if (id == 0) queue0Dormant.store(false, std::memory_order_relaxed);
if (id == 0 && !ready() && (idleEpoch.load(std::memory_order_acquire) != idleEpochAtWait || completionsPending())) continue;
break;
continue;
}
if (poll(ready)) break;
lock.unlock();
@@ -1,7 +1,16 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp"
#include "prx/libSceAgcDriver/Execution/include/Mutex.hpp"
#include "ControlFlow/RequestSerializer.hpp"
#include "Optimization/ResourceProgram.hpp"
#include <charconv>
#include <atomic>
#include <chrono>
#include <sstream>
#ifdef _WIN32
#include <process.h>
#else
#include <unistd.h>
#endif
#include <cstdlib>
#include <functional>
#include <optional>
@@ -11,6 +20,15 @@ namespace AgcDriver::DriverDetail {
namespace {
std::string captureSession() {
#ifdef _WIN32
const auto process = _getpid();
#else
const auto process = getpid();
#endif
return std::to_string(process) + "-" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count());
}
std::optional<std::set<std::uint64_t>> selectedPrograms() {
const char* value = std::getenv("APS5_DUMP_SHADERS");
if (value == nullptr || std::string_view(value) == "1") return std::nullopt;
@@ -32,6 +50,46 @@ std::optional<std::set<std::uint64_t>> selectedPrograms() {
}
std::shared_ptr<const ShaderRecompiler::SourceHandle> PrepareShaderWithDiagnostics(const ShaderRecompiler::RecompileRequest& request, ShaderRecompiler::ShaderPreparationContext* preparation) {
std::exception_ptr failure;
std::string dump;
static const bool dumpInputs = std::getenv("APS5_DUMP_PREPARE_INPUTS") != nullptr;
std::string inputDump;
if (dumpInputs) {
try {
static const auto session = captureSession();
static std::atomic<std::uint64_t> next{0};
const auto suffix = ".input-" + session + "-" + std::to_string(next.fetch_add(1)) + ".prepare";
inputDump = Driver::dumpRequest(request.shader.codeAddress, request, suffix);
if (!inputDump.empty()) {
std::fprintf(stderr, "[prepare-input] begin %s\n", inputDump.c_str());
std::fflush(stderr);
}
} catch (const std::exception& error) {
std::fprintf(stderr, "[prepare-input] capture failed: %s\n", error.what());
}
}
try {
auto handle = ShaderRecompiler::PrepareShader(request, preparation);
if (!inputDump.empty()) std::fprintf(stderr, "[prepare-input] end %s\n", inputDump.c_str());
return handle;
} catch (...) {
failure = std::current_exception();
try {
if (std::getenv("APS5_DUMP_SHADERS") != nullptr) dump = Driver::dumpRequest(request.shader.codeAddress, request, ".prepare");
} catch (...) {}
}
try {
std::rethrow_exception(failure);
} catch (const std::exception& error) {
std::ostringstream where;
where << "shader 0x" << std::hex << request.shader.codeAddress << " stage " << static_cast<unsigned>(request.shader.stage);
if (!dump.empty()) where << " (" << dump << ")";
where << ": ";
throw std::runtime_error(where.str() + error.what());
}
}
void Driver::reportSkip(const char* kind, const std::string& what) {
static AgcDriver::Mutex reportedMutex;
static std::set<std::size_t> reported;
@@ -96,14 +154,17 @@ std::string Driver::dumpRequest(std::uint64_t address, const ShaderRecompiler::R
if (written != text.size() || closed != 0) {
dumped.erase(name);
std::fprintf(stderr, "[gpu] incomplete write to dump file %s (%zu of %zu bytes, close status %d)\n", name.c_str(), written, text.size(), closed);
return {};
}
} else {
dumped.erase(name);
std::fprintf(stderr, "[gpu] could not open dump file %s for writing\n", name.c_str());
return {};
}
} catch (const std::exception& error) {
dumped.erase(name);
std::fprintf(stderr, "[gpu] could not serialize request for 0x%llx: %s\n", static_cast<unsigned long long>(address), error.what());
return {};
}
return name;
}
@@ -60,30 +60,8 @@
namespace AgcDriver::DriverDetail {
std::shared_ptr<const ShaderRecompiler::SourceHandle> PrepareShaderWithDiagnostics(const ShaderRecompiler::RecompileRequest& request, ShaderRecompiler::ShaderPreparationContext* preparation) {
std::exception_ptr failure;
std::string dump;
try {
auto handle = ShaderRecompiler::PrepareShader(request, preparation);
return handle;
} catch (...) {
failure = std::current_exception();
try {
if (std::getenv("APS5_DUMP_SHADERS") != nullptr) dump = Driver::dumpRequest(request.shader.codeAddress, request, ".prepare");
} catch (...) {}
}
try {
std::rethrow_exception(failure);
} catch (const std::exception& error) {
std::ostringstream where;
where << "shader 0x" << std::hex << request.shader.codeAddress << " stage " << static_cast<unsigned>(request.shader.stage);
if (!dump.empty()) where << " (" << dump << ")";
where << ": ";
throw std::runtime_error(where.str() + error.what());
}
}
std::shared_ptr<const ShaderSnapshot> ReadRawShader(std::uint64_t address) {
std::shared_ptr<const ShaderSnapshot> ReadRawShader(std::uint64_t address, const std::shared_ptr<const ShaderSnapshot>& retained) {
const auto drain = [](std::uint64_t first, std::size_t bytes) {
if (!DrawPipeline::Active()) return;
auto& pipeline = DrawPipeline::Queue0();
@@ -92,8 +70,8 @@ std::shared_ptr<const ShaderSnapshot> ReadRawShader(std::uint64_t address) {
static std::mutex cacheMutex;
static std::list<std::shared_ptr<const ShaderSnapshot>> cache;
static std::size_t cacheBytes = 0;
std::shared_ptr<const ShaderSnapshot> cached;
{
std::shared_ptr<const ShaderSnapshot> cached = retained != nullptr && retained->codeAddress == address && retained->header.empty() && !retained->code.empty() ? retained : nullptr;
if (cached == nullptr) {
std::lock_guard lock(cacheMutex);
const auto found = std::find_if(cache.begin(), cache.end(), [address](const auto& entry) { return entry->codeAddress == address; });
if (found != cache.end()) cached = *found;
@@ -902,6 +880,10 @@ void ReportPreparedAtUse(const ShaderSnapshot& snapshot, const ShaderRecompiler:
APS5_LOG_OUT_DEBUG("Shader 0x%llx samples a converted image; preparing its converted-sample variant at use", static_cast<unsigned long long>(request.shader.codeAddress));
return;
}
if (request.context.layerRowSamples) {
APS5_LOG_OUT_DEBUG("Shader 0x%llx samples a 1D array past maxImageArrayLayers; preparing its layer-row variant at use", static_cast<unsigned long long>(request.shader.codeAddress));
return;
}
if (snapshot.codeAddress == NullPixelProgramAddress() && request.shader.stage == ShaderRecompiler::ShaderStage::Fragment && request.context.waveSize == 32u) {
APS5_LOG_ERR("The null pixel program has no wave%u artifact for this draw; preparing it at draw", request.context.waveSize);
return;
@@ -1163,6 +1145,7 @@ ShaderRecompiler::PreparedShaderInvocation InvocationFor(const ShaderSnapshot& s
std::unique_lock lock(snapshot.prepared->mutex);
AwaitRegisteredPreparation(*snapshot.prepared, lock);
if (std::ranges::find(snapshot.prepared->convertedSamples, codeOffset) != snapshot.prepared->convertedSamples.end()) source.context.convertedSamples = true;
if (std::ranges::find(snapshot.prepared->layerRowSamples, codeOffset) != snapshot.prepared->layerRowSamples.end()) source.context.layerRowSamples = true;
auto invocationRequest = source;
struct PreparedKeyStorage {};
auto& key = HostThreadLocal<std::vector<std::uint64_t>, PreparedKeyStorage>();
@@ -1190,18 +1173,22 @@ ShaderRecompiler::PreparedShaderInvocation InvocationFor(const ShaderSnapshot& s
}
std::shared_ptr<const ShaderRecompiler::ResourceCapture> CaptureInvocation(ShaderMemory& memory, const ShaderSnapshot& snapshot, std::size_t codeOffset, const ShaderRecompiler::RecompileRequest& request, ShaderRecompiler::PreparedShaderInvocation& invocation) {
try {
return memory.Capture(invocation);
} catch (const ShaderRecompiler::ConvertedSampleRequired&) {
if (invocation.Request().context.convertedSamples) throw;
}
{
const auto record = [&](std::vector<std::size_t>& offsets) {
std::lock_guard lock(snapshot.prepared->mutex);
auto& offsets = snapshot.prepared->convertedSamples;
if (std::ranges::find(offsets, codeOffset) == offsets.end()) offsets.push_back(codeOffset);
};
while (true) {
try {
return memory.Capture(invocation);
} catch (const ShaderRecompiler::ConvertedSampleRequired&) {
if (invocation.Request().context.convertedSamples) throw;
record(snapshot.prepared->convertedSamples);
} catch (const ShaderRecompiler::LayerRowSamplesRequired&) {
if (invocation.Request().context.layerRowSamples) throw;
record(snapshot.prepared->layerRowSamples);
}
invocation = InvocationFor(snapshot, codeOffset, request);
}
invocation = InvocationFor(snapshot, codeOffset, request);
return memory.Capture(invocation);
}
namespace {
@@ -1057,11 +1057,11 @@ struct WriteTracker {
static constexpr std::size_t CoarseBlocks = 64;
static constexpr std::size_t LeafBlocks = std::size_t{1} << 16;
struct Leaf {
std::array<std::uint32_t, LeafBlocks> blocks{};
std::array<std::uint32_t, LeafBlocks> cpuBlocks{};
std::array<std::uint32_t, LeafBlocks / CoarseBlocks> coarseBlocks{};
std::array<std::uint64_t, LeafBlocks> blocks{};
std::array<std::uint64_t, LeafBlocks> cpuBlocks{};
std::array<std::uint64_t, LeafBlocks / CoarseBlocks> coarseBlocks{};
#ifdef _WIN32
std::array<std::uint32_t, LeafBlocks> hintBlocks{};
std::array<std::uint64_t, LeafBlocks> hintBlocks{};
#endif
};
std::vector<std::unique_ptr<Leaf>> leaves;
@@ -1076,8 +1076,8 @@ struct WriteTracker {
// stamp still happen under it): a hit must return the current value, including MarkWritten
// bumps, or an image refreshed after a stamp would keep failing UnchangedSince until the next
// walk of its range and re-upload at every use of the epoch.
std::atomic<std::uint32_t> generation{1};
std::atomic<std::uint32_t> stable{1};
std::atomic<std::uint64_t> generation{1};
std::atomic<std::uint64_t> stable{1};
std::vector<void*> pages;
// Collect memo: page-rounded ranges walked during the current epoch (see BumpCollectEpoch). A
// collect fully inside one skips GetWriteWatch, whose cost is proportional to the range's pages,
@@ -1160,24 +1160,24 @@ struct WriteTracker {
return !GuestArena::GuestArenaHostRegionOverlaps_nid_postfix(static_cast<std::uintptr_t>(first), static_cast<std::size_t>(stop - first));
}
std::uint32_t newestHint(std::uint64_t first, std::uint64_t stop) const {
std::uint32_t newest = 0;
std::uint64_t newestHint(std::uint64_t first, std::uint64_t stop) const {
std::uint64_t newest = 0;
for (auto block = blockOf(first); block <= blockOf(stop - 1); ++block) newest = std::max(newest, hintOf(block));
return newest;
}
#endif
struct DriverPiece {
std::uint32_t generation = 0;
std::uint64_t generation = 0;
std::uint32_t begin = 0;
std::uint32_t end = 0;
};
struct DriverPieces {
std::uint32_t whole = 0;
std::uint32_t dropped = 0;
std::uint64_t whole = 0;
std::uint64_t dropped = 0;
std::array<DriverPiece, 4> pieces{};
std::uint32_t possibleWhole = 0;
std::uint32_t possibleDropped = 0;
std::uint64_t possibleWhole = 0;
std::uint64_t possibleDropped = 0;
std::array<DriverPiece, 4> possiblePieces{};
bool covers(std::uint32_t begin, std::uint32_t end, std::uint64_t generation) const {
@@ -1197,21 +1197,21 @@ struct WriteTracker {
std::unordered_map<std::uint64_t, DriverPieces> driverPieces;
struct CpuPages {
std::array<std::uint32_t, WritePagesPerBlock> pages{};
std::array<std::uint64_t, WritePagesPerBlock> pages{};
};
std::unordered_map<std::uint64_t, CpuPages> cpuPages;
std::unordered_map<std::uint64_t, CpuPages> walkPages;
std::map<std::uint64_t, std::uint32_t> refused;
std::map<std::uint64_t, std::uint64_t> refused;
void noteCpuStore(std::uint64_t begin, std::uint64_t end, std::uint32_t stampGeneration) {
void noteCpuStore(std::uint64_t begin, std::uint64_t end, std::uint64_t stampGeneration) {
notePages(cpuPages, begin, end, stampGeneration);
}
void noteWalkStore(std::uint64_t begin, std::uint64_t end, std::uint32_t stampGeneration) {
void noteWalkStore(std::uint64_t begin, std::uint64_t end, std::uint64_t stampGeneration) {
notePages(walkPages, begin, end, stampGeneration);
}
void notePages(std::unordered_map<std::uint64_t, CpuPages>& pages, std::uint64_t begin, std::uint64_t end, std::uint32_t stampGeneration) {
void notePages(std::unordered_map<std::uint64_t, CpuPages>& pages, std::uint64_t begin, std::uint64_t end, std::uint64_t stampGeneration) {
for (auto block = blockOf(begin); block <= blockOf(end - 1); ++block) {
const auto blockStart = blockBegin(block);
const auto from = std::max(begin, blockStart) - blockStart;
@@ -1235,7 +1235,7 @@ struct WriteTracker {
#endif
}
void stampWatchedPart(std::uint64_t address, std::uint64_t end, std::uint32_t stampGeneration, bool complete) {
void stampWatchedPart(std::uint64_t address, std::uint64_t end, std::uint64_t stampGeneration, bool complete) {
#ifdef _WIN32
address = std::max<std::uint64_t>(address, base);
end = std::min<std::uint64_t>(end, base + size);
@@ -1253,7 +1253,7 @@ struct WriteTracker {
}
}
void noteDriverStore(std::uint64_t block, std::uint64_t address, std::uint64_t end, std::uint32_t stampGeneration, bool complete) {
void noteDriverStore(std::uint64_t block, std::uint64_t address, std::uint64_t end, std::uint64_t stampGeneration, bool complete) {
const auto begin = blockBegin(block);
const auto from = static_cast<std::uint32_t>(std::max(address, begin) - begin);
const auto to = static_cast<std::uint32_t>(std::min<std::uint64_t>(end, begin + WriteBlockBytes) - begin);
@@ -1301,19 +1301,19 @@ struct WriteTracker {
leafFor(block).hintBlocks[block % LeafBlocks] = generation;
}
std::uint32_t hintOf(std::uint64_t block) const {
std::uint64_t hintOf(std::uint64_t block) const {
const auto& leaf = leaves[block / LeafBlocks];
return leaf != nullptr ? leaf->hintBlocks[block % LeafBlocks] : 0;
}
#endif
std::uint32_t stampOf(std::uint64_t block) const {
std::uint64_t stampOf(std::uint64_t block) const {
const auto& leaf = leaves[block / LeafBlocks];
return leaf != nullptr ? leaf->blocks[block % LeafBlocks] : 0;
}
static constexpr std::size_t UnstampedSlots = 1u << 16;
std::vector<std::uint32_t> unstampedStores;
std::vector<std::uint64_t> unstampedStores;
void noteUnstampedStore(std::uint64_t address, std::uint64_t end) {
if (unstampedStores.empty()) unstampedStores.assign(UnstampedSlots, 0);
@@ -1326,8 +1326,8 @@ struct WriteTracker {
for (auto block = first; block <= last; ++block) unstampedStores[block % UnstampedSlots] = generation;
}
std::uint32_t newestStamp(std::uint64_t address, std::uint64_t end) const {
std::uint32_t newest = 0;
std::uint64_t newestStamp(std::uint64_t address, std::uint64_t end) const {
std::uint64_t newest = 0;
if (!unstampedStores.empty()) {
const auto first = address / WriteBlockBytes;
const auto last = (end - 1) / WriteBlockBytes;
@@ -1346,14 +1346,14 @@ struct WriteTracker {
return newest;
}
std::uint32_t coarseStampOf(std::uint64_t block) const {
std::uint64_t coarseStampOf(std::uint64_t block) const {
const auto& leaf = leaves[block / LeafBlocks];
return leaf != nullptr ? leaf->coarseBlocks[(block % LeafBlocks) / CoarseBlocks] : 0;
}
bool unchanged(std::uint64_t first, std::uint64_t last, std::uint64_t since) const {
if (first == last) return stampOf(first) <= since;
const auto newer = [since](std::uint32_t stamp) { return stamp > since; };
const auto newer = [since](std::uint64_t stamp) { return stamp > since; };
while (first <= last) {
const auto& leaf = leaves[first / LeafBlocks];
if (leaf == nullptr) {
@@ -1370,7 +1370,7 @@ struct WriteTracker {
return true;
}
std::uint32_t cpuStampOf(std::uint64_t block) const {
std::uint64_t cpuStampOf(std::uint64_t block) const {
const auto& leaf = leaves[block / LeafBlocks];
return leaf != nullptr ? leaf->cpuBlocks[block % LeafBlocks] : 0;
}
@@ -1422,7 +1422,7 @@ struct WriteTracker {
return unchanged(blockOf(address), blockOf(address + bytes - 1), since) || !storedOver(address, address + bytes, since, true);
}
void stamp(std::uint64_t block, std::uint32_t stampGeneration, StampKind kind) {
void stamp(std::uint64_t block, std::uint64_t stampGeneration, StampKind kind) {
const bool cpu = kind == StampKind::Cpu || kind == StampKind::ImportWindow;
const bool stored = kind != StampKind::ImportWindow;
auto& leaf = leafFor(block);
@@ -1516,7 +1516,7 @@ void watchPrivateMapping(std::uintptr_t address, std::size_t bytes, std::uint64_
tracker.noteCpuStore(address, address + bytes, tracker.generation);
for (auto block = tracker.blockOf(address); block <= tracker.blockOf(address + bytes - 1); ++block) {
if (const auto& leaf = tracker.leaves[block / WriteTracker::LeafBlocks]; leaf != nullptr) leaf->hintBlocks[block % WriteTracker::LeafBlocks] = 0;
if (const auto found = tracker.driverPieces.find(block); found != tracker.driverPieces.end()) found->second.dropped = std::max<std::uint32_t>(found->second.dropped, tracker.generation);
if (const auto found = tracker.driverPieces.find(block); found != tracker.driverPieces.end()) found->second.dropped = std::max<std::uint64_t>(found->second.dropped, tracker.generation);
tracker.stamp(block, tracker.generation, StampKind::Cpu);
}
unwatchSerial.fetch_add(1, std::memory_order_release);
@@ -1593,7 +1593,7 @@ struct StampRuns {
std::vector<std::pair<std::uint64_t, std::uint64_t>> windowRuns;
};
void noteWrittenRun(StampRuns& runs, std::uintptr_t begin, std::uintptr_t end, std::uint32_t generation) {
void noteWrittenRun(StampRuns& runs, std::uintptr_t begin, std::uintptr_t end, std::uint64_t generation) {
if (runs.kind != StampKind::Driver) runs.tracker.noteCpuStore(begin, end, generation);
else runs.tracker.noteWalkStore(begin, end, generation);
}
@@ -1741,7 +1741,8 @@ std::uint64_t collectWrites(std::uint64_t address, std::size_t bytes, bool memoi
}
}
const TimedAccess timed(CounterCollect, bytes);
#ifndef _WIN32
const auto requestedFirst = first;
const auto requestedStop = stop;
if (useMemo && HostThreadSlot<std::uint64_t, CollectEpochSlot>::Get() != 0 && bytes <= WriteBlockBytes) {
const auto begin = first & ~(WriteBlockBytes - 1);
const auto end = (stop + WriteBlockBytes - 1) & ~(WriteBlockBytes - 1);
@@ -1750,8 +1751,16 @@ std::uint64_t collectWrites(std::uint64_t address, std::size_t bytes, bool memoi
stop = end;
}
}
if (!walkWrites(tracker, first, stop, StampKind::Cpu)) {
#ifdef _WIN32
if (first == requestedFirst && stop == requestedStop) return 0;
first = requestedFirst;
stop = requestedStop;
if (!walkWrites(tracker, first, stop, StampKind::Cpu)) return 0;
#else
return 0;
#endif
if (!walkWrites(tracker, first, stop, StampKind::Cpu)) return 0;
}
// Only a completed walk is remembered; a failed one (uncommitted pages) returned 0 above.
if (collectMemoEnabled()) {
const auto serial = unwatchSerial.load(std::memory_order_relaxed);
@@ -2299,6 +2308,12 @@ std::uint64_t TrackerGeneration() {
return tracker.generation;
}
void AdvanceTrackerGenerationForTest(std::uint64_t generation) {
auto& tracker = Tracker();
const auto lock = lockTracker(tracker);
if (generation > tracker.generation.load(std::memory_order_relaxed)) tracker.generation.store(generation, std::memory_order_relaxed);
}
std::uint64_t NewestStamp(std::uint64_t address, std::size_t bytes) {
auto& tracker = Tracker();
const auto lock = lockTracker(tracker);
@@ -3024,7 +3039,7 @@ void WriteChanged(std::uint64_t address, std::span<const std::byte> current, std
WriteChanged(address, current, original, ChangedByteStoreLimit());
}
void WriteChanged(std::uint64_t address, std::span<const std::byte> current, std::span<const std::byte> original, std::uint32_t byteStoreLimit) {
static void writeChanged(std::uint64_t address, std::span<const std::byte> current, std::span<const std::byte> original, std::uint32_t byteStoreLimit, bool keepGuest) {
require(current.size() == original.size(), "write-back snapshot sizes differ");
BreakProofs();
if (current.empty()) return;
@@ -3044,7 +3059,9 @@ void WriteChanged(std::uint64_t address, std::span<const std::byte> current, std
std::size_t at = 0;
for (; at + 16 <= size; at += 16) {
const auto bytes = _mm_loadu_si128(reinterpret_cast<const __m128i*>(current.data() + at));
const auto same = _mm_cmpeq_epi8(bytes, _mm_loadu_si128(reinterpret_cast<const __m128i*>(original.data() + at)));
const auto uploaded = _mm_loadu_si128(reinterpret_cast<const __m128i*>(original.data() + at));
auto same = _mm_cmpeq_epi8(bytes, uploaded);
if (keepGuest) same = _mm_or_si128(same, _mm_xor_si128(_mm_cmpeq_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(destination + at)), uploaded), _mm_set1_epi8(-1)));
const auto equal = static_cast<std::uint32_t>(_mm_movemask_epi8(same));
if (equal == 0xffffu) continue;
const auto changed = ~equal & 0xffffu;
@@ -3063,7 +3080,7 @@ void WriteChanged(std::uint64_t address, std::span<const std::byte> current, std
}
if (masked) _mm_sfence();
for (; at < size; ++at) {
if (current[at] == original[at]) continue;
if (current[at] == original[at] || (keepGuest && destination[at] != original[at])) continue;
destination[at] = current[at];
firstChanged = std::min(firstChanged, at);
lastChanged = std::max(lastChanged, at + 1);
@@ -3072,6 +3089,14 @@ void WriteChanged(std::uint64_t address, std::span<const std::byte> current, std
});
}
void WriteChanged(std::uint64_t address, std::span<const std::byte> current, std::span<const std::byte> original, std::uint32_t byteStoreLimit) {
writeChanged(address, current, original, byteStoreLimit, false);
}
void WriteChangedKeepingGuest(std::uint64_t address, std::span<const std::byte> current, std::span<const std::byte> original) {
writeChanged(address, current, original, ChangedByteStoreLimit(), true);
}
void Write(std::uint64_t address, std::span<const std::byte> source, std::size_t alignment) {
if (source.empty()) return;
// A store, as in WriteChanged.
@@ -14,6 +14,7 @@
#include <cerrno>
#include <sys/utsname.h>
#include <unistd.h>
extern char** environ;
#endif
namespace AgcDriver {
@@ -372,7 +372,20 @@ OverlayLayout LayOutKeyboard(const ImeKeyboardView& view, VkExtent2D extent) {
const auto inner = gridWidth(view);
rect(KeyboardMetrics::Padding, KeyboardMetrics::Padding, inner, KeyboardMetrics::FieldHeight, OverlayColor::Field);
std::size_t caret = 0;
const auto characters = decode(view.text, view.caret, &caret);
auto characters = decode(view.text, view.caret, &caret);
std::vector<std::uint8_t> marks(characters.size(), 0);
if (!view.preedit.empty()) {
Graphics::Require(view.preeditCursor <= view.preedit.size() && view.preeditSelection <= view.preedit.size() - view.preeditCursor, "the system keyboard composition cursor is past its text");
std::size_t cursor = 0;
std::size_t selectionEnd = 0;
const auto composed = decode(view.preedit, view.preeditCursor, &cursor);
decode(view.preedit, view.preeditCursor + view.preeditSelection, &selectionEnd);
std::vector<std::uint8_t> composedMarks(composed.size(), KeyboardCompositionMark);
std::fill(composedMarks.begin() + static_cast<std::ptrdiff_t>(cursor), composedMarks.begin() + static_cast<std::ptrdiff_t>(selectionEnd), KeyboardSelectionMark);
characters.insert(characters.begin() + static_cast<std::ptrdiff_t>(caret), composed.begin(), composed.end());
marks.insert(marks.begin() + static_cast<std::ptrdiff_t>(caret), composedMarks.begin(), composedMarks.end());
caret += cursor;
}
const auto textLeft = KeyboardMetrics::Padding + KeyboardMetrics::FieldInset;
const auto textTop = KeyboardMetrics::Padding + KeyboardMetrics::FieldInset;
const auto visible = static_cast<std::size_t>((inner - 2 * KeyboardMetrics::FieldInset + 1) / KeyboardMetrics::Advance);
@@ -381,6 +394,8 @@ OverlayLayout LayOutKeyboard(const ImeKeyboardView& view, VkExtent2D extent) {
for (auto index = first; index < last; ++index) {
const auto column = static_cast<std::int32_t>(index - first);
glyph(layout, KeyboardGlyph(characters[index]), left + (textLeft + column * KeyboardMetrics::Advance) * scale, top + textTop * scale, scale, OverlayColor::Text);
if (marks[index] == KeyboardCompositionMark) rect(textLeft + column * KeyboardMetrics::Advance, textTop + KeyboardMetrics::GlyphHeight, KeyboardMetrics::Advance, 1, OverlayColor::Accent);
else if (marks[index] == KeyboardSelectionMark) rect(textLeft + column * KeyboardMetrics::Advance, textTop + KeyboardMetrics::GlyphHeight, KeyboardMetrics::Advance, 2, OverlayColor::Text);
}
rect(textLeft + static_cast<std::int32_t>(caret - first) * KeyboardMetrics::Advance - 1, KeyboardMetrics::Padding + 1, 1, KeyboardMetrics::FieldHeight - 2, OverlayColor::Accent);
for (const auto& key : view.keys) {
@@ -8,6 +8,7 @@
#include <thread>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <memory>
@@ -16,10 +17,55 @@
namespace AgcDriver::Pm4 {
namespace {
std::atomic<bool> importableGdsRequested{false};
std::atomic<bool> gdsShared{false};
std::atomic<bool> gdsImportable{false};
}
void RequestImportableGds(bool requested) {
importableGdsRequested.store(requested, std::memory_order_release);
}
bool ImportableGdsRequested() {
return importableGdsRequested.load(std::memory_order_acquire);
}
bool GdsShared() {
static_cast<void>(GdsAddress());
return gdsShared.load(std::memory_order_acquire);
}
bool GdsImportable() {
static_cast<void>(GdsAddress());
return gdsImportable.load(std::memory_order_acquire);
}
void RejectGdsImport() {
gdsImportable.store(false, std::memory_order_release);
}
std::uint64_t GdsAddress() {
static const std::uint64_t address = [] {
constexpr int ReadWrite = 0x3;
constexpr int PrivateAnonymous = 0x1002;
constexpr int Shared = 0x1;
constexpr int OpenReadWrite = 0x2;
const char* const anonymousSharedMemory = reinterpret_cast<const char*>(1);
if (ImportableGdsRequested() && std::getenv("APS5_NO_SHARED_GDS") == nullptr) {
if (const int descriptor = shm_open_nid_postfix(anonymousSharedMemory, OpenReadWrite, 0600); descriptor >= 0) {
void* shared = ftruncate_nid_postfix(descriptor, GdsBytes) == 0 ? mmap_nid_postfix(nullptr, GdsBytes, ReadWrite, Shared, descriptor, 0) : nullptr;
close_nid_postfix(descriptor);
if (shared != nullptr && shared != reinterpret_cast<void*>(static_cast<std::uintptr_t>(-1))) {
std::memset(shared, 0, GdsBytes);
gdsShared.store(true, std::memory_order_release);
gdsImportable.store(true, std::memory_order_release);
return reinterpret_cast<std::uint64_t>(shared);
}
}
}
void* mapped = mmap_nid_postfix(nullptr, GdsBytes, ReadWrite, PrivateAnonymous, -1, 0);
if (mapped == nullptr || mapped == reinterpret_cast<void*>(static_cast<std::uintptr_t>(-1))) throw std::runtime_error("cannot allocate the global data share");
return reinterpret_cast<std::uint64_t>(mapped);
@@ -289,7 +335,7 @@ void Validate(std::span<const std::uint32_t> packet, std::uint32_t queue) {
// Header bit 1 selects the compute shader type and bit 2 (register writes) resets the filter CAM;
// neither changes what the packet writes.
const auto flags = header & 0xffu;
const bool registerWrite = opcode == 0x69 || opcode == 0x76 || opcode == 0x79 || opcode == 0x7a;
const bool registerWrite = opcode == 0x69 || opcode == 0x76 || opcode == 0x79 || opcode == 0x7a || (opcode == 0x37 && ((packet[1] >> 8u) & 0xfu) == 0);
auto allowedFlags = opcode == 0x11 || opcode == 0x15 || opcode == 0x16 ? 2u : registerWrite ? 6u : opcode == 0x3c || opcode == 0x93 ? 2u : 0u;
if (opcode != 0x20 && opcode != 0x22) allowedFlags |= 1u;
if ((flags & ~allowedFlags) != 0) throw std::runtime_error("PM4 header flags 0x" + ToHex(flags) + " are not implemented");
@@ -1,5 +1,6 @@
#include "prx/libSceAgcDriver/Execution/include/ShaderDeviceProfile.hpp"
#include "BdaAbi.hpp"
#include "CacheKey.hpp"
#include <spirv/unified1/spirv.hpp>
#include <algorithm>
@@ -75,6 +76,7 @@ ShaderDeviceProfile::ShaderDeviceProfile(const ShaderRecompiler::SpirvTarget& ta
Require(!target.mesh || meshEnabled, "shader device profile exposes disabled mesh shaders");
Require(!target.nonConstantImageOffsets || (maintenance8 != nullptr && maintenance8->maintenance8 == VK_TRUE), "shader device profile exposes disabled maintenance8");
Require(!target.tessellation || core.tessellationShader == VK_TRUE, "shader device profile exposes disabled tessellation");
Require(!target.shaderImageMinLod || core.shaderResourceMinLod == VK_TRUE, "shader device profile exposes a disabled shaderResourceMinLod");
for (const auto extension : target.supportedExtensions) extensions.emplace_back(extension);
std::ranges::sort(extensions);
extensions.erase(std::unique(extensions.begin(), extensions.end()), extensions.end());
@@ -83,6 +85,7 @@ ShaderDeviceProfile::ShaderDeviceProfile(const ShaderRecompiler::SpirvTarget& ta
Require(std::ranges::find(extensionViews, "SPV_KHR_terminate_invocation") == extensionViews.end() || (terminate != nullptr && terminate->shaderTerminateInvocation == VK_TRUE), "shader device profile advertises a disabled feature: shaderTerminateInvocation");
this->target.supportedCapabilities = capabilities;
this->target.supportedExtensions = extensionViews;
ShaderRecompiler::RecompileCacheKey::SealFeatureDigest(this->target);
}
}
@@ -2,10 +2,15 @@
#include "prx/libSceAgcDriver/Execution/include/ShaderMemory.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include "prx/libc/include/GuestAllocations.hpp"
#include "prx/libSceAgcDriver/Graphics/include/GuestTextureResource.hpp"
#include "prx/libSceAgcDriver/Graphics/include/TextureTiling.hpp"
#include "prx/libSceAgcDriver/Graphics/include/TextureFormat.hpp"
#include "prx/libSceAgcDriver/Graphics/include/TextureSwizzleEquations.hpp"
#include "prx/libc/include/HostThreadLocal.hpp"
#include "Optimization/RequestMemoryView.hpp"
#include "Optimization/ResourceMaterializer.hpp"
#include "Optimization/ResourceProgram.hpp"
#include "Optimization/SrtWalker.hpp"
#include "ThreadOwned.hpp"
#include <algorithm>
#include <atomic>
@@ -35,6 +40,8 @@ struct CaptureProfile {
// were read raw on the driver's evidence, or were read both ways (verify) and differed.
std::atomic<std::uint64_t> pagesWordwise{0};
std::atomic<std::uint64_t> wordWaits{0};
std::atomic<std::uint64_t> branchReadsRefused{0};
std::atomic<std::uint64_t> branchCapturesRedone{0};
std::atomic<std::uint64_t> wordWaitNanoseconds{0};
std::atomic<std::uint64_t> wordsRaw{0};
std::atomic<std::uint64_t> wordsVerified{0};
@@ -69,6 +76,55 @@ struct CaptureProfile {
constexpr std::uint64_t WordWaitNanoseconds = 50000;
std::uint64_t imageViewGeneration(void*) {
return GuestAllocations::GuestAllocationsGeneration_nid_postfix();
}
bool normalizeImageView(void*, std::uint32_t maxArrayLayers, std::array<std::uint32_t, 8>& descriptor, ShaderRecompiler::SrtImageViewIdentity& identity) {
identity.generation = GuestAllocations::GuestAllocationsGeneration_nid_postfix();
if (((descriptor[3] >> 28u) & 0xfu) != 12u) return false;
const auto resource = Graphics::DecodeTextureResource(descriptor);
identity.address = resource.baseAddress;
const auto range = GuestAllocations::GuestAllocationsLookup_nid_postfix(static_cast<std::uintptr_t>(resource.baseAddress), false);
if (range != nullptr) {
identity.hasRange = true;
identity.readable = range->readable;
identity.writable = range->writable;
identity.gpu = range->gpu;
identity.rangeAddress = range->address;
identity.rangeBytes = range->bytes;
identity.allocationAddress = range->allocationAddress;
identity.allocationBytes = range->allocationBytes;
identity.backingSerial = range->backingSerial;
}
if (maxArrayLayers == 0u || resource.dimension != Graphics::TextureDimension::k1DArray || range == nullptr) return false;
const auto rawCount = resource.depthOrLastArray >= resource.baseArray ? resource.depthOrLastArray - resource.baseArray + 1u : 0u;
const auto geometry = Graphics::DescribeSurface(resource);
if (geometry.layerBytes == 0u || geometry.thick || geometry.layers != resource.depthOrLastArray + 1u) return false;
if (const auto xorMode = Graphics::XorSwizzleMode(resource.tileMode); xorMode != 0u) {
const auto* equation = Graphics::FindTextureSwizzleEquation(xorMode, Graphics::BytesPerElement(resource.format));
if (equation == nullptr || std::any_of(equation->bits.begin(), equation->bits.end(), [](std::uint32_t bit) { return (bit & 0xff000000u) != 0u; })) return false;
}
if (!range->readable || !range->gpu || range->bytes == 0u || range->address > std::numeric_limits<std::uint64_t>::max() - range->bytes || range->allocationAddress > std::numeric_limits<std::uint64_t>::max() - range->allocationBytes) return false;
const auto rangeEnd = range->address + range->bytes;
const auto allocationEnd = range->allocationAddress + range->allocationBytes;
if (resource.baseAddress < range->address || resource.baseAddress > rangeEnd || range->address < range->allocationAddress || rangeEnd > allocationEnd) return false;
const auto offset = resource.baseAddress - range->address;
if (offset % geometry.layerBytes != 0u) return false;
const auto coveredBytes = rangeEnd - resource.baseAddress;
if (coveredBytes % geometry.layerBytes != 0u) return false;
const auto completeSlices = coveredBytes / geometry.layerBytes;
if (completeSlices <= resource.baseArray) return false;
if (rawCount <= maxArrayLayers) return false;
const auto available = completeSlices - resource.baseArray;
const auto effectiveCount = std::min<std::uint64_t>(rawCount, available);
if (effectiveCount == 0u || effectiveCount == rawCount) return false;
const auto lastArray = static_cast<std::uint64_t>(resource.baseArray) + effectiveCount - 1u;
if (lastArray > 0x1fffu) return false;
descriptor[4] = (descriptor[4] & ~0x1fffu) | static_cast<std::uint32_t>(lastArray);
return true;
}
bool WordwisePages() {
static const bool wordwise = std::getenv("APS5_NO_WORDWISE_CAPTURE") == nullptr;
return wordwise;
@@ -94,6 +150,11 @@ CaptureProfile& CaptureTotals() {
return profile;
}
bool BranchesSkipPendingWords() {
static const bool skip = std::getenv("APS5_WAIT_PENDING_BRANCHES") == nullptr;
return skip;
}
std::atomic<ShaderMemory::WaitedMsProvider> waitedMsProvider{nullptr};
double WaitedMs() {
@@ -372,6 +433,10 @@ bool ShaderMemory::read(void* context, std::uint64_t address, std::uint32_t* val
waited = page.wordwise && (self.hookWaits != nullptr ? self.hookWaits() != waitsBefore : true);
word = verifiedWord;
}
} else if (page.wordwise && policy == PendingWrite::Sync && !forcedRaw && !self.waitBranches && BranchesSkipPendingWords() && ShaderRecompiler::SrtEvaluatingBranch()) {
++self.branchReadsRefused;
if (CaptureProfiled()) ++CaptureTotals().branchReadsRefused;
return false;
} else {
// On a word-wise page the bytes before the hook's wait are kept for the observer.
const bool observed = page.wordwise && policy == PendingWrite::Sync && self.observe != nullptr && GuestMemory::Accessible(reinterpret_cast<const void*>(address), sizeof(word));
@@ -722,11 +787,29 @@ std::vector<std::shared_ptr<const ShaderRecompiler::SrtGuestWords>> ShaderMemory
}
std::shared_ptr<const ShaderRecompiler::ResourceCapture> ShaderMemory::Capture(const ShaderRecompiler::RecompileRequest& request, const ShaderRecompiler::SourceHandle* handle) {
return capture(request, handle, nullptr);
return captureWaitingOnFailure(request, handle, nullptr);
}
std::shared_ptr<const ShaderRecompiler::ResourceCapture> ShaderMemory::Capture(const ShaderRecompiler::PreparedShaderInvocation& invocation) {
return capture(invocation.Request(), nullptr, &invocation);
return captureWaitingOnFailure(invocation.Request(), nullptr, &invocation);
}
std::shared_ptr<const ShaderRecompiler::ResourceCapture> ShaderMemory::captureWaitingOnFailure(const ShaderRecompiler::RecompileRequest& request, const ShaderRecompiler::SourceHandle* handle, const ShaderRecompiler::PreparedShaderInvocation* invocation) {
branchReadsRefused = 0;
try {
return capture(request, handle, invocation);
} catch (const std::exception&) {
if (branchReadsRefused == 0u) throw;
}
if (CaptureProfiled()) ++CaptureTotals().branchCapturesRedone;
struct WaitBranches {
bool& wait;
explicit WaitBranches(bool& flag) : wait(flag) { wait = true; }
~WaitBranches() { wait = false; }
WaitBranches(const WaitBranches&) = delete;
WaitBranches& operator=(const WaitBranches&) = delete;
} waiting(waitBranches);
return capture(request, handle, invocation);
}
std::shared_ptr<const ShaderRecompiler::ResourceCapture> ShaderMemory::capture(const ShaderRecompiler::RecompileRequest& request, const ShaderRecompiler::SourceHandle* handle, const ShaderRecompiler::PreparedShaderInvocation* invocation) {
@@ -750,6 +833,8 @@ std::shared_ptr<const ShaderRecompiler::ResourceCapture> ShaderMemory::capture(c
runtime.unchangedSince = &unchangedSince;
runtime.supplyWords = &supplyWords;
runtime.descriptorScope = &descriptorScope;
runtime.normalizeImageView = &normalizeImageView;
runtime.imageViewGeneration = &imageViewGeneration;
auto capture = invocation != nullptr ? invocation->Capture(runtime) : handle != nullptr ? ShaderRecompiler::CaptureResources(request, runtime, *handle) : ShaderRecompiler::CaptureResources(request, runtime);
if (profile) {
totals.captureNanoseconds += NanosecondsSince(started);
@@ -772,7 +857,7 @@ std::shared_ptr<const ShaderRecompiler::ResourceCapture> ShaderMemory::capture(c
const auto materializeNs = ShaderRecompiler::ResourceMaterializer::MaterializeNanoseconds();
const auto evaluateNs = ShaderRecompiler::ResourceMaterializer::EvaluateNanoseconds();
const auto walkNs = captureNs > resolveNs + pageNs + wordNs + specializationNs ? captureNs - resolveNs - pageNs - wordNs - specializationNs : 0;
AgcDriver::ProfilePrint_nid_no_patch( "[capture] %llu captures: %llu word reads, %llu pages fetched (%llu read word by word over pending GPU writes: %llu words waited %.2f s, %llu read raw on evidence, %llu verified with %llu mismatches, %llu served from known values, %llu hook reads not observed: no GPU wait), capture (plan lookup + materialize) %.1f s, %llu KiB registered code this capture; sub-phases (s, us per capture): source resolve %.2f/%.1f, walk %.2f/%.1f, specialization (every materialize) %.2f/%.1f, page reads %.2f/%.1f, word reads %.2f/%.1f, hook GPU waits inside %.2f/%.1f, materialize %.2f/%.1f (SRT evaluate %.2f/%.1f); source handle memo %llu hits, %llu resolves\n", static_cast<unsigned long long>(totals.captures.load()), static_cast<unsigned long long>(totals.reads.load()), static_cast<unsigned long long>(totals.pages.load()), static_cast<unsigned long long>(totals.pagesWordwise.load()), static_cast<unsigned long long>(totals.wordWaits.load()), totals.wordWaitNanoseconds.load() / 1e9, static_cast<unsigned long long>(totals.wordsRaw.load()), static_cast<unsigned long long>(totals.wordsVerified.load()), static_cast<unsigned long long>(totals.wordMismatches.load()), static_cast<unsigned long long>(totals.wordsKnown.load()), static_cast<unsigned long long>(totals.observationsSkipped.load()), captureNs / 1e9, static_cast<unsigned long long>(initialBytes / 1024), resolveNs / 1e9, resolveNs / captures / 1e3, walkNs / 1e9, walkNs / captures / 1e3, specializationNs / 1e9, specializationNs / captures / 1e3, pageNs / 1e9, pageNs / captures / 1e3, wordNs / 1e9, wordNs / captures / 1e3, hookNs / 1e9, hookNs / captures / 1e3, materializeNs / 1e9, materializeNs / captures / 1e3, evaluateNs / 1e9, evaluateNs / captures / 1e3, static_cast<unsigned long long>(totals.handleHits.load()), static_cast<unsigned long long>(totals.handleMisses.load()));
AgcDriver::ProfilePrint_nid_no_patch( "[capture] %llu captures: %llu word reads, %llu pages fetched (%llu read word by word over pending GPU writes: %llu words waited %.2f s, %llu read raw on evidence, %llu verified with %llu mismatches, %llu served from known values, %llu hook reads not observed: no GPU wait, %llu branch condition reads over pending GPU writes left the branch unpruned instead of waiting, %llu captures redone waiting after one failed), capture (plan lookup + materialize) %.1f s, %llu KiB registered code this capture; sub-phases (s, us per capture): source resolve %.2f/%.1f, walk %.2f/%.1f, specialization (every materialize) %.2f/%.1f, page reads %.2f/%.1f, word reads %.2f/%.1f, hook GPU waits inside %.2f/%.1f, materialize %.2f/%.1f (SRT evaluate %.2f/%.1f); source handle memo %llu hits, %llu resolves\n", static_cast<unsigned long long>(totals.captures.load()), static_cast<unsigned long long>(totals.reads.load()), static_cast<unsigned long long>(totals.pages.load()), static_cast<unsigned long long>(totals.pagesWordwise.load()), static_cast<unsigned long long>(totals.wordWaits.load()), totals.wordWaitNanoseconds.load() / 1e9, static_cast<unsigned long long>(totals.wordsRaw.load()), static_cast<unsigned long long>(totals.wordsVerified.load()), static_cast<unsigned long long>(totals.wordMismatches.load()), static_cast<unsigned long long>(totals.wordsKnown.load()), static_cast<unsigned long long>(totals.observationsSkipped.load()), static_cast<unsigned long long>(totals.branchReadsRefused.load()), static_cast<unsigned long long>(totals.branchCapturesRedone.load()), captureNs / 1e9, static_cast<unsigned long long>(initialBytes / 1024), resolveNs / 1e9, resolveNs / captures / 1e3, walkNs / 1e9, walkNs / captures / 1e3, specializationNs / 1e9, specializationNs / captures / 1e3, pageNs / 1e9, pageNs / captures / 1e3, wordNs / 1e9, wordNs / captures / 1e3, hookNs / 1e9, hookNs / captures / 1e3, materializeNs / 1e9, materializeNs / captures / 1e3, evaluateNs / 1e9, evaluateNs / captures / 1e3, static_cast<unsigned long long>(totals.handleHits.load()), static_cast<unsigned long long>(totals.handleMisses.load()));
}
}
return capture;
@@ -368,6 +368,51 @@ struct WorkgroupMemory {
}
};
struct ScratchPool {
VkDevice device = VK_NULL_HANDLE;
PFN_vkDestroyDescriptorPool destroyPool = nullptr;
std::unique_ptr<Graphics::DeviceBuffer> buffer;
VkDescriptorPool pool = VK_NULL_HANDLE;
VkDescriptorSet set = VK_NULL_HANDLE;
std::uint64_t slots = 0;
std::uint64_t headerBytes = 0;
std::uint64_t bytes = 0;
std::uint64_t lastUse = 0;
~ScratchPool() {
buffer.reset();
if (pool != VK_NULL_HANDLE) destroyPool(device, pool, nullptr);
}
};
void ZeroScratchPoolHeader(const Graphics::Context& context, const ScratchPool& pool) {
Graphics::CommandBatch batch(context);
context.Resolved(&Graphics::DeviceFunctions::cmdFillBuffer, "vkCmdFillBuffer")(batch.Handle(), pool.buffer->Handle(), 0, pool.headerBytes, 0u);
Graphics::RecordMemoryBarrier(context, batch.Handle(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT);
batch.SubmitAndWait();
}
std::uint64_t MebibytesFromEnvironment(const char* name, std::uint64_t fallback) {
std::uint64_t mebibytes = fallback;
if (const char* text = std::getenv(name)) {
char* end = nullptr;
const auto parsed = std::strtoull(text, &end, 10);
if (end != text && *end == 0 && parsed != 0) mebibytes = parsed;
}
return mebibytes << 20u;
}
std::uint64_t ScratchPoolCapBytes() {
static const std::uint64_t bytes = MebibytesFromEnvironment("APS5_SCRATCH_POOL_MIB", 64);
return bytes;
}
constexpr std::uint64_t ScratchPoolBufferLimit = std::uint64_t{1} << 31u;
std::uint64_t ScratchPoolTotalBytes() {
static const std::uint64_t bytes = MebibytesFromEnvironment("APS5_SCRATCH_POOL_TOTAL_MIB", 256);
return bytes;
}
struct VulkanDevice::State {
bool compileOnly = false;
void* library = nullptr;
@@ -424,6 +469,7 @@ struct VulkanDevice::State {
bool shaderTerminateInvocation = false;
bool fusedExactArithmetic = false;
bool fragmentBarycentricBuiltins = false;
bool hostInterpolationFirst = false;
bool geometryShader = false;
bool largePoints = false;
bool sampleRateShading = false;
@@ -464,8 +510,11 @@ struct VulkanDevice::State {
bool graphicsPipelineLibrary = false;
bool pipelineLinkTimeOptimization = true;
bool imageViewMinLod = false;
bool shaderResourceMinLod = false;
bool shaderImageMinLod = false;
bool pipelineExecutableInfo = false;
bool maintenance8 = false;
bool pushDescriptors = false;
bool maintenance5 = false;
bool fillModeNonSolid = false;
std::uint32_t srgbDecodeFormats = 0;
@@ -536,6 +585,9 @@ struct VulkanDevice::State {
std::vector<std::pair<std::array<std::uint32_t, 4>, std::shared_ptr<Graphics::DeviceBuffer>>> patternBuffers;
VkDescriptorSetLayout workgroupMemoryLayout = VK_NULL_HANDLE;
std::shared_ptr<WorkgroupMemory> workgroupMemory;
std::mutex scratchPoolsMutex;
std::map<ShaderRecompiler::PipelineIdentity, std::shared_ptr<ScratchPool>> scratchPools;
std::uint64_t scratchPoolUses = 0;
// Compute pipeline objects by variant (and push-constant use), under their own mutex: the
// dispatch's find-or-insert and the verify switch's lookups touch the map, recipes hold weak
// references to its objects.
@@ -554,6 +606,7 @@ struct VulkanDevice::State {
std::unique_ptr<Graphics::PipelineCache> pipelineCache;
std::unique_ptr<Graphics::DescriptorCache> descriptorCache;
std::unique_ptr<Graphics::VertexInputCache> vertexInputs;
Graphics::VertexBufferFormats vertexFormats;
std::unique_ptr<Graphics::SamplerCache> samplerCache;
Graphics::ResourceCache& resourceCache = Graphics::SharedResourceCache();
// Recorded dispatches that write a copied buffer (their results reach guest memory by a CPU
@@ -699,6 +752,65 @@ struct VulkanDevice::State {
return workgroupMemory;
}
std::shared_ptr<ScratchPool> ScratchPoolFor(const Graphics::Context& context, const ShaderRecompiler::PipelineIdentity& identity, std::uint32_t slotDwords, std::uint64_t groups) {
const auto range = std::min<std::uint64_t>(properties.limits.maxStorageBufferRange, ScratchPoolBufferLimit);
const auto slotBytes = (static_cast<std::uint64_t>(slotDwords) + 2u) * 4u;
if (slotBytes > range) {
throw std::runtime_error("Vulkan dispatch: one scratch pool slot of " + std::to_string(slotBytes) + " bytes is over the scratch pool buffer limit of " + std::to_string(range) + " bytes");
}
const auto capSlots = std::max<std::uint64_t>(std::min({ScratchPoolCapBytes(), ScratchPoolTotalBytes(), range}) / slotBytes, 1u);
const auto wanted = std::clamp<std::uint64_t>(groups, 1u, capSlots);
std::lock_guard lock(scratchPoolsMutex);
const auto use = ++scratchPoolUses;
if (const auto found = scratchPools.find(identity); found != scratchPools.end() && found->second->slots >= wanted) {
found->second->lastUse = use;
return found->second;
}
const auto size = wanted * slotBytes;
EvictScratchPools(identity, size);
auto created = std::make_shared<ScratchPool>();
created->device = device;
created->destroyPool = DeviceFunction<PFN_vkDestroyDescriptorPool>("vkDestroyDescriptorPool");
created->slots = wanted;
created->headerBytes = wanted * 2u * 4u;
created->bytes = size;
created->lastUse = use;
created->buffer = std::make_unique<Graphics::DeviceBuffer>(context, static_cast<std::size_t>(size), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
const VkDescriptorPoolSize poolSize{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1};
VkDescriptorPoolCreateInfo poolInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO};
poolInfo.maxSets = 1;
poolInfo.poolSizeCount = 1;
poolInfo.pPoolSizes = &poolSize;
check(DeviceFunction<PFN_vkCreateDescriptorPool>("vkCreateDescriptorPool")(device, &poolInfo, nullptr, &created->pool), "vkCreateDescriptorPool scratch pool");
VkDescriptorSetAllocateInfo allocation{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
allocation.descriptorPool = created->pool;
allocation.descriptorSetCount = 1;
allocation.pSetLayouts = &workgroupMemoryLayout;
check(DeviceFunction<PFN_vkAllocateDescriptorSets>("vkAllocateDescriptorSets")(device, &allocation, &created->set), "vkAllocateDescriptorSets scratch pool");
const VkDescriptorBufferInfo described{created->buffer->Handle(), 0, size};
VkWriteDescriptorSet write{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
write.dstSet = created->set;
write.dstBinding = 0;
write.descriptorCount = 1;
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
write.pBufferInfo = &described;
DeviceFunction<PFN_vkUpdateDescriptorSets>("vkUpdateDescriptorSets")(device, 1, &write, 0, nullptr);
ZeroScratchPoolHeader(context, *created);
scratchPools[identity] = created;
return created;
}
void EvictScratchPools(const ShaderRecompiler::PipelineIdentity& identity, std::uint64_t needed) {
scratchPools.erase(identity);
std::uint64_t held = 0;
for (const auto& [key, pool] : scratchPools) held += pool->bytes;
while (!scratchPools.empty() && held + needed > ScratchPoolTotalBytes()) {
const auto oldest = std::min_element(scratchPools.begin(), scratchPools.end(), [](const auto& left, const auto& right) { return left.second->lastUse < right.second->lastUse; });
held -= oldest->second->bytes;
scratchPools.erase(oldest);
}
}
void CreateMarkerBuffer() {
bufferMarker = DeviceFunction<PFN_vkCmdWriteBufferMarkerAMD>("vkCmdWriteBufferMarkerAMD");
VkBufferCreateInfo buffer{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
@@ -960,6 +1072,7 @@ struct VulkanDevice::State {
Graphics::ClearHostImports(device);
patternBuffers.clear();
workgroupMemory.reset();
scratchPools.clear();
if (workgroupMemoryLayout != VK_NULL_HANDLE) reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(deviceProc(device, "vkDestroyDescriptorSetLayout"))(device, workgroupMemoryLayout, nullptr);
descriptorCache.reset();
vertexInputs.reset();
@@ -1362,6 +1475,8 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
state->individuallyFreeDescriptorSets = driver.driverID == VK_DRIVER_ID_MESA_LLVMPIPE;
state->fusedExactArithmetic = driver.driverID == VK_DRIVER_ID_MOLTENVK;
state->tessellationPipelineCache = TessellationPipelineCacheUsable(driver.driverID);
state->hostInterpolationFirst = HostInterpolationPreferred(driver.driverID) && std::getenv("APS5_NO_HOST_INTERPOLATION_FIRST") == nullptr;
APS5_LOG_OUT("Pixel interpolation driver=%d hostInterpolationFirst=%d", static_cast<int>(driver.driverID), state->hostInterpolationFirst ? 1 : 0);
state->subgroupControlBarriers = SubgroupControlBarrierUsable(driver.driverID);
state->workgroupScopeFences = WorkgroupScopeFenceUsable(driver.driverID);
state->ldsLockFences = LdsLockFencesRequired(driver.driverID);
@@ -1633,6 +1748,7 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
state->drawInputsInPlace = std::getenv("APS5_NO_DRAW_INPUTS_IN_PLACE") == nullptr && (std::getenv("APS5_DRAW_INPUTS_IN_PLACE") != nullptr || DrawInputsInPlaceUsable(driverProperties.driverID, windows));
if (!compileOnly) Graphics::SetHostImportWindow(8ull << 20u);
if (!compileOnly) Graphics::SetHostImportMaxBytes(maintenance3.maxMemoryAllocationSize);
if (!compileOnly) Pm4::RequestImportableGds(state->properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU);
#ifdef _WIN32
// Imported pages are locked; locking is bounded by the process working-set minimum.
if (const char* value = std::getenv("APS5_WORKING_SET_MIB"); value != nullptr && !compileOnly) {
@@ -1677,7 +1793,7 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
if (hasExtension(VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME)) {
VkPhysicalDeviceFeatures2 features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &minLodFeatures};
state->InstanceFunction<PFN_vkGetPhysicalDeviceFeatures2>("vkGetPhysicalDeviceFeatures2")(selected, &features);
state->imageViewMinLod = minLodFeatures.minLod == VK_TRUE;
state->imageViewMinLod = minLodFeatures.minLod == VK_TRUE && std::getenv("APS5_NO_IMAGE_VIEW_MIN_LOD") == nullptr;
if (state->imageViewMinLod) deviceExtensions.push_back(VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME);
}
minLodFeatures = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT};
@@ -1691,6 +1807,8 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
}
maintenance8Features = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_8_FEATURES_KHR};
maintenance8Features.maintenance8 = VK_TRUE;
state->pushDescriptors = hasExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
if (state->pushDescriptors) deviceExtensions.push_back(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
VkPhysicalDeviceDepthClipControlFeaturesEXT depthClipFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT};
if (hasExtension(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME)) {
VkPhysicalDeviceFeatures2 features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &depthClipFeatures};
@@ -1896,6 +2014,8 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
if (enabled.shaderImageGatherExtended) state->capabilities.push_back(spv::CapabilityImageGatherExtended);
enabled.shaderResourceMinLod = available.shaderResourceMinLod;
if (enabled.shaderResourceMinLod) state->capabilities.push_back(spv::CapabilityMinLod);
state->shaderResourceMinLod = enabled.shaderResourceMinLod == VK_TRUE;
state->shaderImageMinLod = state->shaderResourceMinLod && !state->imageViewMinLod && !state->graphicsPipelineLibrary;
enabled.sampleRateShading = available.sampleRateShading;
enabled.geometryShader = available.geometryShader;
state->geometryShader = enabled.geometryShader == VK_TRUE;
@@ -2203,12 +2323,13 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
if (domains(selected, &domainCount, available.data()) != VK_SUCCESS) available.clear();
}
#ifdef _WIN32
const auto host = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR;
const std::array hosts{VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR};
#else
const auto host = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR;
const std::array hosts{VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR, VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR};
#endif
if (std::ranges::find(available, VK_TIME_DOMAIN_DEVICE_KHR) != available.end() && std::ranges::find(available, host) != available.end()) {
state->hostTimeDomain = host;
const auto host = std::ranges::find_first_of(hosts, available);
if (std::ranges::find(available, VK_TIME_DOMAIN_DEVICE_KHR) != available.end() && host != hosts.end()) {
state->hostTimeDomain = *host;
state->calibratedTimestamps = state->DeviceFunction<PFN_vkGetCalibratedTimestampsKHR>(khr ? "vkGetCalibratedTimestampsKHR" : "vkGetCalibratedTimestampsEXT");
}
}
@@ -2257,6 +2378,7 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
Graphics::PrepareImportWatch(graphicsContext());
state->bufferPool = std::make_shared<Graphics::BufferPool>(graphicsContext());
state->emptyBuffer = std::make_unique<Graphics::Buffer>(graphicsContext(), Graphics::EmptyBufferBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
if (!compileOnly && Pm4::GdsImportable() && Graphics::HostImportFor(graphicsContext(), Pm4::GdsAddress(), Pm4::GdsBytes, Graphics::ImportRequester::Map) == nullptr) Pm4::RejectGdsImport();
state->pipelineCache = std::make_unique<Graphics::PipelineCache>(graphicsContext(), state->properties, window != nullptr || compileOnly);
state->detiler = std::make_unique<Graphics::TextureDetiler>(graphicsContext());
state->textureCache = std::make_unique<Graphics::TextureCache>(graphicsContext());
@@ -2592,7 +2714,7 @@ int VulkanDevice::WriteLabelOnGpu(std::uint64_t address, std::span<const std::by
static const bool storeAtLabel = Graphics::StorageTexture::StoreAtLabelRequested(std::getenv("APS5_STORE_AT_LABEL"));
if (storeAtLabel) Graphics::StorageTexture::FlushAllPending("label", state->device);
if (queue == 0) static_cast<void>(Graphics::StorageTexture::StoreDrawnLinear("label"));
Graphics::StorageTexture::StoreReadbackBeforeLabel("readback before label");
Graphics::StorageTexture::StoreReadbackBeforeLabel("readback before label", state->device);
if (!state->recorder || bytes.empty() || bytes.size() > 65536 || address % 4 != 0 || bytes.size() % 4 != 0) return 4;
auto& recorder = *state->recorder;
// Batches that already finished are retired before the checks: their completions ran, so they
@@ -4123,7 +4245,7 @@ bool VulkanDevice::CalibrateClock(double& gpuNs, std::chrono::steady_clock::time
const double sinceNs = static_cast<double>(static_cast<std::uint64_t>(counter.QuadPart) - stamps[1]) * 1e9 / static_cast<double>(frequency.QuadPart);
#else
timespec monotonic{};
clock_gettime(CLOCK_MONOTONIC, &monotonic);
clock_gettime(state->hostTimeDomain == VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR ? CLOCK_MONOTONIC_RAW : CLOCK_MONOTONIC, &monotonic);
const auto now = std::chrono::steady_clock::now();
const double sinceNs = static_cast<double>(static_cast<std::uint64_t>(monotonic.tv_sec) * 1000000000ull + static_cast<std::uint64_t>(monotonic.tv_nsec) - stamps[1]);
#endif
@@ -4151,6 +4273,7 @@ ShaderRecompiler::SpirvTarget VulkanDevice::Target() const {
auto target = state->shaderProfile->Target();
target.float32FlushToZero = state->float32FlushToZero;
target.fusedExactArithmetic = state->fusedExactArithmetic;
target.hostInterpolationFirst = state->hostInterpolationFirst;
target.float32DenormPreserve = state->float32DenormPreserve;
return target;
}
@@ -4166,6 +4289,7 @@ ShaderRecompiler::SpirvTarget VulkanDevice::buildTarget() const {
target.fragmentShaderBarycentricEnabled = state->fragmentShaderBarycentric;
target.fragmentBarycentricBuiltins = state->fragmentBarycentricBuiltins;
target.nonConstantImageOffsets = state->maintenance8;
target.shaderImageMinLod = state->shaderImageMinLod;
target.narrowSubgroupClock = state->narrowSubgroupClock;
target.float64DenormPreserve = state->float64DenormPreserve;
target.float16DenormPreserve = state->float16DenormPreserve;
@@ -4182,6 +4306,7 @@ ShaderRecompiler::SpirvTarget VulkanDevice::buildTarget() const {
target.ldsLockFences = state->ldsLockFences;
target.meshWindowBuffer = state->driverId == VK_DRIVER_ID_NVIDIA_PROPRIETARY && std::getenv("APS5_NO_MESH_WINDOW_BUFFER") == nullptr;
target.srgbDecodeFormats = state->srgbDecodeFormats & ~state->srgbCopyFormats;
target.maxImageArrayLayers = limits.maxImageArrayLayers;
target.vertexSubgroups = (state->subgroup.supportedStages & VK_SHADER_STAGE_VERTEX_BIT) != 0;
target.tessellationEvaluationSubgroups = (state->subgroup.supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0;
if (state->meshShader) {
@@ -4230,6 +4355,13 @@ bool VulkanDevice::GraphicsPipelineLibraries() const {
return state->graphicsPipelineLibrary;
}
std::pair<VkBuffer, std::uint64_t> VulkanDevice::scratchPoolHeader(const ShaderRecompiler::RecompileResult& shader) const {
std::lock_guard lock(state->scratchPoolsMutex);
const auto found = state->scratchPools.find(shader.Identity());
if (found == state->scratchPools.end() || found->second == nullptr) return {VK_NULL_HANDLE, 0};
return {found->second->buffer->Handle(), found->second->headerBytes};
}
Graphics::Context VulkanDevice::graphicsContext() const {
static const bool noCache = std::getenv("APS5_NO_CONTEXT_CACHE") != nullptr;
if (state->contextReady && !noCache) return state->context;
@@ -4283,6 +4415,7 @@ Graphics::Context VulkanDevice::buildContext() const {
context.recorder = state->recorder.get();
context.descriptorCache = state->descriptorCache.get();
context.vertexInputs = state->vertexInputs.get();
context.vertexFormats = &state->vertexFormats;
context.samplerCache = state->samplerCache.get();
context.drawIndirectFirstInstance = state->drawIndirectFirstInstance;
context.multiDrawIndirect = state->multiDrawIndirect;
@@ -4339,8 +4472,11 @@ Graphics::Context VulkanDevice::buildContext() const {
context.earlyFragmentSampleMaskTestBeforeSampleCounting = state->earlyFragmentSampleMaskTestBeforeSampleCounting;
context.primitiveListRestart = state->primitiveListRestart;
context.imageViewMinLod = state->imageViewMinLod;
context.shaderResourceMinLod = state->shaderResourceMinLod;
context.shaderImageMinLod = state->shaderImageMinLod;
context.pipelineExecutableInfo = state->pipelineExecutableInfo;
context.maintenance8 = state->maintenance8;
context.pushDescriptors = state->pushDescriptors;
context.srgbDecodeFormats = state->srgbDecodeFormats;
context.srgbCopyFormats = state->srgbCopyFormats;
context.sampleLocationSampleCounts = state->sampleLocationSampleCounts;
@@ -5049,14 +5185,14 @@ VulkanDevice::PresyncStatistics VulkanDevice::PresyncCounts() {
return {counters.checked.load(std::memory_order_relaxed), counters.presyncs.load(std::memory_order_relaxed), counters.keyChecks.load(std::memory_order_relaxed), counters.keyWaits.load(std::memory_order_relaxed)};
}
std::shared_ptr<PreparedDispatch> VulkanDevice::PrepareDispatch(const ShaderRecompiler::RecompileResult& shader, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t dispatchThreads, std::uint64_t programAddress, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear) {
std::shared_ptr<PreparedDispatch> VulkanDevice::PrepareDispatch(const ShaderRecompiler::RecompileResult& shader, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t dispatchThreads, std::uint64_t programAddress, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear, const std::vector<ShaderRecompiler::RegisteredImageView>* registeredImageViews) {
ShaderRecompiler::RuntimeAbi::RequireVersion(shader.runtimeAbiVersion);
// APS5_LOCKED_BUILD=1: the whole build under the mutex, as before the split.
static const bool lockedBuild = std::getenv("APS5_LOCKED_BUILD") != nullptr;
if (lockedBuild || shader.spirv.size() < 5 || shader.spirv[0] != 0x07230203u) return nullptr;
static const bool profile = std::getenv("APS5_PROFILE_DRAW") != nullptr;
const auto start = std::chrono::steady_clock::now();
const Graphics::CompiledShader compute{ShaderRecompiler::ShaderStage::Compute, &shader, 0};
const Graphics::CompiledShader compute{ShaderRecompiler::ShaderStage::Compute, &shader, 0, registeredImageViews};
const auto context = graphicsContext();
auto prepared = std::make_shared<PreparedDispatch>();
prepared->dispatchThreads = dispatchThreads;
@@ -5172,12 +5308,12 @@ std::shared_ptr<RecipeHit> VulkanDevice::PrepareRecipe(const std::shared_ptr<con
return hit;
}
void VulkanDevice::Dispatch(const ShaderRecompiler::RecompileResult& shader, std::uint32_t x, std::uint32_t y, std::uint32_t z, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t programAddress, std::shared_ptr<PreparedDispatch> prepared, std::shared_ptr<const Recipe>* recipe, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear) {
static_cast<void>(dispatch(shader, x, y, z, 0, snapshots, programAddress, std::move(prepared), recipe, {}, htileClear));
void VulkanDevice::Dispatch(const ShaderRecompiler::RecompileResult& shader, std::uint32_t x, std::uint32_t y, std::uint32_t z, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t programAddress, std::shared_ptr<PreparedDispatch> prepared, std::shared_ptr<const Recipe>* recipe, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear, const std::vector<ShaderRecompiler::RegisteredImageView>* registeredImageViews) {
static_cast<void>(dispatch(shader, x, y, z, 0, snapshots, programAddress, std::move(prepared), recipe, {}, htileClear, registeredImageViews));
}
VulkanDevice::IndirectOutcome VulkanDevice::DispatchIndirect(const ShaderRecompiler::RecompileResult& shader, std::uint64_t arguments, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t programAddress, std::shared_ptr<PreparedDispatch> prepared, std::shared_ptr<const Recipe>* recipe, const std::array<std::uint32_t, 3>& threadGroup) {
return dispatch(shader, 0, 0, 0, arguments, snapshots, programAddress, std::move(prepared), recipe, threadGroup);
VulkanDevice::IndirectOutcome VulkanDevice::DispatchIndirect(const ShaderRecompiler::RecompileResult& shader, std::uint64_t arguments, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t programAddress, std::shared_ptr<PreparedDispatch> prepared, std::shared_ptr<const Recipe>* recipe, const std::array<std::uint32_t, 3>& threadGroup, const std::vector<ShaderRecompiler::RegisteredImageView>* registeredImageViews) {
return dispatch(shader, 0, 0, 0, arguments, snapshots, programAddress, std::move(prepared), recipe, threadGroup, std::nullopt, registeredImageViews);
}
void VulkanDevice::decideIndirect(RecordedDispatch& record, IndirectOutcome& outcome, char* groupsText) {
@@ -5291,6 +5427,11 @@ void VulkanDevice::recordDispatch(RecordedDispatch& record) {
if (recorder.HasQueuedKeyStores() && (resources.HoldsLease() || recorder.AnyQueuedKeyStore(touches))) recorder.FlushKeyStores();
if (recorder.HasQueuedStores() && (resources.HoldsLease() || recorder.AnyQueuedStore(touches))) recorder.FlushStores();
static_cast<void>(Graphics::StorageTexture::StoreDrawnLinearTouching("dispatch access", touches, resources.HoldsLease()));
std::shared_ptr<ScratchPool> pool;
if (const auto slotDwords = record.shader->program->scratchPoolSlotDwords; slotDwords != 0) {
const std::uint64_t groups = argumentImport != nullptr ? std::numeric_limits<std::uint64_t>::max() : static_cast<std::uint64_t>(record.x) * record.y * record.z;
pool = state->ScratchPoolFor(context, record.shader->program->Identity(), slotDwords, groups);
}
bool unordered = false;
const auto overlapQueue = Graphics::Recorder::TakeDispatchOrder(unordered);
const auto* groupLimit = state->properties.limits.maxComputeWorkGroupCount;
@@ -5409,6 +5550,10 @@ void VulkanDevice::recordDispatch(RecordedDispatch& record) {
context.Resolved(&Graphics::DeviceFunctions::cmdBindDescriptorSets, "vkCmdBindDescriptorSets")(commands, VK_PIPELINE_BIND_POINT_COMPUTE, record.objects->layout, ShaderRecompiler::WorkgroupMemoryDescriptorSet, 1, &memory->set, 0, nullptr);
recorder.Keep(std::move(memory));
}
if (pool != nullptr) {
context.Resolved(&Graphics::DeviceFunctions::cmdBindDescriptorSets, "vkCmdBindDescriptorSets")(commands, VK_PIPELINE_BIND_POINT_COMPUTE, record.objects->layout, ShaderRecompiler::ScratchPoolDescriptorSet, 1, &pool->set, 0, nullptr);
recorder.Keep(std::move(pool));
}
if (record.pushStages != 0) {
context.Resolved(&Graphics::DeviceFunctions::cmdPushConstants, "vkCmdPushConstants")(commands, record.objects->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, Graphics::ComputePushConstantBytes, record.pushBytes->data());
}
@@ -5507,10 +5652,11 @@ std::shared_ptr<ComputePipelineObjects> VulkanDevice::createComputePipeline(cons
objects->destroyPipeline = state->DeviceFunction<PFN_vkDestroyPipeline>("vkDestroyPipeline");
objects->module = Graphics::CreateShaderModule(state->DeviceFunction<PFN_vkCreateShaderModule>("vkCreateShaderModule"), state->device, state->graphicsPipelineLibrary, shader.spirv.data(), shader.spirv.size() * sizeof(std::uint32_t), "vkCreateShaderModule");
objects->resourcesLayout = setLayout;
const std::array<VkDescriptorSetLayout, 2> setLayouts{setLayout, shader.workgroupMemoryDwords != 0 ? state->workgroupMemoryLayout : VK_NULL_HANDLE};
const bool scratchPool = shader.scratchPoolSlotDwords != 0;
const std::array<VkDescriptorSetLayout, 3> setLayouts{setLayout, shader.workgroupMemoryDwords != 0 || scratchPool ? state->workgroupMemoryLayout : VK_NULL_HANDLE, scratchPool ? state->workgroupMemoryLayout : VK_NULL_HANDLE};
const VkPushConstantRange push{VK_SHADER_STAGE_COMPUTE_BIT, 0, Graphics::ComputePushConstantBytes};
VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
layoutInfo.setLayoutCount = shader.workgroupMemoryDwords != 0 ? ShaderRecompiler::WorkgroupMemoryDescriptorSet + 1 : 1;
layoutInfo.setLayoutCount = scratchPool ? ShaderRecompiler::ScratchPoolDescriptorSet + 1 : shader.workgroupMemoryDwords != 0 ? ShaderRecompiler::WorkgroupMemoryDescriptorSet + 1 : 1;
layoutInfo.pSetLayouts = setLayouts.data();
layoutInfo.pushConstantRangeCount = pushStages != 0 ? 1 : 0;
layoutInfo.pPushConstantRanges = pushStages != 0 ? &push : nullptr;
@@ -5530,7 +5676,8 @@ std::shared_ptr<ComputePipelineObjects> VulkanDevice::createComputePipeline(cons
resourcesLayout.bindings.push_back({layoutKey[index], type, layoutKey[index + 2u], layoutKey[index + 3u], updateAfterBind && type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ? VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT : 0u});
}
capture.sets.push_back(std::move(resourcesLayout));
if (shader.workgroupMemoryDwords != 0) capture.sets.push_back({0, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, 0}}});
if (shader.workgroupMemoryDwords != 0 || scratchPool) capture.sets.push_back({0, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, 0}}});
if (scratchPool) capture.sets.push_back({0, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, 0}}});
if (pushStages != 0) capture.pushConstants.push_back(push);
for (const auto& value : shader.specialization) capture.specialization.push_back({value.id, value.value});
capture.requiredSubgroupSize = subgroupSize;
@@ -5616,7 +5763,7 @@ std::shared_ptr<ComputePipelineObjects> VulkanDevice::computePipeline(const Grap
return finish(std::move(objects), nullptr);
}
VulkanDevice::IndirectOutcome VulkanDevice::dispatch(const ShaderRecompiler::RecompileResult& shader, std::uint32_t x, std::uint32_t y, std::uint32_t z, std::uint64_t arguments, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t programAddress, std::shared_ptr<PreparedDispatch> prepared, std::shared_ptr<const Recipe>* recipeOut, const std::array<std::uint32_t, 3>& threadGroup, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear) {
VulkanDevice::IndirectOutcome VulkanDevice::dispatch(const ShaderRecompiler::RecompileResult& shader, std::uint32_t x, std::uint32_t y, std::uint32_t z, std::uint64_t arguments, std::span<const Graphics::GuestMemorySnapshot> snapshots, std::uint64_t programAddress, std::shared_ptr<PreparedDispatch> prepared, std::shared_ptr<const Recipe>* recipeOut, const std::array<std::uint32_t, 3>& threadGroup, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear, const std::vector<ShaderRecompiler::RegisteredImageView>* registeredImageViews) {
startJournalReplay();
for (const auto& binding : shader.bindings) {
if (binding.role != ShaderRecompiler::DescriptorRole::GuestBuffers) continue;
@@ -5641,7 +5788,7 @@ VulkanDevice::IndirectOutcome VulkanDevice::dispatch(const ShaderRecompiler::Rec
if (shader.spirv.size() < 5 || shader.spirv[0] != 0x07230203u) {
throw std::runtime_error("Vulkan dispatch: invalid SPIR-V");
}
const std::array<Graphics::CompiledShader, 1> shaders{{{ShaderRecompiler::ShaderStage::Compute, &shader, 0}}};
const std::array<Graphics::CompiledShader, 1> shaders{{{ShaderRecompiler::ShaderStage::Compute, &shader, 0, registeredImageViews}}};
const auto pushStages = Graphics::PushConstantStages(shaders);
if (pushStages != 0 && state->properties.limits.maxPushConstantsSize < Graphics::ComputePushConstantBytes) {
throw std::runtime_error("Vulkan dispatch: compute push constant range exceeds device limit");
@@ -26,6 +26,16 @@
namespace AgcDriver {
#ifdef _WIN32
bool ReadableStackRegion(std::uint64_t address, std::uint64_t& low, std::uint64_t& high) {
constexpr DWORD readable = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
MEMORY_BASIC_INFORMATION memory{};
if (VirtualQuery(reinterpret_cast<LPCVOID>(address), &memory, sizeof(memory)) == 0 || memory.State != MEM_COMMIT) return false;
if ((memory.Protect & (PAGE_GUARD | PAGE_NOACCESS)) != 0 || (memory.Protect & readable) == 0) return false;
low = reinterpret_cast<std::uint64_t>(memory.BaseAddress);
high = low + memory.RegionSize;
return true;
}
namespace {
std::jthread processSamplerThread;
@@ -72,7 +82,7 @@ struct Sampler {
}
bool readStack(std::uint64_t address, std::uint64_t& value) const {
if (address < stackLow || address > stackHigh - sizeof(value)) return false;
if (stackHigh < stackLow + sizeof(value) || address < stackLow || address > stackHigh - sizeof(value)) return false;
std::memcpy(&value, reinterpret_cast<const void*>(address), sizeof(value));
return true;
}
@@ -104,6 +114,11 @@ struct Sampler {
}
int walk(CONTEXT& context, std::array<std::uint64_t, WorkerDepth>& frames) {
if (context.Rsp < stackLow || context.Rsp >= stackHigh) {
stackLow = 0;
stackHigh = 0;
ReadableStackRegion(context.Rsp, stackLow, stackHigh);
}
const bool dwarf = stackHigh != 0 && context.Rsp >= stackLow && context.Rsp < stackHigh;
int count = 0;
while (count < depth && context.Rip != 0) {
@@ -364,6 +379,7 @@ void StopWorkerSampler() {
if (committerSamplerThread.joinable()) committerSamplerThread.join();
}
#else
bool ReadableStackRegion(std::uint64_t, std::uint64_t&, std::uint64_t&) { return false; }
void StartWorkerSampler(std::uint32_t) {}
void StartCommitterSampler() {}
void StopWorkerSampler() {}
-20
View File
@@ -127,26 +127,6 @@ int APS5_VABI sceAgcDriverTmpInitIdhs(void) {
return 0;
}
int APS5_VABI sceAgcDriverUserDataWritePacket(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcDriverUserDataWritePopMarker(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcDriverUserDataWritePushMarker(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcDriverUserDataWriteSetMarker(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
}
extern "C" {
@@ -3,7 +3,10 @@
#include "prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp"
#include "Recompiler.hpp"
#include <cstddef>
#include <cstdint>
#include <memory>
#include <span>
#include <string>
#include <utility>
#include <vector>
@@ -12,13 +15,30 @@ namespace AgcDriver::Graphics {
bool LoopGuardTripped();
struct BdaFaultChunk;
class BdaResources {
public:
explicit BdaResources(const Context& context);
BdaResources(const Context& context, const GuestBufferMemory& memory);
explicit BdaResources(const Context& context, bool reportOnly = false);
BdaResources(const Context& context, const GuestBufferMemory& memory, bool reportOnly = false);
~BdaResources();
BdaResources(const BdaResources&) = delete;
BdaResources& operator=(const BdaResources&) = delete;
VkDescriptorBufferInfo Table() const;
VkDescriptorBufferInfo Fault() const;
void CheckFault() const;
void NoteUse(std::uint64_t serial);
bool TakeFaultSlot(const Context& context);
bool HoldsFaultSlot() const { return faultChunk != nullptr; }
static void NoteFinished(VkDevice device, std::uint64_t serial);
struct FaultSlotCounts {
std::uint64_t chunks = 0;
std::uint64_t slots = 0;
std::uint64_t held = 0;
std::uint64_t reclaimed = 0;
std::uint64_t retaken = 0;
};
static FaultSlotCounts FaultSlots(VkDevice device);
struct ImageTableFaults {
std::uint32_t stage = 0;
std::uint64_t shader = 0;
@@ -57,8 +77,13 @@ private:
// BdaResources.cpp, which refers to it weakly).
void markWrittenPages() const;
void checkSrtGuard() const;
std::span<std::byte> faultBytes() const;
std::shared_ptr<Buffer> table;
std::unique_ptr<Buffer> fault;
VkDevice faultDevice = VK_NULL_HANDLE;
std::shared_ptr<BdaFaultChunk> faultChunk;
VkDeviceSize faultOffset = 0;
bool reportOnly = false;
std::uint64_t lastUse = 0;
std::size_t tableBytes = 0;
std::vector<ImageTableFaults> imageTables;
std::vector<std::pair<std::uint64_t, std::uint64_t>> imageTableRanges;
@@ -28,6 +28,7 @@ struct BufferAllocation {
bool slab = false;
std::size_t bufferBytes = 0;
std::uint32_t memoryType = 0;
bool hostPlaced = false;
};
struct SlabSlot {
@@ -71,7 +72,7 @@ public:
VkDeviceMemory TakeImageMemory(const VkMemoryAllocateInfo& allocation, const char* operation, std::optional<std::uint32_t> hostType = std::nullopt, std::uint32_t* allocatedType = nullptr, bool newImage = false);
void PutImageMemory(VkDeviceMemory memory, VkDeviceSize bytes, std::uint32_t memoryType) noexcept;
std::size_t RetainedImages();
std::optional<BufferAllocation> Take(std::size_t bytes, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, const char* category = nullptr);
std::optional<BufferAllocation> Take(std::size_t bytes, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, const char* category = nullptr, bool hostPlaced = false);
void Put(const BufferAllocation& allocation) noexcept;
VkDeviceSize ReclaimIdleDevice(VkDeviceSize bytes, std::chrono::steady_clock::time_point now);
static bool SlabEligible(std::size_t capacity, VkDeviceSize alignment, VkDeviceSize size, VkDeviceSize atom);
@@ -106,11 +107,12 @@ private:
VkBufferUsageFlags usage;
VkMemoryPropertyFlags properties;
std::uint32_t memoryType = 0;
bool hostPlaced = false;
bool operator==(const SlotKey&) const = default;
};
struct SlotKeyHash {
std::size_t operator()(const SlotKey& key) const noexcept {
return std::hash<std::size_t>{}(key.bytes) ^ (static_cast<std::size_t>(key.usage) << 32u) ^ (static_cast<std::size_t>(key.properties) << 48u) ^ (static_cast<std::size_t>(key.memoryType) << 56u);
return std::hash<std::size_t>{}(key.bytes) ^ (static_cast<std::size_t>(key.usage) << 32u) ^ (static_cast<std::size_t>(key.properties) << 48u) ^ (static_cast<std::size_t>(key.memoryType) << 56u) ^ (static_cast<std::size_t>(key.hostPlaced) << 63u);
}
};
// One retention tier: its slots by key (each list oldest first), their count and bytes, the
@@ -6,6 +6,7 @@
#endif
#include <mutex>
#include <vulkan/vulkan.h>
#include "prx/libc/include/PrimedSharedMutex.hpp"
#include <array>
#include <atomic>
#include <cstdint>
@@ -35,6 +36,7 @@ class SamplerCache;
class ShaderResources;
class PlaceholderImages;
class VertexInputCache;
class VertexBufferFormats;
class PipelineCacheSynchronization {
public:
@@ -46,7 +48,7 @@ public:
SnapshotLock TryLockForSnapshot() const { return SnapshotLock(mutex, std::try_to_lock); }
private:
mutable std::shared_mutex mutex;
mutable PrimedSharedMutex mutex;
};
inline void Require(bool condition, const std::string& reason) {
@@ -259,8 +261,11 @@ struct Context {
bool earlyFragmentSampleMaskTestBeforeSampleCounting = false;
bool primitiveListRestart = false;
bool imageViewMinLod = false;
bool shaderResourceMinLod = false;
bool shaderImageMinLod = false;
bool pipelineExecutableInfo = false;
bool maintenance8 = false;
bool pushDescriptors = false;
bool graphicsPipelineLibrary = false;
bool pipelineLinkTimeOptimization = true;
std::uint32_t srgbDecodeFormats = 0;
@@ -279,6 +284,7 @@ struct Context {
return pipelineCacheSynchronization != nullptr ? pipelineCacheSynchronization->LockForPipelineUse() : PipelineCacheSynchronization::PipelineUseLock{};
}
VertexInputCache* vertexInputs = nullptr;
VertexBufferFormats* vertexFormats = nullptr;
template<typename TFunction>
TFunction Function(const char* name) const {
@@ -330,35 +336,62 @@ struct Context {
return type;
}
std::uint32_t DeviceMemoryType(std::uint32_t mask, VkDeviceSize bytes, const char* what) const {
const auto type = MemoryType(mask, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
if (memoryProperties2 == nullptr || physical == VK_NULL_HANDLE) return type;
struct HeapReport {
VkDeviceSize budget = 0;
VkDeviceSize usage = 0;
bool Fits(VkDeviceSize bytes) const { return budget == 0 || (usage < budget && bytes <= budget - usage); }
};
HeapReport ReportedHeap(std::uint32_t heap) const {
if (memoryProperties2 == nullptr || physical == VK_NULL_HANDLE) return {};
VkPhysicalDeviceMemoryBudgetPropertiesEXT reported{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT};
VkPhysicalDeviceMemoryProperties2 properties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
properties.pNext = &reported;
memoryProperties2(physical, &properties);
return {reported.heapBudget[heap], reported.heapUsage[heap]};
}
bool DeviceLocalFits(std::uint32_t mask, VkDeviceSize bytes) const {
return ReportedHeap(memory.memoryTypes[MemoryType(mask, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)].heapIndex).Fits(bytes);
}
std::uint32_t DeviceMemoryType(std::uint32_t mask, VkDeviceSize bytes, const char* what) const {
const auto type = MemoryType(mask, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
const auto heap = memory.memoryTypes[type].heapIndex;
const auto budget = reported.heapBudget[heap];
const auto usage = reported.heapUsage[heap];
if (budget == 0 || (usage < budget && bytes <= budget - usage)) return type;
const auto report = ReportedHeap(heap);
if (report.Fits(bytes)) return type;
const auto host = HostMemoryType(mask);
if (!host) return type;
if (cacheReclaim != nullptr) {
const auto wanted = bytes + (usage > budget ? usage - budget : 0u);
const auto wanted = bytes + (report.usage > report.budget ? report.usage - report.budget : 0u);
const auto released = cacheReclaim(wanted, true);
if (released >= wanted) return type;
if (released != 0) {
memoryProperties2(physical, &properties);
if (reported.heapUsage[heap] < reported.heapBudget[heap] && bytes <= reported.heapBudget[heap] - reported.heapUsage[heap]) return type;
const auto after = ReportedHeap(heap);
if (after.Fits(bytes)) return type;
}
}
static std::atomic<std::uint64_t> placements{0}, placedBytes{0};
const auto count = placements.fetch_add(1) + 1;
const auto total = placedBytes.fetch_add(bytes) + bytes;
if (count <= 5 || (count & (count - 1)) == 0) std::fprintf(stderr, "[gpu] %s: device-local heap %u uses %llu of its %llu MiB budget, %llu bytes placed in host memory type %u; %llu such allocations, %llu MiB\n", what, heap, static_cast<unsigned long long>(usage >> 20u), static_cast<unsigned long long>(budget >> 20u), static_cast<unsigned long long>(bytes), *host, static_cast<unsigned long long>(count), static_cast<unsigned long long>(total >> 20u));
if (count <= 5 || (count & (count - 1)) == 0) std::fprintf(stderr, "[gpu] %s: device-local heap %u uses %llu of its %llu MiB budget, %llu bytes placed in host memory type %u; %llu such allocations, %llu MiB\n", what, heap, static_cast<unsigned long long>(report.usage >> 20u), static_cast<unsigned long long>(report.budget >> 20u), static_cast<unsigned long long>(bytes), *host, static_cast<unsigned long long>(count), static_cast<unsigned long long>(total >> 20u));
return *host;
}
bool DeviceLocalHeadroom(std::uint32_t type, VkDeviceSize bytes) const {
if (memoryProperties2 == nullptr || physical == VK_NULL_HANDLE || type >= memory.memoryTypeCount) return true;
const auto heap = memory.memoryTypes[type].heapIndex;
if ((memory.memoryHeaps[heap].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) == 0) return true;
VkPhysicalDeviceMemoryBudgetPropertiesEXT reported{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT};
VkPhysicalDeviceMemoryProperties2 properties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, &reported};
memoryProperties2(physical, &properties);
const auto budget = reported.heapBudget[heap];
if (budget == 0) return true;
const auto limit = budget - budget / 8u;
const auto usage = reported.heapUsage[heap];
return usage < limit && bytes <= limit - usage;
}
std::optional<std::uint32_t> HostMemoryType(std::uint32_t mask) const {
for (std::uint32_t i = 0; i < memory.memoryTypeCount; ++i) {
if ((mask & (1u << i)) != 0 && (memory.memoryHeaps[memory.memoryTypes[i].heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) == 0) return i;
@@ -70,6 +70,8 @@ DccKeys TextureClearKeys(const GuestTextureResource& resource, std::uint64_t gue
struct DccKeyProof {
DccKeys keys = DccKeys::Uncompressed;
std::uint64_t generation = 0;
std::uint64_t pendingNote = 0;
std::uint64_t pendingRecorder = 0;
};
// TextureClearKeys with the scan skipped while the key range is unchanged since `proof` was taken
// (CollectWrites over the keys, then UnchangedSince its generation), so a surface's keys are scanned
@@ -80,6 +82,8 @@ struct DccKeyProof {
// their record), which makes the proof exactly as sound as UnchangedSince over the texels.
// APS5_NO_KEY_FAST_PATH=1 scans on every call and stores nothing.
DccKeys ProvedClearKeys(const GuestTextureResource& resource, std::uint64_t guestBytes, DccKeyProof& proof);
DccKeyProof PendingKeyProof(const GuestTextureResource& resource, std::uint64_t guestBytes, DccKeys keys);
bool PendingKeyProofHolds(const GuestTextureResource& resource, std::uint64_t guestBytes, const DccKeyProof& proof);
bool KeyFastPath();
bool SingleKeysReadable(const GuestTextureResource& resource);
bool ReadSingleElement(const GuestTextureResource& resource, std::span<std::byte> element);
@@ -18,6 +18,7 @@ class Texture;
class StorageTexture;
VkImageView DepthSurfaceView(const Context& context, const DepthTarget& target, bool depthWritten = true, bool stencilTested = false);
VkImageView DepthSurfaceViewWithStencilWriteIntent(const Context& context, const DepthTarget& target, bool depthWritten, bool stencilTested, bool stencilWritten);
SampleOrderTarget DepthSurfaceOrderTarget(const Context& context, const DepthTarget& target);
DepthSampleLocations DepthSurfaceSampleLocations(const Context& context, const DepthTarget& target);
enum class DepthPlaneScope { Overlapped, Whole };
@@ -37,6 +38,8 @@ std::uint64_t DepthSliceBytes(VkExtent2D extent, std::uint32_t bytesPerTexel);
bool DirectDepthCopy(const Context& context, VkFormat depthFormat, VkImageAspectFlagBits aspect, VkFormat colorFormat);
void SetDirectDepthCopy(bool enabled);
std::uint64_t DirectDepthCopyCount();
void SetDepthTransferPasses(bool enabled);
std::uint64_t DepthTransferPassCount();
std::uint64_t MultisampledDepthBytes_nid_no_patch(VkExtent2D extent, std::uint32_t bytesPerTexel, std::uint32_t samples);
void RequireNoResidentDepthRead_nid_no_patch(std::uint64_t address, std::size_t bytes, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear = std::nullopt);
void AppendHostWrittenDepthRanges(std::uint64_t address, std::size_t bytes, std::vector<std::pair<std::uint64_t, std::uint64_t>>& ranges);
@@ -86,6 +89,7 @@ VkImageAspectFlags HtileFillClears(std::uint32_t pattern, bool stencilInHtile);
std::uint64_t HtileMetadataBytes(VkExtent2D extent);
bool HtileFillCovers(std::uint64_t htile, VkExtent2D extent, std::uint64_t address, std::size_t bytes);
std::shared_ptr<Texture> DepthSurfaceTexture(const Context& context, std::span<const std::uint32_t> words, const GuestTextureResource& resource, VkComponentMapping components, VkImageViewType multisampleViewType = VK_IMAGE_VIEW_TYPE_2D);
std::shared_ptr<Texture> DepthSurfaceFirstSample(const Context& context, std::span<const std::uint32_t> words, const GuestTextureResource& resource, VkComponentMapping components);
std::size_t DepthPlaneCopyCount();
VkDeviceSize DepthPlaneCopyBytes();
VkFormat HostDepthFormat(const Context& context, VkFormat format);
@@ -57,6 +57,15 @@ inline VkDeviceSize HostImportOffset(const HostImport& import, std::uint64_t add
return address - import.base + import.lead;
}
struct HostImportStart {
std::uint64_t guest;
VkDeviceAddress device;
};
inline HostImportStart HostImportBufferStart(const HostImport& import) {
return {import.base - import.lead, import.address - import.lead};
}
enum class ImportWatch : std::uint8_t { Watch, Unwatch };
struct ImportProbe {
@@ -467,7 +476,9 @@ private:
bool gpuCopy = false;
VkBuffer copySource = VK_NULL_HANDLE;
std::uint64_t copySourceBase = 0;
VkDeviceAddress copySourceAddress = 0;
bool copiedBack = false;
std::shared_ptr<Buffer> shadowCopy;
// An element the shader updates atomically lies inside (AddWritable's `atomic`).
bool atomic = false;
bool swept = false;
@@ -35,6 +35,8 @@ struct GuestSamplerResource {
GuestSamplerResource DecodeSamplerResource(std::span<const std::uint32_t> words, bool unnormalizedProven = false, bool forceDegammaPaired = false, bool integerBorder = false);
std::optional<std::array<std::uint32_t, 4>> SingleLevelSamplerWords(std::span<const std::uint32_t, 4> words, bool singleLevelImage, bool mipmappedImage);
bool HoldsLodAtZero(std::span<const std::uint32_t, 4> words);
std::array<std::uint32_t, 4> PinnedLodSamplerWords(std::span<const std::uint32_t, 4> words, std::uint32_t lod);
}
@@ -4,6 +4,7 @@
#include "Recompiler.hpp"
#include <array>
#include <cstdint>
#include <optional>
#include <span>
namespace AgcDriver::Graphics {
@@ -141,6 +142,8 @@ constexpr TextureTileMode GcnMicroTileMode(TextureTileMode mode) {
float EffectiveMinLod(const GuestTextureResource& resource);
bool IsNullTextureResource(std::span<const std::uint32_t> words);
std::optional<std::uint64_t> TextureResourceAllocationAddress(std::span<const std::uint32_t> words);
bool IsNullSampledTextureResource(std::span<const std::uint32_t> words);
GuestTextureResource DecodeTextureResource(std::span<const std::uint32_t> words);
std::array<std::uint32_t, 8> EncodeTextureResource(const GuestTextureResource& resource);
bool DescriptorSingleLevel(std::span<const std::uint32_t> words);
@@ -157,7 +157,7 @@ bool ShadersWriteMemory(std::span<const CompiledShader> shaders);
bool DeclaresEarlyFragmentTests(const ShaderRecompiler::RecompileResult& program);
void ValidateSampleMask(const Context& context, const State& state, std::span<const CompiledShader> shaders);
// Returns the color attachment locations the pixel shader writes.
std::set<std::uint32_t> ValidateShaders(std::span<const CompiledShader> shaders, const State& state, const VkPhysicalDeviceSubgroupProperties& subgroup, bool fragmentShaderBarycentric, bool descriptorIndexing = false, bool imageInt64Atomics = false, bool geometryShader = false, bool sampleRateShading = false, bool bufferInt64Atomics = false, bool shaderClipDistance = false, bool shaderCullDistance = false, bool viewportIndexLayer = false, bool runtimeDescriptorArray = false, bool demoteToHelperInvocation = false, bool shaderTerminateInvocation = false, bool meshShader = true);
std::set<std::uint32_t> ValidateShaders(std::span<const CompiledShader> shaders, const State& state, const VkPhysicalDeviceSubgroupProperties& subgroup, bool fragmentShaderBarycentric, bool descriptorIndexing = false, bool imageInt64Atomics = false, bool geometryShader = false, bool sampleRateShading = false, bool bufferInt64Atomics = false, bool shaderClipDistance = false, bool shaderCullDistance = false, bool viewportIndexLayer = false, bool runtimeDescriptorArray = false, bool demoteToHelperInvocation = false, bool shaderTerminateInvocation = false, bool meshShader = true, bool shaderResourceMinLod = false);
}
@@ -244,6 +244,7 @@ public:
void CountSamples();
bool CountingSamples() const { return countingSamples; }
bool RecordMeshArguments(VkCommandBuffer commands, VkDeviceAddress record, VkDeviceAddress arguments, std::span<const std::uint32_t, 7> rules);
bool RecordChangedCopy(VkCommandBuffer commands, VkDeviceAddress result, VkDeviceAddress snapshot, VkDeviceAddress target, std::uint32_t dwords, VkDeviceAddress counter = 0);
std::uint64_t SamplesTotal();
bool DumpSamples(VkDeviceAddress target, std::uint64_t address = 0);
void NoteSampledDraw(VkCommandBuffer commands);
@@ -394,6 +395,7 @@ public:
// The function the flush hook calls, on the accessing thread (which may hold the GPU mutex),
// when an access overlaps one of that thread's queued labels; it records them. Set once.
static void SetQueuedLabelRecorder(void (*recorder)());
static void FailNextSubmitsForTest(unsigned count);
// Whether the lock-free pending-write snapshot (open, in-flight and finishing batches) overlaps
// the range: false means no recorded work writes it, so a wait on it has nothing to submit.
static bool SnapshotWriteOverlaps(std::uint64_t address, std::size_t bytes);
@@ -769,6 +771,9 @@ private:
int meshArgumentState = 0;
VkPipelineLayout meshArgumentLayout = VK_NULL_HANDLE;
VkPipeline meshArgumentPipeline = VK_NULL_HANDLE;
int changedCopyState = 0;
VkPipelineLayout changedCopyLayout = VK_NULL_HANDLE;
VkPipeline changedCopyPipeline = VK_NULL_HANDLE;
int sampleCounterState = 0;
std::unique_ptr<Buffer> sampleCounter;
VkPipelineLayout sampleLayout = VK_NULL_HANDLE;
@@ -12,6 +12,7 @@ public:
~Buffer();
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
static std::shared_ptr<Buffer> WithinDeviceLocalHeadroom(const Context& context, std::size_t size, VkBufferUsageFlags usage);
VkBuffer Handle() const;
VkDeviceAddress DeviceAddress() const;
// Host-visible buffers only: a device-local one (properties without HOST_VISIBLE, the staging
@@ -21,6 +22,7 @@ public:
void Invalidate();
private:
Buffer(const Context& context, std::size_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, bool headroom);
void initializeAddress(VkBufferUsageFlags usage);
void release() noexcept;
Context context;
@@ -68,10 +68,10 @@ private:
std::uint64_t misses = 0;
};
void RequireFilterMinmax(const Context& context, VkFormat format, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
bool ForcesDegammaOn(std::uint32_t guestFormat, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
void RequireBorderSwizzle(std::uint32_t bcSwizzle, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
void RequireNonSeamlessCube(bool cube, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
void RequireFilterMinmax(const Context& context, VkFormat format, std::uint64_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
bool ForcesDegammaOn(std::uint32_t guestFormat, std::uint64_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
void RequireBorderSwizzle(std::uint32_t bcSwizzle, std::uint64_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
void RequireNonSeamlessCube(bool cube, std::uint64_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
}
@@ -7,6 +7,7 @@
#include "prx/libSceAgcDriver/Graphics/include/Sampler.hpp"
#include "prx/libSceAgcDriver/Execution/include/Mutex.hpp"
#include "Recompiler.hpp"
#include "IntermediateRepresentation/IrMetadata/ResourcePlan.hpp"
#include "prx/libSceAgcDriver/Graphics/include/Shaders.hpp"
#include <array>
#include <chrono>
@@ -54,6 +55,7 @@ bool SampledTexturesShareEntry(std::span<const std::uint32_t> first, std::span<c
bool AnyPendingCpuWrites(const Context& context);
bool CompletePendingCpuWrites(const Context& context, std::uint64_t address, std::size_t bytes);
bool SpirvStoresThroughAddresses(std::span<const std::uint32_t> words);
bool SpirvFaultReportOnly(std::span<const std::uint32_t> words, std::uint32_t set, std::uint32_t binding);
bool ShaderStoresThroughAddresses(const ShaderRecompiler::SharedSpirv& spirv);
void LastRecordIndices(std::span<const void* const> logged, std::span<const void* const> objects, std::vector<std::size_t>& indices);
@@ -157,6 +159,7 @@ struct ImageTableReuseCounts {
ImageTableReuseCounts ImageTableReuses();
std::uint64_t SampledTexturesCleared();
std::uint64_t SampledLookupKeyScans();
std::uint64_t SampledLookupKeyProofs();
struct PresyncSurface {
std::uint64_t address;
@@ -504,6 +507,7 @@ private:
bool depthCompare = false;
VkImageViewType multisampleViewType = VK_IMAGE_VIEW_TYPE_2D;
bool firstSample = false;
bool layerRows = false;
std::shared_ptr<Texture> texture;
};
PreviousSampled previousSampled;
@@ -513,7 +517,7 @@ private:
// lock and the cache still holds it; null sends the element to cachedTexture.
std::shared_ptr<Texture> fastTexture(const ImageRecord& record);
void resolveImageBinding(const ShaderRecompiler::DescriptorBinding& binding, Binding& item, std::span<const std::shared_ptr<Sampler>> shaderSamplers);
void applyAnisoOverride();
void applySamplerVariants();
void forgetDeferredInputs();
void release() noexcept;
void prepareAddressBindings(std::span<const CompiledShader> shaders, std::span<const GuestMemorySnapshot> snapshots);
@@ -586,6 +590,7 @@ private:
std::vector<BdaResources::SrtGuardFaults> srtGuardFaults;
bool usesBda = false;
bool bdaReadOnly = true;
bool faultReportOnly = true;
std::vector<std::uint64_t> multisampleSources;
bool usesFaultBuffer = false;
bool faultChecks = false;
@@ -618,9 +623,16 @@ private:
std::shared_ptr<const TableDescriptors> keptTable(std::size_t set, std::shared_ptr<const std::vector<std::weak_ptr<Texture>>>& held) noexcept;
std::uint32_t setOf(const Binding& binding) const;
std::vector<Allocation> allocations;
std::vector<VkDescriptorBufferInfo> descriptorBuffers;
mutable std::vector<VkDescriptorBufferInfo> descriptorBuffers;
std::vector<VkDescriptorImageInfo> descriptorImages;
std::vector<VkWriteDescriptorSet> descriptorWrites;
struct FaultDescriptor {
std::size_t write;
std::size_t buffer;
std::uint32_t element;
};
std::vector<FaultDescriptor> faultDescriptors;
void prepareFaultSlot() const;
mutable std::vector<VkDescriptorPoolSize> drawPoolSizes;
// Guest buffer elements bound read-only: each use of this object skips that many pending-write
// notes (counted in MarkGpuWrites for the [buffers] line).
@@ -651,11 +663,13 @@ private:
bool integerBorder = false;
bool singleLevelImage = false;
bool mipmappedImage = false;
std::optional<std::uint32_t> pinnedLod;
};
std::vector<SamplerSource> samplerSources;
bool reusable = false;
std::vector<DirectRegion> directRegions;
std::vector<ValidatedSurface> validatedTextures;
std::vector<ShaderRecompiler::RegisteredImageView> registeredImageViews;
// The pending registry's serial at the last Revalidate that proved this object, taken before
// its checks and kept only when unchanged after them (0: none): while it is still the serial,
// no image other than the object's own sources has results pending over its surfaces and
@@ -2,6 +2,7 @@
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_GRAPHICS_INCLUDE_SHADERS_HPP
#include "prx/libSceAgcDriver/Graphics/include/Context.hpp"
#include "IntermediateRepresentation/IrMetadata/ResourcePlan.hpp"
#include "Recompiler.hpp"
#include <array>
#include <cstddef>
@@ -37,6 +38,7 @@ struct CompiledShader {
ShaderRecompiler::ShaderStage stage;
const ShaderRecompiler::RecompileResult* program;
std::uint32_t pushConstantOffset;
const std::vector<ShaderRecompiler::RegisteredImageView>* registeredImageViews = nullptr;
};
inline VkShaderStageFlagBits VulkanStage(ShaderRecompiler::ShaderStage stage) {
@@ -111,6 +111,7 @@ struct DepthTarget {
bool htilePipeAligned = false;
std::uint32_t htileVrsEncoding = 0;
bool htileDepthOnly = false;
bool gcn = false;
};
struct State {
@@ -60,7 +60,7 @@ struct OwnedImage {
class Texture {
public:
Texture(const Context& context, TextureDetiler& detiler, const GuestTextureResource& descriptor, VkComponentMapping components, std::span<const std::byte> snapshot, bool depthCompare = false, const VkClearColorValue* clear = nullptr);
Texture(const Context& context, TextureDetiler& detiler, const GuestTextureResource& descriptor, VkComponentMapping components, std::span<const std::byte> snapshot, bool depthCompare = false, bool layerRows = false, const VkClearColorValue* clear = nullptr);
Texture(const Context& context, const std::shared_ptr<ResidentColor>& source, const GuestTextureResource& descriptor, VkComponentMapping components);
// A view of a storage image's own VkImage: the sampled texture follows the image's content, so a
// compute pass writing it and the next pass sampling it share one image and copy nothing.
@@ -303,9 +303,12 @@ public:
static bool UnwatchHookLocksGpu(std::span<const std::pair<std::uint64_t, std::uint64_t>> ranges);
static void SetPublishHookForTest(void (*hook)());
static constexpr std::uint64_t SmallStoreBytes = 64 * 1024;
static constexpr std::uint64_t OccasionalStoreBytes = 1024 * 1024;
static constexpr std::uint64_t OccasionalWriteFlips = 8;
static std::size_t StoreSmallPending(const char* reason);
static void StoreReadbackBeforeLabel(const char* reason);
static void StoreReadbackBeforeLabel(const char* reason, VkDevice device = VK_NULL_HANDLE);
static std::size_t StoreDrawnLinear(const char* reason);
static void NoteFlip();
static std::size_t StoreDrawnLinearTouching(const char* reason, const std::function<bool(std::uint64_t, std::uint64_t)>& touches, bool all);
static bool AnyPending();
static void FlushDumpSelected(const char* reason);
@@ -471,6 +474,7 @@ public:
static std::uint64_t HandedOverSuperseded();
static void SetClearHandOver(bool enabled);
static std::uint64_t UntrackedCompares();
static std::uint64_t OccasionalLabelStores();
std::uint64_t GuestBytes() const;
std::uint64_t BudgetBytes() const;
std::size_t OriginalSnapshotBytes() const { return original.capacity(); }
@@ -518,9 +522,11 @@ private:
void releaseReadTraps(bool sharingPages);
void storeTrappedOverlaps(const char* reason);
bool unchangedSinceBaseline(std::uint64_t from, std::uint64_t to) const;
bool cpuLeftUnchanged(std::uint32_t layer, std::uint64_t from, std::uint64_t to, bool edge) const;
void saveBeforeUnwatch();
void forgetKeptAtUnwatch(std::uint32_t unit);
bool keptAtUnwatchHolds(std::uint64_t from, std::uint32_t unit) const;
bool keptForCpu(std::uint32_t unit) const;
// Drops the saved guest bytes of the units over [address, address + bytes) (another image's fill
// or copy supersedes them there); the other units' bytes stay valid.
void forgetSavedOver(std::uint64_t address, std::size_t bytes);
@@ -747,6 +753,7 @@ private:
std::uint32_t trackedLayers = 1;
std::uint64_t trackedLayerBytes = 0;
std::vector<std::uint64_t> layerGeneration;
std::vector<std::uint64_t> layerPendingSince;
std::vector<std::uint64_t> completionKept;
UnitFlags layerPending;
std::vector<bool> layerBehind;
@@ -795,6 +802,8 @@ private:
bool pendingFromOthers = false;
std::vector<DrawnRect> drawnRects;
std::vector<std::uint64_t> storeNotes;
std::uint64_t writtenFlip = 0;
std::atomic<bool> writtenOccasionally{false};
std::uint64_t version = 0;
std::uint64_t writes = 0;
// `original` holds the guest bytes; false after a GPU-side clear, which never read them.
@@ -92,6 +92,8 @@ namespace AgcDriver::Graphics {
VkShaderModule imageModule = VK_NULL_HANDLE;
VkShaderModule repackModule = VK_NULL_HANDLE;
VkPipeline repackPipeline = VK_NULL_HANDLE;
VkShaderModule imageWordModule = VK_NULL_HANDLE;
VkShaderModule wordModule = VK_NULL_HANDLE;
DescriptorRing imageDescriptorSets;
VkDescriptorSetLayout readbackDescriptorLayout = VK_NULL_HANDLE;
VkPipelineLayout readbackPipelineLayout = VK_NULL_HANDLE;
@@ -11,7 +11,6 @@
#include <cstdio>
#include <limits>
#include <optional>
#include <set>
#include <span>
#include <utility>
#include <vector>
@@ -128,14 +127,39 @@ inline std::array<char, 160> VertexDescriptorFlagsMessage(const ShaderRecompiler
return message;
}
inline bool QueryVertexBufferFormat(const Context& context, VkFormat format) {
VkFormatProperties properties{};
context.formatProperties(context.physical, format, &properties);
return (properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != 0;
}
class VertexBufferFormats {
public:
bool Supported(const Context& context, VkFormat format) {
const auto index = static_cast<std::size_t>(format);
if (index >= known.size()) return QueryVertexBufferFormat(context, format);
auto state = known[index].load(std::memory_order_relaxed);
if (state == 0) {
state = QueryVertexBufferFormat(context, format) ? 2 : 1;
known[index].store(state, std::memory_order_relaxed);
}
return state == 2;
}
private:
std::array<std::atomic<std::uint8_t>, VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1> known{};
};
inline VertexInputLayout BuildVertexInputLayout(const Context& context, std::span<const ShaderRecompiler::VertexAttribute> attributes) {
Require(attributes.size() <= context.limits.maxVertexInputBindings && attributes.size() <= context.limits.maxVertexInputAttributes, "vertex input count exceeds device limits");
VertexInputLayout result;
std::set<std::uint32_t> locations;
result.bindings.reserve(attributes.size());
result.attributes.reserve(attributes.size());
for (const auto& attribute : attributes) {
const auto& fields = attribute.resource.fields;
const auto format = DecodeVertexFormat(attribute);
Require(attribute.location < context.limits.maxVertexInputAttributes && locations.insert(attribute.location).second, "invalid or duplicate vertex attribute location");
const auto duplicate = std::any_of(result.attributes.begin(), result.attributes.end(), [&](const auto& described) { return described.location == attribute.location; });
Require(attribute.location < context.limits.maxVertexInputAttributes && !duplicate, "invalid or duplicate vertex attribute location");
Require(attribute.fetchIndex <= 1, "unsupported vertex fetch index");
if ((fields[1] & 0x80000000u) != 0 || (fields[3] & 0x00800000u) != 0 || (fields[3] >> 30u) != 0) {
Require(false, VertexDescriptorFlagsMessage(attribute).data());
@@ -146,9 +170,7 @@ inline VertexInputLayout BuildVertexInputLayout(const Context& context, std::spa
Require(stride <= context.limits.maxVertexInputBindingStride, "vertex stride exceeds device limits");
Require(context.formatProperties != nullptr, "missing vertex format property query");
const auto supported = [&](VkFormat candidate) {
VkFormatProperties properties{};
context.formatProperties(context.physical, candidate, &properties);
return (properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != 0;
return context.vertexFormats != nullptr ? context.vertexFormats->Supported(context, candidate) : QueryVertexBufferFormat(context, candidate);
};
auto host = format.format;
auto hostSupported = supported(host);
@@ -156,7 +178,7 @@ inline VertexInputLayout BuildVertexInputLayout(const Context& context, std::spa
host = DecodeVertexFormat(attribute, components).format;
hostSupported = supported(host);
}
Require(hostSupported, "device does not support vertex format " + std::to_string(format.format));
if (!hostSupported) Require(false, "device does not support vertex format " + std::to_string(format.format));
const auto binding = static_cast<std::uint32_t>(result.bindings.size());
result.bindings.push_back({binding, stride, attribute.fetchIndex == 0 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE});
result.attributes.push_back({attribute.location, binding, host, 0});
@@ -0,0 +1,16 @@
#version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(local_size_x = 8, local_size_y = 8) in;
layout(set = 0, binding = 0) uniform texture2D depthPlane;
layout(set = 0, binding = 1, r32ui) uniform writeonly uimage2D texels;
layout(push_constant) uniform Push {
uvec2 offset;
uvec2 extent;
} push;
void main() {
if (any(greaterThanEqual(gl_GlobalInvocationID.xy, push.extent))) return;
const ivec2 position = ivec2(push.offset + gl_GlobalInvocationID.xy);
imageStore(texels, position, uvec4(floatBitsToUint(texelFetch(depthPlane, position, 0).r)));
}
@@ -0,0 +1,34 @@
#version 450
#extension GL_EXT_buffer_reference : require
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
layout(local_size_x = 64) in;
layout(buffer_reference, std430, buffer_reference_align = 4) buffer Words { uint words[]; };
layout(push_constant) uniform Parameters {
Words result;
Words snapshot;
Words target;
Words counter;
uint count;
uint always;
} parameters;
uint differingBytes(uint difference) {
uint folded = difference | (difference >> 1u);
folded |= folded >> 2u;
folded |= folded >> 4u;
return (folded & 0x01010101u) * 0xffu;
}
void main() {
uint index = gl_GlobalInvocationID.x;
if (index >= parameters.count) return;
uint value = parameters.result.words[index];
uint before = parameters.snapshot.words[index];
uint held = parameters.target.words[index];
uint changed = differingBytes(value ^ before);
uint kept = differingBytes(held ^ before);
uint stored = parameters.always != 0u ? 0xffffffffu : changed & ~kept;
if (stored != 0u) parameters.target.words[index] = (held & ~stored) | (value & stored);
if (uint64_t(parameters.counter) != 0ul && (changed & kept) != 0u) atomicAdd(parameters.counter.words[0], 1u);
}
@@ -207,34 +207,27 @@ void copyElement(uint src, uint dst) {
}
#endif
void main() {
uvec2 p = gl_GlobalInvocationID.xy + uvec2(params.columnBegin, params.rowBegin);
if (p.x >= params.width || p.y >= params.height) {
return;
}
bool locate(uvec2 p, out uint src, out uint dst, out uint ranged) {
uint linearOffset = p.y * params.pitchBytes + p.x * ELEMENT_BYTES;
if (TILE_FAMILY == 0u) {
// kLinear: guest and host layouts match; a straight copy at the
// same pitch, no swizzle.
ranged = linearOffset;
if (linearOffset < params.rangeBegin || linearOffset >= params.rangeEnd) {
return;
return false;
}
#ifdef LINEAR_IMAGE
if (RETILE != 0u) {
loadElement(p, params.dstBase + linearOffset - params.tiledBase);
} else {
storeElement(params.srcBase + linearOffset - params.tiledBase, p);
}
src = params.srcBase + linearOffset - params.tiledBase;
dst = params.dstBase + linearOffset - params.tiledBase;
#else
if (RETILE != 0u) {
copyElement(params.srcBase + linearOffset - params.linearBase, params.dstBase + linearOffset - params.tiledBase);
src = params.srcBase + linearOffset - params.linearBase;
dst = params.dstBase + linearOffset - params.tiledBase;
} else {
copyElement(params.srcBase + linearOffset - params.tiledBase, params.dstBase + linearOffset - params.linearBase);
src = params.srcBase + linearOffset - params.tiledBase;
dst = params.dstBase + linearOffset - params.linearBase;
}
#endif
return;
return true;
}
uvec2 swizzle = p;
@@ -251,24 +244,106 @@ void main() {
uint split = equationBit(SPLIT0, p) | (equationBit(SPLIT1, p) << 1) | (equationBit(SPLIT2, p) << 2) | (equationBit(SPLIT3, p) << 3);
tiledOffset += split * params.splitStride;
}
ranged = tiledOffset;
if (tiledOffset < params.rangeBegin || tiledOffset >= params.rangeEnd) {
return;
return false;
}
tiledOffset -= params.tiledBase;
linearOffset -= params.linearBase;
#ifdef LINEAR_IMAGE
if (RETILE != 0u) {
loadElement(p, params.dstBase + tiledOffset);
} else {
storeElement(params.srcBase + tiledOffset, p);
}
src = params.srcBase + tiledOffset;
dst = params.dstBase + tiledOffset;
#else
if (RETILE != 0u) {
copyElement(params.srcBase + linearOffset, params.dstBase + tiledOffset);
src = params.srcBase + linearOffset;
dst = params.dstBase + tiledOffset;
} else {
copyElement(params.srcBase + tiledOffset, params.dstBase + linearOffset);
src = params.srcBase + tiledOffset;
dst = params.dstBase + linearOffset;
}
#endif
return true;
}
void moveElement(uvec2 p) {
uint src;
uint dst;
uint ranged;
if (!locate(p, src, dst, ranged)) {
return;
}
#ifdef LINEAR_IMAGE
if (RETILE != 0u) {
loadElement(p, dst);
} else {
storeElement(src, p);
}
#else
copyElement(src, dst);
#endif
}
#ifdef WORD_GROUPS
shared uint groupWords[32];
shared uint groupLanes[32];
shared uint groupDestinations[64];
void main() {
uvec2 p = gl_GlobalInvocationID.xy + uvec2(params.columnBegin, params.rowBegin);
bool inside = p.x < params.width && p.y < params.height;
uint lane = gl_LocalInvocationID.y * gl_WorkGroupSize.x + gl_LocalInvocationID.x;
uint count = 4u / ELEMENT_BYTES;
uint slot = lane / count;
uint index = lane % count;
uint src = 0u;
uint dst = 0u;
uint ranged = 0u;
bool valid = inside && locate(p, src, dst, ranged);
if (index == 0u) {
groupWords[slot] = 0u;
groupLanes[slot] = 0u;
}
groupDestinations[lane] = dst;
barrier();
if (valid) {
uint mask = ELEMENT_BYTES == 1u ? 0xffu : 0xffffu;
#ifdef LINEAR_IMAGE
uint value = imageLoad(linearImage, ivec2(p)).x & mask;
#else
uint value = (inputBuffer.data[src >> 2] >> ((src & 3u) * 8u)) & mask;
#endif
atomicOr(groupWords[slot], value << (index * ELEMENT_BYTES * 8u));
atomicOr(groupLanes[slot], 1u << index);
}
barrier();
uint first = groupDestinations[slot * count];
bool whole = groupLanes[slot] == (1u << count) - 1u && (first & 3u) == 0u;
for (uint i = 1u; i < count; ++i) {
whole = whole && groupDestinations[slot * count + i] == first + i * ELEMENT_BYTES;
}
if (whole) {
if (index == 0u) {
#ifdef LINEAR_IMAGE
tiledBuffer.data[first >> 2] = groupWords[slot];
#else
outputBuffer.data[first >> 2] = groupWords[slot];
#endif
}
} else if (valid) {
#ifdef LINEAR_IMAGE
loadElement(p, dst);
#else
copyElement(src, dst);
#endif
}
}
#else
void main() {
uvec2 p = gl_GlobalInvocationID.xy + uvec2(params.columnBegin, params.rowBegin);
if (p.x >= params.width || p.y >= params.height) {
return;
}
moveElement(p);
}
#endif
@@ -4,6 +4,7 @@
#include "ImageTableAbi.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include <algorithm>
#include <array>
#include <atomic>
#include <bit>
#include <cstdio>
@@ -13,7 +14,12 @@
#include <list>
#include <mutex>
#include <iomanip>
#include <span>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
namespace AgcDriver::Graphics {
@@ -104,15 +110,207 @@ std::uint64_t hashRanges(const std::vector<ShaderRecompiler::BdaAbi::Range>& ran
}
BdaResources::BdaResources(const Context& context) {
static_assert(std::endian::native == std::endian::little);
Require(ShaderRecompiler::BdaAbi::FaultBufferBytes <= context.limits.maxStorageBufferRange, "BDA fault buffer exceeds storage buffer range limit");
fault = std::make_unique<Buffer>(context, ShaderRecompiler::BdaAbi::FaultBufferBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
std::memset(fault->Bytes().data(), 0, ShaderRecompiler::BdaAbi::WrittenListWord * sizeof(std::uint32_t));
std::memset(fault->Bytes().data() + ShaderRecompiler::BdaAbi::SrtGuardWord * sizeof(std::uint32_t), 0, sizeof(std::uint32_t));
struct BdaFaultChunk {
std::unique_ptr<Buffer> buffer;
std::vector<VkDeviceSize> free;
std::size_t slots = 0;
VkDeviceSize slotBytes = 0;
};
namespace {
struct FaultArena {
std::vector<std::shared_ptr<BdaFaultChunk>> chunks;
std::unordered_set<BdaResources*> holders;
std::uint64_t finished = 0;
BdaResources::FaultSlotCounts counts;
};
struct FaultArenas {
std::mutex mutex;
std::unordered_map<VkDevice, FaultArena> devices;
};
FaultArenas& faultArenas() {
static auto* arenas = new FaultArenas();
return *arenas;
}
BdaResources::BdaResources(const Context& context, const GuestBufferMemory& memory) : BdaResources(context) {
bool sharedFaultSlots() {
static const bool shared = std::getenv("APS5_NO_SHARED_FAULT_SLOTS") == nullptr;
return shared;
}
constexpr VkDeviceSize FaultChunkBytes = VkDeviceSize{512} * 1024;
VkDeviceSize faultSlotBytes(bool reportOnly) {
return reportOnly ? sizeof(ShaderRecompiler::BdaAbi::Fault) : ShaderRecompiler::BdaAbi::FaultBufferBytes;
}
VkDeviceSize faultStride(const Context& context, VkDeviceSize bytes) {
const auto alignment = std::max<VkDeviceSize>(context.limits.minStorageBufferOffsetAlignment, sizeof(std::uint32_t));
return (bytes + alignment - 1) / alignment * alignment;
}
bool faultSlotClean(std::span<const std::byte> bytes) {
namespace Abi = ShaderRecompiler::BdaAbi;
if (bytes.size() < Abi::FaultBufferBytes) return std::all_of(bytes.begin(), bytes.end(), [](std::byte value) { return value == std::byte{0}; });
std::array<std::uint32_t, Abi::WrittenSlotsWord> head{};
std::memcpy(head.data(), bytes.data(), sizeof(head));
std::uint32_t guard = 0;
std::memcpy(&guard, bytes.data() + Abi::SrtGuardWord * sizeof(std::uint32_t), sizeof(guard));
return guard == 0 && std::all_of(head.begin(), head.end(), [](std::uint32_t word) { return word == 0; });
}
void clearFaultSlot(std::span<std::byte> bytes) {
namespace Abi = ShaderRecompiler::BdaAbi;
if (bytes.size() < Abi::FaultBufferBytes) {
std::memset(bytes.data(), 0, bytes.size());
return;
}
std::memset(bytes.data(), 0, Abi::WrittenListWord * sizeof(std::uint32_t));
std::memset(bytes.data() + Abi::SrtGuardWord * sizeof(std::uint32_t), 0, sizeof(std::uint32_t));
}
void dropChunk(FaultArena& arena, const std::shared_ptr<BdaFaultChunk>& chunk, std::vector<std::shared_ptr<BdaFaultChunk>>& dropped) {
const auto found = std::find(arena.chunks.begin(), arena.chunks.end(), chunk);
if (found == arena.chunks.end()) return;
arena.counts.slots -= (*found)->slots;
--arena.counts.chunks;
dropped.push_back(std::move(*found));
arena.chunks.erase(found);
}
}
BdaResources::BdaResources(const Context& context, bool reportOnly) : reportOnly(reportOnly) {
static_assert(std::endian::native == std::endian::little);
Require(ShaderRecompiler::BdaAbi::FaultBufferBytes <= context.limits.maxStorageBufferRange, "BDA fault buffer exceeds storage buffer range limit");
TakeFaultSlot(context);
}
BdaResources::~BdaResources() {
std::vector<std::shared_ptr<BdaFaultChunk>> dropped;
auto& arenas = faultArenas();
std::lock_guard lock(arenas.mutex);
if (faultChunk == nullptr) return;
const auto bytes = faultBytes();
if (!faultSlotClean(bytes)) clearFaultSlot(bytes);
const auto chunk = faultChunk;
dropped.push_back(std::move(faultChunk));
const auto found = arenas.devices.find(faultDevice);
if (found == arenas.devices.end()) return;
auto& arena = found->second;
arena.holders.erase(this);
--arena.counts.held;
if (!sharedFaultSlots()) {
arena.counts.slots -= chunk->slots;
--arena.counts.chunks;
} else {
chunk->free.push_back(faultOffset);
if (chunk->free.size() == chunk->slots) dropChunk(arena, chunk, dropped);
}
if (arena.holders.empty()) {
while (!arena.chunks.empty()) dropChunk(arena, arena.chunks.back(), dropped);
arenas.devices.erase(found);
}
}
std::span<std::byte> BdaResources::faultBytes() const {
return faultChunk->buffer->Bytes().subspan(static_cast<std::size_t>(faultOffset), static_cast<std::size_t>(faultChunk->slotBytes));
}
void BdaResources::NoteUse(std::uint64_t serial) {
auto& arenas = faultArenas();
std::lock_guard lock(arenas.mutex);
lastUse = std::max(lastUse, serial);
}
void BdaResources::NoteFinished(VkDevice device, std::uint64_t serial) {
auto& arenas = faultArenas();
std::lock_guard lock(arenas.mutex);
const auto found = arenas.devices.find(device);
if (found != arenas.devices.end()) found->second.finished = serial;
}
BdaResources::FaultSlotCounts BdaResources::FaultSlots(VkDevice device) {
auto& arenas = faultArenas();
std::lock_guard lock(arenas.mutex);
const auto found = arenas.devices.find(device);
return found != arenas.devices.end() ? found->second.counts : FaultSlotCounts{};
}
bool BdaResources::TakeFaultSlot(const Context& context) {
if (faultChunk != nullptr) return false;
std::vector<std::shared_ptr<BdaFaultChunk>> dropped;
auto& arenas = faultArenas();
std::lock_guard lock(arenas.mutex);
auto& arena = arenas.devices[context.device];
const bool retake = faultDevice != VK_NULL_HANDLE;
if (!retake) lastUse = arena.finished + 1;
faultDevice = context.device;
const bool shared = sharedFaultSlots();
const auto slotBytes = shared ? faultSlotBytes(reportOnly) : VkDeviceSize{ShaderRecompiler::BdaAbi::FaultBufferBytes};
const auto withFree = [&] { return std::find_if(arena.chunks.rbegin(), arena.chunks.rend(), [&](const std::shared_ptr<BdaFaultChunk>& chunk) { return chunk->slotBytes == slotBytes && !chunk->free.empty(); }); };
auto source = shared ? withFree() : arena.chunks.rend();
bool reclaimed = false;
if (shared && source == arena.chunks.rend() && GuestMemory::GpuMutex().HeldByThisThread()) {
std::vector<BdaResources*> idle;
for (auto* holder : arena.holders) {
if (holder->faultChunk->slotBytes == slotBytes && holder->lastUse <= arena.finished && faultSlotClean(holder->faultBytes())) idle.push_back(holder);
}
if (!idle.empty()) {
const auto reclaim = (idle.size() + 1) / 2;
std::nth_element(idle.begin(), idle.begin() + static_cast<std::ptrdiff_t>(reclaim - 1), idle.end(), [](const BdaResources* left, const BdaResources* right) { return left->lastUse < right->lastUse; });
for (std::size_t index = 0; index < reclaim; ++index) {
auto& holder = *idle[index];
holder.faultChunk->free.push_back(holder.faultOffset);
holder.faultChunk.reset();
arena.holders.erase(&holder);
--arena.counts.held;
++arena.counts.reclaimed;
}
reclaimed = true;
source = withFree();
}
}
std::shared_ptr<BdaFaultChunk> chunk;
if (source != arena.chunks.rend()) {
chunk = *source;
} else {
const auto stride = shared ? faultStride(context, slotBytes) : slotBytes;
const auto slots = shared ? std::max<VkDeviceSize>(1, FaultChunkBytes / stride) : 1;
chunk = std::make_shared<BdaFaultChunk>();
chunk->buffer = std::make_unique<Buffer>(context, static_cast<std::size_t>(stride * slots), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
std::memset(chunk->buffer->Bytes().data(), 0, chunk->buffer->Bytes().size());
chunk->slots = static_cast<std::size_t>(slots);
chunk->slotBytes = slotBytes;
for (auto slot = slots; slot-- > 0;) chunk->free.push_back(slot * stride);
if (shared) arena.chunks.push_back(chunk);
arena.counts.slots += chunk->slots;
++arena.counts.chunks;
}
faultOffset = chunk->free.back();
chunk->free.pop_back();
faultChunk = chunk;
arena.holders.insert(this);
++arena.counts.held;
if (retake) ++arena.counts.retaken;
bool spare = false;
for (auto it = arena.chunks.begin(); reclaimed && it != arena.chunks.end();) {
if ((*it)->free.size() != (*it)->slots || !std::exchange(spare, true)) {
++it;
continue;
}
arena.counts.slots -= (*it)->slots;
--arena.counts.chunks;
dropped.push_back(std::move(*it));
it = arena.chunks.erase(it);
}
return true;
}
BdaResources::BdaResources(const Context& context, const GuestBufferMemory& memory, bool reportOnly) : BdaResources(context, reportOnly) {
const auto cached = memory.CachedAddressTable();
std::vector<ShaderRecompiler::BdaAbi::Range> built;
if (!cached.has_value()) built = memory.AddressRanges();
@@ -228,7 +426,7 @@ VkDescriptorBufferInfo BdaResources::Table() const {
}
VkDescriptorBufferInfo BdaResources::Fault() const {
return {fault->Handle(), 0, ShaderRecompiler::BdaAbi::FaultBufferBytes};
return {faultChunk->buffer->Handle(), faultOffset, faultChunk->slotBytes};
}
namespace {
@@ -240,12 +438,13 @@ bool LoopGuardTripped() {
}
void BdaResources::CheckFault() const {
markWrittenPages();
if (faultChunk == nullptr) return;
if (!reportOnly) markWrittenPages();
ShaderRecompiler::BdaAbi::Fault report{};
std::memcpy(&report, fault->Bytes().data(), sizeof(report));
std::memcpy(&report, faultBytes().data(), sizeof(report));
if (report.state == ShaderRecompiler::BdaAbi::FaultState::Empty) {
Require(static_cast<std::uint32_t>(report.reason) == 0 && report.address == 0 && report.bytes == 0 && report.stage == 0 && report.instruction == 0 && report.otherFaults == 0, "BDA fault record has data without publication");
checkSrtGuard();
if (!reportOnly) checkSrtGuard();
return;
}
Require(report.state == ShaderRecompiler::BdaAbi::FaultState::Ready && report.otherFaults <= 1, "incomplete or invalid BDA fault record");
@@ -254,7 +453,7 @@ void BdaResources::CheckFault() const {
// APS5_LOOP_GUARD: the shader left a loop that ran past the guard; the dispatch result is kept.
loopGuardTripped.store(true, std::memory_order_relaxed);
std::fprintf(stderr, "[gpu] loop guard: the loop exit at pc 0x%x of shader 0x%llx ran past %u evaluations\n", report.instruction, static_cast<unsigned long long>(report.address), report.bytes);
std::memset(fault->Bytes().data(), 0, fault->Bytes().size());
std::memset(faultBytes().data(), 0, faultBytes().size());
return;
}
if (report.reason == ShaderRecompiler::BdaAbi::FaultReason::ImageTable) {
@@ -321,7 +520,7 @@ void BdaResources::SetSrtGuards(std::vector<SrtGuardFaults> guards) {
void BdaResources::checkSrtGuard() const {
namespace Abi = ShaderRecompiler::BdaAbi;
std::uint32_t guard = 0;
std::memcpy(&guard, fault->Bytes().data() + Abi::SrtGuardWord * sizeof(std::uint32_t), sizeof(guard));
std::memcpy(&guard, faultBytes().data() + Abi::SrtGuardWord * sizeof(std::uint32_t), sizeof(guard));
if (guard == 0) return;
const auto stage = guard >> Abi::SrtGuardStageShift;
const auto record = guard & ((1u << Abi::SrtGuardStageShift) - 1u);
@@ -337,7 +536,7 @@ void BdaResources::checkSrtGuard() const {
void BdaResources::markWrittenPages() const {
namespace Abi = ShaderRecompiler::BdaAbi;
auto* words = reinterpret_cast<std::uint32_t*>(fault->Bytes().data());
auto* words = reinterpret_cast<std::uint32_t*>(faultBytes().data());
Require(words[Abi::WrittenOverflowWord] == 0, "more than " + std::to_string(Abi::WrittenPageSlots) + " chunks of " + std::to_string(Abi::WrittenChunkPages) + " pages stored to through the BDA table in one use are not implemented");
const auto count = words[Abi::WrittenCountWord];
if (count == 0) return;
@@ -399,7 +399,7 @@ BufferPool::Tier& BufferPool::tierFor(std::size_t capacity, VkMemoryPropertyFlag
return !sharedTiers() && capacity < classLimit ? smallTier : largeTier;
}
std::optional<BufferAllocation> BufferPool::Take(std::size_t bytes, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, const char* category) {
std::optional<BufferAllocation> BufferPool::Take(std::size_t bytes, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, const char* category, bool hostPlaced) {
static const bool profile = std::getenv("APS5_PROFILE_DRAW") != nullptr;
const auto capacity = Capacity(bytes);
std::lock_guard lock(mutex);
@@ -415,9 +415,9 @@ std::optional<BufferAllocation> BufferPool::Take(std::size_t bytes, VkBufferUsag
auto& tier = tierFor(capacity, properties);
const auto largest = &tier == &deviceTier && !exactSizes() && bytes <= std::numeric_limits<std::size_t>::max() / 2 ? std::max(capacity, bytes * 2) : capacity;
auto found = tier.free.end();
for (auto size = capacity; size <= largest && found == tier.free.end(); size = NextCapacity(size)) found = tier.free.find({size, usage, properties});
for (auto size = capacity; size <= largest && found == tier.free.end(); size = NextCapacity(size)) found = tier.free.find({size, usage, properties, 0, hostPlaced});
if (found == tier.free.end() || found->second.empty()) {
++tier.misses;
if (!hostPlaced) ++tier.misses;
return std::nullopt;
}
auto& slots = found->second;
@@ -497,7 +497,7 @@ VkDeviceSize BufferPool::ReclaimIdleDevice(VkDeviceSize bytes, std::chrono::stea
for (auto it = deviceTier.free.begin(); it != deviceTier.free.end(); ++it) {
if (it->second.empty()) continue;
const auto& slot = it->second.front();
if (slot.allocation.buffer == VK_NULL_HANDLE || slot.allocation.slab || slot.lastUse > reclaimBefore) continue;
if (slot.allocation.buffer == VK_NULL_HANDLE || slot.allocation.slab || slot.allocation.hostPlaced || slot.lastUse > reclaimBefore) continue;
if (oldest == deviceTier.free.end() || slot.lastUse < oldest->second.front().lastUse) oldest = it;
}
if (oldest == deviceTier.free.end()) {
@@ -586,7 +586,7 @@ void BufferPool::Put(const BufferAllocation& allocation) noexcept {
evicted.push_back(allocation);
} else {
while (tier.slots != 0 && (tier.retainedBytes + allocation.allocationBytes > tier.budget || tier.slots >= maxSlots)) evictOldest(tier, evicted);
tier.free[{allocation.bytes, allocation.usage, allocation.properties}].push_back({allocation, ++clock, {}});
tier.free[{allocation.bytes, allocation.usage, allocation.properties, 0, allocation.hostPlaced}].push_back({allocation, ++clock, {}});
++tier.slots;
tier.retainedBytes += allocation.allocationBytes;
if (allocation.slab) MemoryAccounting::RetainPart(device, allocation.memory, allocation.allocationBytes, true);
@@ -729,7 +729,7 @@ DccKeys ProvedClearKeys(const GuestTextureResource& resource, std::uint64_t gues
// The collect precedes the scan: a write landing between them is stamped above `collected`, so
// the proof it would invalidate is never taken as current.
const auto collected = count == 0 ? 0 : GuestMemory::CollectWrites(resource.dccAddress, count);
if (proof.generation != 0 && collected != 0 && GuestMemory::UnchangedSince(resource.dccAddress, count, proof.generation)) {
if (proof.generation != 0 && collected != 0 && GuestMemory::UnchangedSince(resource.dccAddress, count, proof.generation) && PendingKeyProofHolds(resource, guestBytes, proof)) {
counters.proved.fetch_add(1, std::memory_order_relaxed);
return proof.keys;
}
@@ -748,12 +748,36 @@ DccKeys ProvedClearKeys(const GuestTextureResource& resource, std::uint64_t gues
stable = !Recorder::SnapshotWriteOverlaps(resource.dccAddress, count);
}
}
proof = stable ? DccKeyProof{keys, collected} : DccKeyProof{};
proof = stable ? DccKeyProof{keys, collected} : memoized && collected != 0 ? PendingKeyProof(resource, guestBytes, keys) : DccKeyProof{};
counters.scanned.fetch_add(1, std::memory_order_relaxed);
if (!stable) counters.unstable.fetch_add(1, std::memory_order_relaxed);
return keys;
}
DccKeyProof PendingKeyProof(const GuestTextureResource& resource, std::uint64_t guestBytes, DccKeys keys) {
const auto count = static_cast<std::size_t>(guestBytes / KeyBytes);
if (!KeyFastPath() || resource.dccAddress == 0 || count == 0 || keys == DccKeys::Mixed || keys == DccKeys::Unreadable || !GuestMemory::GpuMutex().HeldByThisThread()) return {};
auto* recorder = Recorder::Active();
if (recorder == nullptr) return {};
const auto info = recorder->DescribePendingWrite(resource.dccAddress, count);
if (!info.has_value() || info->signaled) return {};
const auto note = recorder->NewestWriteNote(resource.dccAddress, count);
if (note == 0) return {};
const auto collected = GuestMemory::CollectWrites(resource.dccAddress, count);
if (collected == 0) return {};
return {keys, collected, note, recorder->Id()};
}
bool PendingKeyProofHolds(const GuestTextureResource& resource, std::uint64_t guestBytes, const DccKeyProof& proof) {
if (proof.pendingNote == 0) return true;
const auto count = static_cast<std::size_t>(guestBytes / KeyBytes);
if (!GuestMemory::GpuMutex().HeldByThisThread()) return false;
auto* recorder = Recorder::Active();
if (recorder == nullptr || recorder->Id() != proof.pendingRecorder || recorder->NewestWriteNote(resource.dccAddress, count) != proof.pendingNote) return false;
const auto info = recorder->DescribePendingWrite(resource.dccAddress, count);
return info.has_value() && !info->signaled;
}
DccKeyProofCounts KeyProofCounts() {
const auto& counters = Proofs();
return {counters.proved.load(std::memory_order_relaxed), counters.scanned.load(std::memory_order_relaxed), counters.unstable.load(std::memory_order_relaxed), counters.rangeProved.load(std::memory_order_relaxed), counters.rangeScanned.load(std::memory_order_relaxed)};
@@ -2,7 +2,9 @@
#include "prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include "prx/libc/include/GuestAllocations.hpp"
#include "prx/libc/include/PrimedSharedMutex.hpp"
#include "prx/libSceAgcDriver/Graphics/include/BufferPool.hpp"
#include "prx/libSceAgcDriver/Graphics/include/FirstSampleCopy.hpp"
#include "prx/libSceAgcDriver/Graphics/include/Recorder.hpp"
#include "prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp"
#include "prx/libSceAgcDriver/Graphics/include/MultisampleTarget.hpp"
@@ -13,6 +15,7 @@
#include "prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp"
#include "prx/libSceAgcDriver/Graphics/include/TextureTiling.hpp"
#include "prx/libSceAgcDriver/Execution/include/Mutex.hpp"
#include "prx/libSceAgcDriver/Graphics/shaders/DepthToStorage_spv.h"
#include "RdnaDecoder/RdnaInstructionDecoder.hpp"
#include "RdnaDecoder/include/RdnaDecoder/RdnaDescriptorFormat.hpp"
#include <algorithm>
@@ -74,6 +77,121 @@ bool singleComponent(VkFormat format, std::uint32_t bytes) {
}
}
std::atomic<bool> depthTransferPasses{std::getenv("APS5_NO_DEPTH_TRANSFER_PASS") == nullptr};
std::atomic<std::uint64_t> depthTransferPassCount{0};
bool depthToStoragePass(const Context& context, VkFormat depthFormat, VkFormat colorFormat) {
if (!context.pushDescriptors || !depthTransferPasses.load(std::memory_order_relaxed)) return false;
return aspectCopyBytes(depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT) == 4 && singleComponent(colorFormat, 4);
}
struct RectPush {
std::array<std::uint32_t, 2> offset;
std::array<std::uint32_t, 2> extent;
};
class DepthToStoragePass {
public:
explicit DepthToStoragePass(const Context& context) : context(context) {
this->context.bufferPool.reset();
try {
pushSet = context.Function<PFN_vkCmdPushDescriptorSetKHR>("vkCmdPushDescriptorSetKHR");
const std::array<VkDescriptorSetLayoutBinding, 2> bindings{{{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, {1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}}};
VkDescriptorSetLayoutCreateInfo setInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO};
setInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
setInfo.bindingCount = static_cast<std::uint32_t>(bindings.size());
setInfo.pBindings = bindings.data();
Check(context.Function<PFN_vkCreateDescriptorSetLayout>("vkCreateDescriptorSetLayout")(context.device, &setInfo, nullptr, &setLayout), "vkCreateDescriptorSetLayout depth to storage");
const VkPushConstantRange rect{VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(RectPush)};
VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
layoutInfo.setLayoutCount = 1;
layoutInfo.pSetLayouts = &setLayout;
layoutInfo.pushConstantRangeCount = 1;
layoutInfo.pPushConstantRanges = &rect;
Check(context.Function<PFN_vkCreatePipelineLayout>("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &layout), "vkCreatePipelineLayout depth to storage");
const auto compute = CreateShaderModule(context, DEPTH_TO_STORAGE_SPV, sizeof(DEPTH_TO_STORAGE_SPV), "vkCreateShaderModule depth to storage");
VkComputePipelineCreateInfo info{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
info.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, VK_SHADER_STAGE_COMPUTE_BIT, compute, "main", nullptr};
info.layout = layout;
VkResult created;
{
auto pipelineCacheLock = context.LockPipelineCacheForUse();
created = context.Function<PFN_vkCreateComputePipelines>("vkCreateComputePipelines")(context.device, context.pipelineCache, 1, &info, nullptr, &pipeline);
}
context.Function<PFN_vkDestroyShaderModule>("vkDestroyShaderModule")(context.device, compute, nullptr);
Check(created, "vkCreateComputePipelines depth to storage");
} catch (...) {
release();
throw;
}
}
~DepthToStoragePass() { release(); }
DepthToStoragePass(const DepthToStoragePass&) = delete;
DepthToStoragePass& operator=(const DepthToStoragePass&) = delete;
VkDevice Device() const { return context.device; }
void Record(VkCommandBuffer commands, VkImageView depthPlane, VkImageView texels, std::span<const VkRect2D> rects) const {
const VkDescriptorImageInfo depthInfo{VK_NULL_HANDLE, depthPlane, VK_IMAGE_LAYOUT_GENERAL};
const VkDescriptorImageInfo texelInfo{VK_NULL_HANDLE, texels, VK_IMAGE_LAYOUT_GENERAL};
const std::array<VkWriteDescriptorSet, 2> writes{imageWrite(0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, depthInfo), imageWrite(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, texelInfo)};
context.Resolved(&DeviceFunctions::cmdBindPipeline, "vkCmdBindPipeline")(commands, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
pushSet(commands, VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, static_cast<std::uint32_t>(writes.size()), writes.data());
const auto pushConstants = context.Resolved(&DeviceFunctions::cmdPushConstants, "vkCmdPushConstants");
const auto dispatch = context.Resolved(&DeviceFunctions::cmdDispatch, "vkCmdDispatch");
for (const auto& rect : rects) {
const RectPush push{{static_cast<std::uint32_t>(rect.offset.x), static_cast<std::uint32_t>(rect.offset.y)}, {rect.extent.width, rect.extent.height}};
pushConstants(commands, layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(push), &push);
dispatch(commands, (rect.extent.width + 7u) / 8u, (rect.extent.height + 7u) / 8u, 1);
}
}
private:
static VkWriteDescriptorSet imageWrite(std::uint32_t binding, VkDescriptorType type, const VkDescriptorImageInfo& info) {
VkWriteDescriptorSet write{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
write.dstBinding = binding;
write.descriptorCount = 1;
write.descriptorType = type;
write.pImageInfo = &info;
return write;
}
void release() noexcept {
context.Function<PFN_vkDestroyPipeline>("vkDestroyPipeline")(context.device, pipeline, nullptr);
context.Function<PFN_vkDestroyPipelineLayout>("vkDestroyPipelineLayout")(context.device, layout, nullptr);
context.Function<PFN_vkDestroyDescriptorSetLayout>("vkDestroyDescriptorSetLayout")(context.device, setLayout, nullptr);
pipeline = VK_NULL_HANDLE;
layout = VK_NULL_HANDLE;
setLayout = VK_NULL_HANDLE;
}
Context context;
PFN_vkCmdPushDescriptorSetKHR pushSet = nullptr;
VkDescriptorSetLayout setLayout = VK_NULL_HANDLE;
VkPipelineLayout layout = VK_NULL_HANDLE;
VkPipeline pipeline = VK_NULL_HANDLE;
};
std::mutex& depthToStoragePassesMutex() {
static std::mutex mutex;
return mutex;
}
std::vector<std::unique_ptr<DepthToStoragePass>>& depthToStoragePasses() {
static auto* list = new std::vector<std::unique_ptr<DepthToStoragePass>>();
return *list;
}
DepthToStoragePass& depthToStoragePassFor(const Context& context) {
std::lock_guard lock(depthToStoragePassesMutex());
auto& list = depthToStoragePasses();
for (const auto& pass : list) {
if (pass->Device() == context.device) return *pass;
}
list.push_back(std::make_unique<DepthToStoragePass>(context));
return *list.back();
}
struct DepthGuard {
VkDevice device;
std::uint64_t address;
@@ -84,7 +202,7 @@ struct DepthGuard {
};
std::shared_mutex& depthGuardMutex() {
static std::shared_mutex mutex;
static PrimedSharedMutex mutex;
return mutex;
}
@@ -100,6 +218,8 @@ std::atomic<bool>& anyDepthGuard() {
struct DepthSamplingState {
std::vector<GuestMemory::UnchangedQuery> initial;
std::optional<float> initialDepth;
std::optional<std::uint8_t> initialStencil;
std::string refusal;
std::optional<std::uint8_t> aliasStencil;
std::optional<MultisampleColorAlias> unprovenStencil;
@@ -152,6 +272,68 @@ std::uint64_t fillNoteAfter(const Recorder& recorder, const GuestMemory::Unchang
return found;
}
bool uniformPlaneTarget(const DepthTarget& target) {
return target.format == VK_FORMAT_D32_SFLOAT_S8_UINT && target.stencilAddress != 0u && target.htileAddress == 0u;
}
template <typename Element>
std::optional<Element> uniformPlaneValue(std::uint64_t address, std::size_t bytes) {
std::array<Element, 16384> chunk{};
std::optional<Element> value;
for (std::size_t offset = 0u; offset < bytes;) {
const auto count = std::min(chunk.size(), (bytes - offset) / sizeof(Element));
const auto elements = std::span(chunk).first(count);
GuestMemory::Read(address + offset, std::as_writable_bytes(elements));
if (!value) value = elements.front();
if (std::ranges::any_of(elements, [&](Element element) { return element != *value; })) return std::nullopt;
offset += count * sizeof(Element);
}
return value;
}
DepthSamplingState prepareUniformPlaneSampling(const Context& context, const DepthTarget& target, DepthSamplingState state) {
const auto refuse = [&](const char* reason) {
state.refusal = reason;
return state;
};
if (target.depthSwizzle != 24u || target.firstSlice != 0u || target.lastSlice != 0u) return refuse("native multisample depth arrays or non-Z_X layout are not implemented");
if ((target.pipeBankXor & ~0xcf00u) != 0u) return refuse("unsupported native multisample depth XOR");
if (target.address == 0u || (target.address & 65535u) != 0u || (target.stencilAddress & 65535u) != 0u) return refuse("native multisample depth base is not aligned");
if (target.htileStencil) return refuse("native multisample stencil import is not implemented");
state.initial = {{target.address, static_cast<std::size_t>(MultisampledDepthBytes_nid_no_patch(target.extent, 4u, target.samples)), 0u}, {target.stencilAddress, static_cast<std::size_t>(MultisampledDepthBytes_nid_no_patch(target.extent, 1u, target.samples)), 0u}};
for (const auto& range : state.initial) {
if (range.address > std::numeric_limits<std::uint64_t>::max() - range.bytes) return refuse("native depth import range overflows");
if (!GuestMemory::Accessible(reinterpret_cast<const void*>(range.address), range.bytes) || !GuestMemory::Watched(range.address, range.bytes)) return refuse("native multisample depth import requires watched accessible guest memory");
}
const auto& depth = state.initial[0];
const auto& stencil = state.initial[1];
if (depth.address + depth.bytes > stencil.address && stencil.address + stencil.bytes > depth.address) return refuse("native depth and stencil initial ranges overlap");
for (std::size_t index = 0u; index < state.initial.size(); ++index) {
const auto alias = MultisampleColorTargetOver(state.initial[index].address, state.initial[index].bytes);
if (!alias) continue;
reportAlias(*alias, state.initial[index], index == 1u ? "stencil plane" : "depth");
return refuse(index == 1u ? stencilAliasRefusal : depthAliasRefusal);
}
for (auto& range : state.initial) {
if (auto* recorder = RecorderFor(context)) recorder->SyncThrough(range.address, range.bytes);
StorageTexture::FlushPending(range.address, range.bytes);
GuestMemory::FlushGpuWrites(range.address, range.bytes);
if (!GuestMemory::Accessible(reinterpret_cast<const void*>(range.address), range.bytes) || !GuestMemory::Watched(range.address, range.bytes)) return refuse("native multisample depth import requires watched accessible guest memory");
range.generation = GuestMemory::CollectWritesUncached(range.address, range.bytes);
if (range.generation == 0u) return refuse("native multisample depth import requires tracked generations");
}
const auto depthWord = uniformPlaneValue<std::uint32_t>(depth.address, depth.bytes);
const auto depthValue = depthWord ? std::bit_cast<float>(*depthWord) : 0.0f;
if (!depthWord || !(depthValue >= 0.0f && depthValue <= 1.0f)) return refuse("native multisample depth plane without HTILE does not hold one depth value in [0, 1]");
const auto stencilByte = uniformPlaneValue<std::uint8_t>(stencil.address, stencil.bytes);
if (!stencilByte) return refuse("native multisample stencil plane without HTILE does not hold one stencil value");
for (const auto& range : state.initial) GuestMemory::CollectWritesUncached(range.address, range.bytes);
if (!GuestMemory::UnchangedSinceAll(state.initial)) return refuse("guest writes raced native multisample depth import");
state.initialDepth = depthValue;
state.initialStencil = *stencilByte;
return state;
}
DepthSamplingState prepareDepthSampling(const Context& context, const DepthTarget& target) {
DepthSamplingState state;
const auto refuse = [&](const char* reason) {
@@ -159,6 +341,7 @@ DepthSamplingState prepareDepthSampling(const Context& context, const DepthTarge
return state;
};
if (target.samples != 2u && target.samples != 4u && target.samples != 8u) return refuse("unsupported native depth sample count");
if (uniformPlaneTarget(target)) return prepareUniformPlaneSampling(context, target, std::move(state));
const bool stencil = target.format == VK_FORMAT_D32_SFLOAT_S8_UINT;
const bool stencilPlane = stencil && !target.htileStencil && target.htileDepthOnly;
if (target.format != VK_FORMAT_D16_UNORM && target.format != VK_FORMAT_D32_SFLOAT && !stencil) return refuse("native multisample stencil or depth format import is not implemented");
@@ -337,6 +520,10 @@ std::optional<DepthPlaneOverwrite> decodeOverwrite(const StorageImageClear& clea
return overwrite;
}
class DepthSurface;
std::pair<std::uint64_t, std::uint64_t> staleStencilRange(const DepthSurface& surface);
void noteStalePlane(std::uint64_t begin, std::uint64_t end);
class DepthSurface {
public:
DepthSurface(const Context& context, const DepthTarget& target, DepthSamplingState sampling = {}) : context(context), target(target), hostFormat(HostDepthFormat(context, target.format)), sampling(std::move(sampling)) {
@@ -410,7 +597,7 @@ public:
toGeneral.subresourceRange = viewInfo.subresourceRange;
const auto barrier = context.Resolved(&DeviceFunctions::cmdPipelineBarrier, "vkCmdPipelineBarrier");
barrier(commands, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &toGeneral);
const VkClearDepthStencilValue clear{target.clearDepth, this->sampling.aliasStencil.value_or(target.clearStencil)};
const VkClearDepthStencilValue clear{this->sampling.initialDepth.value_or(target.clearDepth), this->sampling.initialStencil.value_or(this->sampling.aliasStencil.value_or(target.clearStencil))};
context.Function<PFN_vkCmdClearDepthStencilImage>("vkCmdClearDepthStencilImage")(commands, image, VK_IMAGE_LAYOUT_GENERAL, &clear, 1, &toGeneral.subresourceRange);
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
if (batch) batch->SubmitAndWait();
@@ -449,8 +636,9 @@ public:
if (!alias || (index == 2u && sampling.unprovenStencil && stencilClearGeneration == 0u)) continue;
const auto value = index == 2u && separatePlane ? aliasedStencil(*alias, range, target.samples) : std::nullopt;
const bool kept = value.has_value() && (stencilClearGeneration != 0u ? *value == *stencilClearValue : value == sampling.aliasStencil);
if (!kept) reportAlias(*alias, range, index == 2u ? "stencil plane" : index == 1u ? "HTILE" : "depth");
Require(kept, index == 2u ? stencilAliasRefusal : depthAliasRefusal);
const bool stencilRange = index == 2u || (index == 1u && uniformPlaneTarget(target));
if (!kept) reportAlias(*alias, range, stencilRange ? "stencil plane" : index == 1u ? "HTILE" : "depth");
Require(kept, stencilRange ? stencilAliasRefusal : depthAliasRefusal);
planeAliased = true;
}
if (stencilClearGeneration != 0u) {
@@ -507,6 +695,10 @@ public:
const bool identity = stencil ? resource.format == 5u : resource.baseAddress == target.address && resource.format == (target.format == VK_FORMAT_D16_UNORM ? 7u : 22u);
Require(identity && resource.width == target.extent.width && resource.height == target.extent.height && resource.samples == target.samples, "native multisample depth sampled identity or format mismatch");
Require(resource.dimension == TextureDimension::k2DMsaa && resource.tileMode == TextureTileMode::kZ64KBX && resource.depthOrLastArray == 0u && resource.baseArray == 0u && resource.baseLevel == 0u && resource.lastLevel == 0u && resource.mipCount == 1u && resource.allocatedMipCount == 1u && resource.minLod == 0u, "native multisample depth sampled array, mip or layout is not implemented");
if (uniformPlaneTarget(target)) {
Require(resource.pipeBankXor == target.pipeBankXor && resource.dccAddress == 0u && !resource.dccAlphaOnMsb, "native multisample depth sampled metadata or XOR mismatch");
return;
}
const bool htile = resource.dccAddress == target.htileAddress && resource.dccPipeAligned == target.htilePipeAligned;
const bool bare = resource.dccAddress == 0u && !resource.dccPipeAligned;
if (stencil) {
@@ -629,21 +821,48 @@ public:
return texture;
}
std::shared_ptr<Texture> FirstSample(const Texture& source, VkComponentMapping components) {
auto* recorder = RecorderFor(context);
Require(recorder != nullptr, "a native multisampled depth target is sampled only by recorded draws and dispatches");
const bool d16 = target.format == VK_FORMAT_D16_UNORM || target.format == VK_FORMAT_D16_UNORM_S8_UINT;
const auto format = d16 ? VK_FORMAT_R16_UNORM : VK_FORMAT_R32_SFLOAT;
if (firstSample == nullptr) firstSample = std::make_shared<FirstSampleTextures>(context, format, target.extent);
firstSample->copy.Record(*recorder, source.View(), source.Layout());
const std::array<std::uint32_t, 4> key{static_cast<std::uint32_t>(components.r), static_cast<std::uint32_t>(components.g), static_cast<std::uint32_t>(components.b), static_cast<std::uint32_t>(components.a)};
auto& texture = firstSample->textures[key];
if (texture == nullptr) {
texture = std::make_shared<Texture>(context, firstSample->copy.Image(), format, VK_IMAGE_ASPECT_COLOR_BIT, components);
texture->MarkRefreshedPerUse();
}
return {firstSample, texture.get()};
}
void ForgetClear(VkImageAspectFlags aspects) {
pendingClear &= ~aspects;
if ((aspects & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) depthFill.reset();
if ((aspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) stencilFill.reset();
}
void MarkStencilStale() {
if (!StencilMirrorable()) return;
stencilStale = true;
const auto [begin, end] = staleStencilRange(*this);
noteStalePlane(begin, end);
}
void NoteHtileClear(VkImageAspectFlags aspects) {
ForgetClear(aspects);
pendingClear |= aspects;
if ((aspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0u) MarkStencilStale();
}
void NotePlaneFill(VkImageAspectFlagBits aspect, float depth, std::uint8_t stencil) {
pendingClear |= aspect;
if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT) depthFill = depth;
else stencilFill = stencil;
else {
stencilFill = stencil;
MarkStencilStale();
}
}
void CopyAspectFrom(const DepthSurface& source, VkImageAspectFlagBits aspect) {
@@ -861,6 +1080,7 @@ public:
auto& plane = stencil ? stencilPlane : depthPlane;
const auto source = std::const_pointer_cast<StorageTexture>(candidate.shared_from_this());
copyPlane(plane, source, stencil, false);
ForgetClear(stencil ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT);
written = ++depthWrites;
NoteHostWrite();
return true;
@@ -1214,11 +1434,18 @@ private:
bool filled = false;
};
std::map<std::array<std::uint32_t, 13>, std::shared_ptr<Texture>> textures;
struct FirstSampleTextures {
FirstSampleTextures(const Context& context, VkFormat format, VkExtent2D extent) : copy(context, format, extent) {}
FirstSampleCopy copy;
std::map<std::array<std::uint32_t, 4>, std::shared_ptr<Texture>> textures;
};
std::shared_ptr<FirstSampleTextures> firstSample;
PlaneStorage depthPlane;
PlaneStorage stencilPlane;
std::uint64_t depthMemory = 0;
std::uint64_t stencilMemory = 0;
StencilCopy stencilCopy;
VkImageView transferView = VK_NULL_HANDLE;
void createSampleShadow() {
VkImage image = VK_NULL_HANDLE;
@@ -1407,7 +1634,8 @@ private:
const auto bytes = static_cast<std::size_t>(target.extent.width) * target.extent.height * texelBytes;
const auto aspect = stencil ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
const bool direct = !stencil && DirectDepthCopy(context, hostFormat, aspect, storage->ImageFormat());
if (!direct && plane.staging == nullptr) plane.staging = std::make_unique<DeviceBuffer>(context, bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
const bool passes = toStorage && !stencil && target.samples == 1 && depthToStoragePass(context, hostFormat, storage->ImageFormat());
if (!direct && !passes && plane.staging == nullptr) plane.staging = std::make_unique<DeviceBuffer>(context, bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
const auto commands = recorder != nullptr ? recorder->Commands() : batch->Handle();
if (recorder != nullptr) recorder->Keep(storage);
const std::uint32_t timing = recorder != nullptr ? recorder->BeginGpuTiming(Recorder::CommandClass::Copy) : 0u;
@@ -1428,6 +1656,22 @@ private:
moved += static_cast<std::size_t>(rect.extent.width) * rect.extent.height * texelBytes;
}
}
if (passes) {
const std::vector<VkRect2D> whole{{{0, 0}, target.extent}};
const auto& areas = rects != nullptr ? *rects : whole;
const auto texels = storage->AtomicView(0, storage->Descriptor().dimension == TextureDimension::k2DArray);
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT);
depthToStoragePassFor(context).Record(commands, depthTransferView(), texels, areas);
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT);
depthTransferPassCount.fetch_add(1, std::memory_order_relaxed);
if (batch) {
batch->SubmitAndWait();
return;
}
Recorder::CountBarriers(Recorder::CommandClass::Copy, 2);
recorder->EndGpuTiming(timing, moved);
return;
}
auto colorRegions = planeRegions;
for (auto& region : colorRegions) region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
const auto count = static_cast<std::uint32_t>(planeRegions.size());
@@ -1465,6 +1709,17 @@ private:
recorder->EndGpuTiming(timing, moved);
}
VkImageView depthTransferView() {
if (transferView != VK_NULL_HANDLE) return transferView;
VkImageViewCreateInfo info{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
info.image = image;
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = hostFormat;
info.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
Check(context.Function<PFN_vkCreateImageView>("vkCreateImageView")(context.device, &info, nullptr, &transferView), "vkCreateImageView depth to storage");
return transferView;
}
void release() noexcept {
depthPlane = {};
stencilPlane = {};
@@ -1472,6 +1727,8 @@ private:
mirrorPlane = {};
stencilMirror = {};
textures.clear();
if (transferView) context.Function<PFN_vkDestroyImageView>("vkDestroyImageView")(context.device, transferView, nullptr);
transferView = VK_NULL_HANDLE;
if (view) context.Function<PFN_vkDestroyImageView>("vkDestroyImageView")(context.device, view, nullptr);
if (owned != nullptr) owned.reset();
else {
@@ -2436,6 +2693,10 @@ float HostDepthBiasConstant(const Context& context, VkFormat format, float const
}
VkImageView DepthSurfaceView(const Context& context, const DepthTarget& target, bool depthWritten, bool stencilTested) {
return DepthSurfaceViewWithStencilWriteIntent(context, target, depthWritten, stencilTested, true);
}
VkImageView DepthSurfaceViewWithStencilWriteIntent(const Context& context, const DepthTarget& target, bool depthWritten, bool stencilTested, bool stencilWritten) {
const auto planeBytes = [&](std::uint32_t bytesPerTexel) { return target.samples == 1u ? DepthSliceBytes(target.extent, bytesPerTexel) : MultisampledDepthBytes_nid_no_patch(target.extent, bytesPerTexel, target.samples); };
ClaimMultisampleTargetMemory(target.address, planeBytes(target.format == VK_FORMAT_D16_UNORM || target.format == VK_FORMAT_D16_UNORM_S8_UINT ? 2u : 4u));
if (target.stencilAddress != 0u) ClaimMultisampleTargetMemory(target.stencilAddress, planeBytes(1u));
@@ -2486,6 +2747,8 @@ VkImageView DepthSurfaceView(const Context& context, const DepthTarget& target,
const bool inherits = owner != depthOwners().end() && owner->second.surface->active->load(std::memory_order_acquire) && !owner->second.surface->retired;
surface->clearDepth = target.clearDepth;
surface->clearStencil = target.clearStencil;
const auto stencilOwner = stencilOwners().find({context.device, target.stencilAddress});
const bool stencilRebound = stencilOwner == stencilOwners().end() || stencilOwner->second.surface != surface;
takePlanes(*surface, created, htileCleared | (cleared ? VK_IMAGE_ASPECT_DEPTH_BIT : 0u));
if (cleared || htileCleared != 0u) surface->expanded = false;
if (created && !inherits && target.htileAddress == 0) surface->TakeStorage();
@@ -2518,11 +2781,7 @@ VkImageView DepthSurfaceView(const Context& context, const DepthTarget& target,
surface->MarkAllStale(planeBytes);
noteStalePlane(plane, plane + planeBytes);
}
if (surface->StencilMirrorable()) {
surface->stencilStale = true;
const auto [begin, end] = staleStencilRange(*surface);
noteStalePlane(begin, end);
}
if (stencilWritten || created || stencilRebound) surface->MarkStencilStale();
drawnDepth = surface;
return surface->view;
}
@@ -2900,6 +3159,10 @@ void ClearDepthSurfaces(VkDevice device) {
std::erase_if(surfaces(), [&](const auto& surface) { return surface->context.device == device; });
std::erase_if(planeCopies(), [&](const auto& entry) { return std::get<0>(entry.first) == device; });
std::erase_if(layeredStorages(), [&](const auto& entry) { return std::get<0>(entry.first) == device; });
{
std::lock_guard passesLock(depthToStoragePassesMutex());
std::erase_if(depthToStoragePasses(), [&](const auto& pass) { return pass->Device() == device; });
}
std::unique_lock guardLock(depthGuardMutex());
std::erase_if(depthGuards(), [&](const auto& range) { return range.device == device; });
anyDepthGuard().store(!depthGuards().empty(), std::memory_order_release);
@@ -2922,6 +3185,16 @@ thread_local bool depthCopySourceActive = false;
}
std::shared_ptr<Texture> DepthSurfaceFirstSample(const Context& context, std::span<const std::uint32_t> words, const GuestTextureResource& resource, VkComponentMapping components) {
Require(resource.dimension == TextureDimension::k2DMsaa, "reading sample 0 of a depth surface needs a multisampled descriptor");
const auto source = DepthSurfaceTexture(context, words, resource, VkComponentMapping{}, VK_IMAGE_VIEW_TYPE_2D);
Require(source != nullptr, "reading sample 0 of a multisampled depth surface whose depth plane is not at the descriptor's address is not implemented");
std::lock_guard lock(surfacesMutex());
auto* found = planeSurface(context.device, resource.baseAddress);
Require(found != nullptr && found->target.address == resource.baseAddress, "reading sample 0 of a multisampled depth surface whose depth plane is not at the descriptor's address is not implemented");
return found->FirstSample(*source, components);
}
std::shared_ptr<Texture> DepthSurfaceTexture(const Context& context, std::span<const std::uint32_t> words, const GuestTextureResource& resource, VkComponentMapping components, VkImageViewType multisampleViewType) {
const auto held = [&](const auto& surface) {
return surface->active->load(std::memory_order_acquire) && surface->context.device == context.device && !surface->retired && (surface->target.address == resource.baseAddress || (surface->target.stencilAddress != 0 && surface->target.stencilAddress == resource.baseAddress));
@@ -2956,7 +3229,9 @@ std::shared_ptr<Texture> DepthSurfaceTexture(const Context& context, std::span<c
Recorder::CountBarriers(Recorder::CommandClass::Draw, 1);
return found->Sampled(words, resource, components, found == drawnDepth, multisampleViewType, depthCopySourceActive);
}
if (resource.width != base.extent.width || resource.height != base.extent.height || resource.baseLevel != 0) return nullptr;
const bool exact = resource.width == base.extent.width && resource.height == base.extent.height;
const bool cropped = !exact && base.gcn && !stencil && found->hostFormat == base.format && (resource.gcnPitch == 0 || resource.gcnPitch == base.extent.width) && resource.width <= base.extent.width && resource.height <= base.extent.height && resource.baseArray == 0 && resource.lastLevel == 0 && resource.dimension == TextureDimension::k2D;
if ((!exact && !cropped) || resource.baseLevel != 0) return nullptr;
const bool d16 = base.format == VK_FORMAT_D16_UNORM || base.format == VK_FORMAT_D16_UNORM_S8_UINT;
const auto format = ResolveTextureFormat(resource.format);
const bool depthBits = !stencil && words.size() >= 4 && ShaderRecompiler::DepthBitsTextureWidth(words[1], words[3]) == (d16 ? 16u : 32u);
@@ -2964,9 +3239,9 @@ std::shared_ptr<Texture> DepthSurfaceTexture(const Context& context, std::span<c
if (!stencil && format != (d16 ? VK_FORMAT_R16_UNORM : VK_FORMAT_R32_SFLOAT) && !depthBits && !integer) return nullptr;
const bool cube = resource.dimension == TextureDimension::kCube;
const bool layered = cube || (resource.dimension == TextureDimension::k2DArray && resource.depthOrLastArray != 0);
const bool sampled = stencil || (!layered && !integer);
const bool sampled = !cropped && (stencil || (!layered && !integer));
const auto copyFormat = integer ? VK_FORMAT_R16_UINT : d16 ? VK_FORMAT_R16_UNORM : VK_FORMAT_R32_SFLOAT;
const bool planes = (format == copyFormat || depthBits) && resource.width == base.extent.width && resource.height == base.extent.height && resource.baseLevel == 0 && resource.lastLevel == 0 && !(resource.baseArray != 0 && (cube || !layered || resource.baseArray > resource.depthOrLastArray)) && !(cube && resource.depthOrLastArray != 0 && (resource.depthOrLastArray + 1u) % 6u != 0u) && (resource.dimension == TextureDimension::k2D || resource.dimension == TextureDimension::k2DArray || cube);
const bool planes = (format == copyFormat || depthBits) && resource.lastLevel == 0 && !(resource.baseArray != 0 && (cube || !layered || resource.baseArray > resource.depthOrLastArray)) && !(cube && resource.depthOrLastArray != 0 && (resource.depthOrLastArray + 1u) % 6u != 0u) && (resource.dimension == TextureDimension::k2D || resource.dimension == TextureDimension::k2DArray || cube);
if (!(sampled ? found->SampledAccepts(words, resource) : planes) && (found->OverwrittenInMemory() || found->OverwrittenOnGpu())) {
retireStoringStale(*found);
return nullptr;
@@ -2992,10 +3267,11 @@ std::shared_ptr<Texture> DepthSurfaceTexture(const Context& context, std::span<c
else slices.push_back({slice->image, slice == drawnDepth ? 0u : slice->written});
}
const auto imageFormat = integer ? VK_FORMAT_R16_UINT : d16 ? VK_FORMAT_D16_UNORM : VK_FORMAT_D32_SFLOAT;
const VkExtent2D extent{resource.width, resource.height};
auto& copies = planeCopies();
const std::tuple<VkDevice, std::uint64_t, std::uint32_t, std::uint32_t, VkFormat> copyKey{context.device, base.address, base.extent.width, base.extent.height, imageFormat};
const std::tuple<VkDevice, std::uint64_t, std::uint32_t, std::uint32_t, VkFormat> copyKey{context.device, base.address, extent.width, extent.height, imageFormat};
auto& copy = copies[copyKey];
if (copy == nullptr || copy->layers < layers) copy = std::make_unique<DepthPlaneCopy>(context, base.extent, imageFormat, layers);
if (copy == nullptr || copy->layers < layers) copy = std::make_unique<DepthPlaneCopy>(context, extent, imageFormat, layers);
copy->lastUse = ++planeCopyClock();
copy->lastPresent = Recorder::Presents();
auto texture = copy->Refresh(slices, resource, components, cube || resource.dimension == TextureDimension::k2DArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, layered && !cube ? resource.baseArray : 0u);
@@ -3293,4 +3569,12 @@ void SetDirectDepthCopy(bool enabled) {
directDepthCopy.store(enabled && std::getenv("APS5_NO_DIRECT_DEPTH_COPY") == nullptr, std::memory_order_relaxed);
}
void SetDepthTransferPasses(bool enabled) {
depthTransferPasses.store(enabled && std::getenv("APS5_NO_DEPTH_TRANSFER_PASS") == nullptr, std::memory_order_relaxed);
}
std::uint64_t DepthTransferPassCount() {
return depthTransferPassCount.load(std::memory_order_relaxed);
}
}
@@ -388,8 +388,15 @@ GuestTextureResource ArraySurfaceForTarget(const ColorTarget& color) {
namespace {
bool writesStencilTarget(const State& state) {
const auto keeps = [](const VkStencilOpState& face) {
return face.writeMask == 0u || (face.failOp == VK_STENCIL_OP_KEEP && face.passOp == VK_STENCIL_OP_KEEP && face.depthFailOp == VK_STENCIL_OP_KEEP);
};
return state.stencilTest && (!keeps(state.stencilFront) || !keeps(state.stencilBack));
}
bool writesDepthTarget(const State& state) {
return state.depthWrite || (state.stencilTest && (state.stencilFront.writeMask != 0u || state.stencilBack.writeMask != 0u));
return state.depthWrite || writesStencilTarget(state);
}
std::size_t colorKeyCount(const ColorTarget& color, std::size_t bytes) {
@@ -1092,7 +1099,7 @@ std::uint32_t CachedFragmentOutputs(const Context& context, std::span<const Comp
}
std::uint32_t outputs = 0;
try {
for (const auto location : ValidateShaders(shaders, state, context.subgroup, context.fragmentShaderBarycentric, context.descriptorIndexing, context.imageInt64Atomics, context.geometryShader, context.sampleRateShading, context.bufferInt64Atomics, context.shaderClipDistance, context.shaderCullDistance, context.viewportIndexLayer, context.runtimeDescriptorArray, context.demoteToHelperInvocation, context.shaderTerminateInvocation, context.meshShader)) {
for (const auto location : ValidateShaders(shaders, state, context.subgroup, context.fragmentShaderBarycentric, context.descriptorIndexing, context.imageInt64Atomics, context.geometryShader, context.sampleRateShading, context.bufferInt64Atomics, context.shaderClipDistance, context.shaderCullDistance, context.viewportIndexLayer, context.runtimeDescriptorArray, context.demoteToHelperInvocation, context.shaderTerminateInvocation, context.meshShader, context.shaderResourceMinLod)) {
Require(location < 32, "fragment output location exceeds the output mask");
outputs |= 1u << location;
}
@@ -1466,7 +1473,7 @@ std::shared_ptr<Buffer> zeroVertexBuffer(const Context& context, std::size_t byt
// Draw's validation, index and vertex phases. With `recipe` the fragment outputs, the pipeline
// stages and the vertex input layout are the recipe's (derived from the same compiled stages)
// instead of computed.
DrawInputs prepareDrawInputs(const Context& context, const State& state, const Pm4::DrawParameters& draw, std::span<const CompiledShader> shaders, DrawOutcome& outcome, DrawTimer& timer, const DrawRecipe* recipe) {
DrawInputs prepareDrawInputs(const Context& context, const State& state, const Pm4::DrawParameters& draw, std::span<const CompiledShader> shaders, DrawOutcome& outcome, DrawTimer& timer, PerformanceTimer& timing, const DrawRecipe* recipe) {
DrawInputs inputs;
APS5_LOG_OUT_DEBUG("Draw indices=%u instances=%u indexSize=%u flags=%u indexAddress=0x%llx", draw.indexCount, draw.instanceCount, draw.indexSize, draw.flags, static_cast<unsigned long long>(draw.indexAddress));
APS5_LOG_OUT_DEBUG("State colorTarget=%u render=%ux%u colorAddress=0x%llx colorBytes=%llu colorExtent=%ux%u", state.hasColorTarget ? 1u : 0u, state.renderExtent.width, state.renderExtent.height, static_cast<unsigned long long>(state.color.address), static_cast<unsigned long long>(state.color.bytes), state.color.extent.width, state.color.extent.height);
@@ -1547,6 +1554,7 @@ DrawInputs prepareDrawInputs(const Context& context, const State& state, const P
ValidateDepthBounds(context, state);
ValidateSampleMask(context, state, shaders);
timer.phase(PhaseValidate);
timing.Mark("validate");
inputs.maxIndex = draw.indexed ? 0u : draw.firstVertex + draw.indexCount - 1u;
if (state.quadList || StripPatches(state, shaders)) {
Require(!draw.indirect, state.quadList ? "indirect quad-list draw is unsupported" : "an indirect triangle strip through emulated barycentric patches is unsupported");
@@ -1645,7 +1653,7 @@ DrawInputs prepareDrawInputs(const Context& context, const State& state, const P
const bool restartLeft = draw.indirect.has_value();
auto highest = HighestDrawIndex(kept, draw.indexSize, restartLeft);
constexpr std::uint32_t ZeroFetchSlack = 0x10000u;
if (const auto zeroFrom = highest ? ZeroFetchVertex(shaders.front().program->vertexAttributes) : std::nullopt) {
if (const auto zeroFrom = highest && !shaders.front().program->vertexAttributes.empty() ? ZeroFetchVertex(shaders.front().program->vertexAttributes) : std::nullopt) {
const auto limit = *zeroFrom > draw.firstVertex ? *zeroFrom - draw.firstVertex : 0u;
if (*highest >= limit && *highest - limit >= ZeroFetchSlack) highest = ClampDrawIndices(kept, draw.indexSize, restartLeft, limit);
}
@@ -1685,7 +1693,7 @@ DrawInputs prepareDrawInputs(const Context& context, const State& state, const P
return inputs;
}
constexpr std::uint32_t ZeroFetchSlack = 0x10000u;
if (const auto zeroFrom = state.stages.mesh ? std::nullopt : ZeroFetchVertex(shaders.front().program->vertexAttributes)) {
if (const auto zeroFrom = state.stages.mesh || shaders.front().program->vertexAttributes.empty() ? std::nullopt : ZeroFetchVertex(shaders.front().program->vertexAttributes)) {
const auto limit = *zeroFrom > draw.firstVertex ? *zeroFrom - draw.firstVertex : 0u;
if (*highest >= limit && *highest - limit >= ZeroFetchSlack) {
GuestMemory::FlushGpuWrites(draw.indexAddress, static_cast<std::size_t>(indexBytes));
@@ -1719,6 +1727,7 @@ DrawInputs prepareDrawInputs(const Context& context, const State& state, const P
}
}
APS5_LOG_CHARS_OUT_DEBUG("Index validation OK");
timing.Mark("index_upload");
const auto& attributes = shaders.front().program->vertexAttributes;
// Validates the vertex descriptors; the layout also keys and builds the pipeline.
if (recipe != nullptr) {
@@ -1822,6 +1831,7 @@ DrawInputs prepareDrawInputs(const Context& context, const State& state, const P
inputs.vertexOffsets[i] = rangeOffsets[plan.copyOf[j]] + plan.offsets[j];
}
timer.phase(PhaseVertex);
timing.Mark("vertex_upload");
return inputs;
}
@@ -2889,6 +2899,10 @@ void rememberShape(const Context& context, std::uint64_t shape, std::span<const
choices.insert(choices.begin(), std::move(choice));
}
bool storesIntoResident(const ShaderResources& resources, const StorageTexture& resident) {
return std::ranges::any_of(resources.StorageImages(), [&](const std::pair<VkImage, bool>& image) { return image.first == resident.Image() && image.second; });
}
bool prepareDraw(const Context& context, const State& state, const Pm4::DrawParameters& draw, std::span<const CompiledShader> shaders, std::span<const GuestMemorySnapshot> snapshots, PreparedDraw& prepared) {
auto*& recipeOut = prepared.recipeOut;
auto& stencilReferences = prepared.stencilReferences;
@@ -2935,12 +2949,10 @@ bool prepareDraw(const Context& context, const State& state, const Pm4::DrawPara
auto& ownWaitedMs = prepared.ownWaitedMs;
const auto report = [&](const char* suffix) { reportDrawEnd(state, timer, built, outcome, waitedBefore, ownWaitedMs, suffix); };
auto& inputs = prepared.inputs;
inputs = prepareDrawInputs(context, state, draw, shaders, outcome, timer, nullptr);
inputs = prepareDrawInputs(context, state, draw, shaders, outcome, timer, timing, nullptr);
if (inputs.nothing) return false;
const auto* args = prepared.args = draw.indirect ? &*draw.indirect : nullptr;
const auto indexBytes = inputs.indexBytes;
timing.Mark("validate");
timing.Mark("index_upload");
const int dumpLimit = prepared.dumpLimit = DumpTargetLimit();
auto& targets = prepared.targets;
targets.resize(state.colors.size());
@@ -3065,7 +3077,7 @@ bool prepareDraw(const Context& context, const State& state, const Pm4::DrawPara
targetViews.push_back(binding.target->View());
}
if (state.depth) {
targetViews.push_back(DepthSurfaceView(context, *state.depth, state.depthWrite, state.stencilTest));
targetViews.push_back(DepthSurfaceViewWithStencilWriteIntent(context, *state.depth, state.depthWrite, state.stencilTest, writesStencilTarget(state)));
if (writesDepthTarget(state)) NoteDepthSurfaceWrite(context, *state.depth);
}
timer.phase(PhasePrepare);
@@ -3075,6 +3087,13 @@ bool prepareDraw(const Context& context, const State& state, const Pm4::DrawPara
auto& resolved = prepared.resolved;
resolved = resolveDrawResources(context, state, draw, shaders, snapshots, indexBytes, recordable, outcome, timer);
auto& resources = resolved.resources;
for (std::size_t index = 0; index < targets.size(); ++index) {
auto& binding = targets[index];
if (binding.color.partialWriteMask == 0 || binding.multisampled || binding.resident == nullptr || binding.proxied || storesIntoResident(*resources, *binding.resident)) continue;
const auto& color = binding.color;
binding.resident = refreshResidentTarget(context, state, color, outcome, profile, [&] { return color.arrayLastSlice != 0 ? CachedStorageLayers(context, ArraySurfaceForTarget(color), color.arraySlice, color.layers) : CachedStorageSurface(context, SurfaceForTarget(color)); });
if (binding.resident != nullptr) targetViews[index] = binding.resident->AttachmentView(color.format, color.mip, color.depthSlice, color.layers, color.arraySlice);
}
if (!stencilReferences.empty() && resources->ChecksFaults()) recordable = false;
if (!stencilReferences.empty()) {
const auto readImages = resources->StorageImages();
@@ -3224,8 +3243,7 @@ bool prepareDraw(const Context& context, const State& state, const Pm4::DrawPara
for (const auto& binding : targets) {
if (binding.color.partialWriteMask == 0 || binding.multisampled) continue;
Require(lean && binding.resident != nullptr && !binding.proxied, "a partial write of a packed color target is merged into its resident image by a recorded draw only");
const auto images = resources->StorageImages();
Require(std::ranges::any_of(images, [&](const std::pair<VkImage, bool>& image) { return image.first == binding.resident->Image() && image.second; }), "the partial write of a packed color target does not store into the target's resident image");
Require(storesIntoResident(*resources, *binding.resident), "the partial write of a packed color target does not store into the target's resident image");
}
if (!lean && !resolved.moved.empty()) {
resolved.resources = std::make_shared<ShaderResources>(context, shaders, state.color, static_cast<std::uint32_t>(state.colors.size()), draw.indexAddress, static_cast<std::size_t>(indexBytes), snapshots);
@@ -3805,7 +3823,7 @@ DrawRecipeOutcome DrawWithRecipe(const Context& context, const State& state, con
if (recipe.hasDepth != state.depth.has_value()) return miss(DrawRecipeMiss::TargetGone);
const std::size_t expectedViews = state.colors.size() + (recipe.hasDepth ? 1u : 0u);
Require(recipe.targets.size() == state.colors.size() && recipe.targetViews.size() == expectedViews, "draw recipe targets do not match the state");
auto inputs = prepareDrawInputs(context, state, draw, shaders, outcome, timer, &recipe);
auto inputs = prepareDrawInputs(context, state, draw, shaders, outcome, timer, timing, &recipe);
if (inputs.nothing) {
result.recorded = true;
return result;
@@ -3834,7 +3852,7 @@ DrawRecipeOutcome DrawWithRecipe(const Context& context, const State& state, con
}
if (recipe.hasDepth) {
timer.phase(PhaseSetup);
const auto depthView = DepthSurfaceView(context, *state.depth, state.depthWrite, state.stencilTest);
const auto depthView = DepthSurfaceViewWithStencilWriteIntent(context, *state.depth, state.depthWrite, state.stencilTest, writesStencilTarget(state));
if (writesDepthTarget(state)) NoteDepthSurfaceWrite(context, *state.depth);
timer.phase(PhaseReadTarget);
if (recipe.targetViews.back() != depthView) return miss(DrawRecipeMiss::TargetGone);
@@ -32,8 +32,20 @@ struct udmabuf_create {
std::uint64_t offset;
std::uint64_t size;
};
struct udmabuf_create_item {
std::uint32_t memfd;
std::uint32_t pad;
std::uint64_t offset;
std::uint64_t size;
};
struct udmabuf_create_list {
std::uint32_t flags;
std::uint32_t count;
udmabuf_create_item list[];
};
constexpr std::uint32_t UDMABUF_FLAGS_CLOEXEC = 0x01;
constexpr unsigned long UDMABUF_CREATE = 0;
constexpr unsigned long UDMABUF_CREATE_LIST = 0;
#else
#include <linux/udmabuf.h>
#endif
@@ -1499,7 +1511,7 @@ ImportPages importPages(std::uint64_t base, std::uint64_t bytes, bool opening =
}
const auto protection = info.Protect & 0xffu;
const bool pageWritable = (info.Type == MEM_PRIVATE || info.Type == MEM_IMAGE) && writableProtection(protection);
const bool pageReadOnly = info.Type != MEM_MAPPED && (protection == PAGE_READONLY || protection == PAGE_EXECUTE_READ);
const bool pageReadOnly = (info.Type != MEM_MAPPED || (info.AllocationProtect & 0xffu) == PAGE_READONLY) && (protection == PAGE_READONLY || protection == PAGE_EXECUTE_READ);
if (!pageReadOnly) pages.readOnly = false;
if (info.Type != MEM_MAPPED) pages.shared = false;
if (info.Type != MEM_MAPPED && !pageWritable && !pageReadOnly && pages.refused.BaseAddress == nullptr) pages.refused = info;
@@ -1907,6 +1919,12 @@ std::optional<std::uint32_t> hostHeapIndex(const VkPhysicalDeviceMemoryPropertie
for (std::uint32_t index = 0; index < memory.memoryHeapCount; ++index) {
if ((memory.memoryHeaps[index].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) == 0 && (!heap || memory.memoryHeaps[index].size > memory.memoryHeaps[*heap].size)) heap = index;
}
if (heap) return heap;
constexpr VkMemoryPropertyFlags shared = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
for (std::uint32_t index = 0; index < std::min<std::uint32_t>(memory.memoryTypeCount, VK_MAX_MEMORY_TYPES); ++index) {
const auto candidate = memory.memoryTypes[index].heapIndex;
if ((memory.memoryTypes[index].propertyFlags & shared) == shared && candidate < memory.memoryHeapCount && (!heap || memory.memoryHeaps[candidate].size > memory.memoryHeaps[*heap].size)) heap = candidate;
}
return heap;
}
@@ -3681,7 +3699,7 @@ bool WaitForLeasesAndImports(std::uintptr_t address, std::size_t bytes) {
const auto end = static_cast<std::uint64_t>(address) + bytes;
auto& imports = Imports();
if (releaseParkedImports(imports, address, end)) retiredImport = true;
const auto lease = GuestAllocations::GuestAllocationsAcquire_nid_postfix();
const auto lease = GuestAllocations::GuestAllocationsAcquireRegistered_nid_postfix();
{
std::lock_guard importsLock(imports.mutex);
for (auto it = imports.imports.begin(); it != imports.imports.end();) {
@@ -3746,7 +3764,7 @@ bool WaitForLeasesAndImports(std::uintptr_t address, std::size_t bytes) {
synced = true;
drained = true;
}
const auto lease = GuestAllocations::GuestAllocationsAcquire_nid_postfix();
const auto lease = GuestAllocations::GuestAllocationsAcquireRegistered_nid_postfix();
{
std::lock_guard importsLock(imports.mutex);
for (auto it = imports.imports.begin(); it != imports.imports.end();) {
@@ -4524,7 +4542,7 @@ bool ImportMappedRanges(const Context& context, const GuestAllocations::Mapped&
bool RegisteredReadableCovers(std::uint64_t address, std::size_t bytes, std::vector<RegisteredPiece>* pieces) {
if (pieces != nullptr) pieces->clear();
if (bytes == 0 || bytes > std::numeric_limits<std::uint64_t>::max() - address) return false;
const auto lease = GuestAllocations::GuestAllocationsAcquire_nid_postfix();
const auto lease = GuestAllocations::GuestAllocationsAcquireRegistered_nid_postfix();
const auto end = address + bytes;
for (auto at = address; at < end;) {
const auto* range = containingRange(lease, at, at + 1);
@@ -4537,7 +4555,7 @@ bool RegisteredReadableCovers(std::uint64_t address, std::size_t bytes, std::vec
std::uint64_t RegisteredReadableEnd(std::uint64_t address) {
if (address == std::numeric_limits<std::uint64_t>::max()) return 0;
const auto lease = GuestAllocations::GuestAllocationsAcquire_nid_postfix();
const auto lease = GuestAllocations::GuestAllocationsAcquireRegistered_nid_postfix();
const auto* range = containingRange(lease, address, address + 1);
return range != nullptr ? range->address + range->bytes : 0;
}
@@ -5325,8 +5343,13 @@ std::uint64_t gpuCopyLimit() {
return limit;
}
VkBufferUsageFlags gpuCopyUsage(bool addressable) {
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | (addressable ? VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT : 0u);
bool changedCopyBacks(const Context& context) {
static const bool disabled = std::getenv("APS5_NO_CHANGED_COPY_BACK") != nullptr;
return !disabled && context.bufferDeviceAddress;
}
VkBufferUsageFlags gpuCopyUsage(const Context& context, bool addressable) {
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | (addressable || changedCopyBacks(context) ? VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT : 0u);
}
// Device-local staging. A written V# element bound in place makes the shader store into host
@@ -5345,10 +5368,11 @@ VkBufferUsageFlags gpuCopyUsage(bool addressable) {
// (resolveOverlays), and AddressRanges cuts the import's range around it so that its pointers reach
// the shadow as its descriptor does. The
// shadow is per use, not resident: a reused build records its copy-in anew (RecordStagingCopies).
// Accepted trade-off, as for the misaligned copies above: a CPU write into a staged range between
// the copy-in and the copy-back is rolled back by the copy-back (the whole written element range,
// since store extents are not known), for the batch's latency; the staging window keeps the
// exposure to the elements named on the [buffers] staging line and APS5_TRACE_STAGING.
// Accepted trade-off, as for the misaligned copies above: the copy-back stores only the bytes the
// shader changed where the import still holds the copy-in (RecordChangedCopy), but a CPU write
// between the copy-in and the copy-back is rolled back at the unaligned ends of a range, in a region
// that is not 4-byte aligned and without a shadow copy; the staging window keeps the exposure to
// the elements named on the [buffers] staging line and APS5_TRACE_STAGING.
// APS5_NO_WRITTEN_SHADOW=1 and APS5_NO_ATOMIC_STAGING=1 bind those elements in place as before;
// APS5_WRITTEN_SHADOW_MIN_KIB / APS5_WRITTEN_SHADOW_MAX_KIB (16 / 2048, 8192 on a discrete GPU) bound
// the written window: on an integrated GPU a kernel streaming once through a large buffer (the
@@ -5432,7 +5456,11 @@ CopyStats& Copies() {
// region takes the path it would take without staging (Region::unstaged).
std::shared_ptr<Buffer> stagingBuffer(const Context& context, std::size_t bytes, VkBufferUsageFlags usage) {
try {
return std::make_shared<Buffer>(context, bytes, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
if (auto buffer = Buffer::WithinDeviceLocalHeadroom(context, bytes, usage)) return buffer;
static std::atomic<int> reported{0};
if (reported.fetch_add(1, std::memory_order_relaxed) < 4) std::fprintf(stderr, "[buffers] staging shadow of %zu bytes refused: its device-local heap is within an eighth of its budget\n", bytes);
Copies().stagingRefused.fetch_add(1, std::memory_order_relaxed);
return nullptr;
} catch (const std::exception& error) {
static std::atomic<int> reported{0};
if (reported.fetch_add(1, std::memory_order_relaxed) < 4) std::fprintf(stderr, "[buffers] staging shadow of %zu bytes refused: %s\n", bytes, error.what());
@@ -5725,7 +5753,7 @@ void GuestBufferMemory::UploadPrepare(bool addressable) {
const bool misaligned = !bindableInPlace(HostImportOffset(*entry, region.begin), addressable);
if (staged) {
const auto allocateStart = std::chrono::steady_clock::now();
region.buffer = stagingBuffer(context, static_cast<std::size_t>(region.end - region.begin), gpuCopyUsage(addressable));
region.buffer = stagingBuffer(context, static_cast<std::size_t>(region.end - region.begin), gpuCopyUsage(context, addressable));
if (profile) allocateUs.fetch_add(microsecondsSince(allocateStart), std::memory_order_relaxed);
if (region.buffer == nullptr) {
// No shadow to be had: in place when aligned, else the host copy below.
@@ -5737,7 +5765,7 @@ void GuestBufferMemory::UploadPrepare(bool addressable) {
if (!staged) {
if (!gpuCopyEligible(region)) continue;
const auto allocateStart = std::chrono::steady_clock::now();
region.buffer = std::make_shared<Buffer>(context, static_cast<std::size_t>(region.end - region.begin), gpuCopyUsage(addressable), copyBufferProperties(false));
region.buffer = std::make_shared<Buffer>(context, static_cast<std::size_t>(region.end - region.begin), gpuCopyUsage(context, addressable), copyBufferProperties(false));
if (profile) allocateUs.fetch_add(microsecondsSince(allocateStart), std::memory_order_relaxed);
}
region.deviceLocal = staged;
@@ -5957,7 +5985,9 @@ void GuestBufferMemory::UploadFinish(bool addressable, std::optional<std::pair<s
copyOnGpu = true;
region.deviceLocal = staged;
region.copySource = entry->buffer;
region.copySourceBase = entry->base - entry->lead;
const auto start = HostImportBufferStart(*entry);
region.copySourceBase = start.guest;
region.copySourceAddress = start.device;
}
}
if (region.direct != nullptr) {
@@ -6157,12 +6187,12 @@ void GuestBufferMemory::recordGpuCopies(std::span<Region* const> copies, bool ad
if (region->buffer == nullptr) {
// Not made by UploadPrepare (the registry was stale then): made here, under the lock.
const auto allocateStart = std::chrono::steady_clock::now();
if (region->deviceLocal) region->buffer = stagingBuffer(context, static_cast<std::size_t>(bytes), gpuCopyUsage(addressable));
if (region->deviceLocal) region->buffer = stagingBuffer(context, static_cast<std::size_t>(bytes), gpuCopyUsage(context, addressable));
if (region->buffer == nullptr) {
// Or no shadow to be had: a host copy serves the region instead, aligned or not.
region->deviceLocal = false;
region->unstaged = true;
region->buffer = std::make_shared<Buffer>(context, static_cast<std::size_t>(bytes), gpuCopyUsage(addressable), copyBufferProperties(false));
region->buffer = std::make_shared<Buffer>(context, static_cast<std::size_t>(bytes), gpuCopyUsage(context, addressable), copyBufferProperties(false));
}
if (profile) allocateUs.fetch_add(microsecondsSince(allocateStart), std::memory_order_relaxed);
}
@@ -6225,6 +6255,28 @@ void GuestBufferMemory::recordGpuCopies(std::span<Region* const> copies, bool ad
}
}
}
std::vector<Region*> shadowed;
for (auto* region : copies) {
const auto bytes = static_cast<std::size_t>(region->end - region->begin);
if (!changedCopyBacks(context) || region->buffer->DeviceAddress() == 0 || !WritesOverlap(region->begin, bytes)) {
region->shadowCopy = nullptr;
continue;
}
if (region->shadowCopy == nullptr) region->shadowCopy = stagingBuffer(context, bytes, gpuCopyUsage(context, true));
if (region->shadowCopy == nullptr || region->shadowCopy->DeviceAddress() == 0) {
region->shadowCopy = nullptr;
continue;
}
shadowed.push_back(region);
}
if (!shadowed.empty()) {
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
Recorder::CountBarriers(Recorder::CommandClass::StagingIn);
for (auto* region : shadowed) {
CopyBuffer(context, commands, region->buffer->Handle(), 0, region->shadowCopy->Handle(), 0, region->end - region->begin);
recorder->Keep(region->shadowCopy);
}
}
if (stagedAny) reportStaging();
// The copied bytes are visible to the shaders bound to the buffers, which may also store into
// them. Every stage: dispatches and draws share this path, and draws run mesh, task and
@@ -6283,7 +6335,7 @@ void GuestBufferMemory::RecordCopyBacks(Recorder& recorder) {
commands = recorder.Commands(&covered);
timing = recorder.BeginGpuTiming(StagingCopyBackKey);
// The shader's stores into the buffer (whichever stage made them) precede the copy.
constexpr BarrierMask leading{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT};
constexpr BarrierMask leading{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT};
if (!Recorder::ElideCovered(Recorder::CommandClass::StagingOut, leading, covered)) {
RecordMemoryBarrier(context, commands, leading.srcStage, leading.dstStage, leading.srcAccess, leading.dstAccess);
Recorder::CountBarriers(Recorder::CommandClass::StagingOut);
@@ -6292,7 +6344,34 @@ void GuestBufferMemory::RecordCopyBacks(Recorder& recorder) {
}
// Exactly the sub-range the shader may write, in place in the import: what the shader
// would have stored there itself had the range been bindable.
CopyBuffer(context, commands, region.buffer->Handle(), from - region.begin, region.copySource, from - region.copySourceBase, to - from);
auto whole = from;
auto wholeEnd = to;
if (region.shadowCopy != nullptr && region.copySourceAddress != 0 && region.begin % 4u == 0 && region.copySourceBase % 4u == 0) {
const auto alignedFrom = (from + 3u) & ~std::uint64_t{3};
const auto alignedTo = to & ~std::uint64_t{3};
static const bool traceDivergence = std::getenv("APS5_TRACE_COPY_BACK") != nullptr;
std::shared_ptr<Buffer> counter;
if (traceDivergence && alignedFrom < alignedTo) {
counter = std::make_shared<Buffer>(context, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
std::memset(counter->Bytes().data(), 0, 16);
}
if (alignedFrom < alignedTo && recorder.RecordChangedCopy(commands, region.buffer->DeviceAddress() + (alignedFrom - region.begin), region.shadowCopy->DeviceAddress() + (alignedFrom - region.begin), region.copySourceAddress + (alignedFrom - region.copySourceBase), static_cast<std::uint32_t>((alignedTo - alignedFrom) / 4u), counter != nullptr ? counter->DeviceAddress() : 0)) {
if (counter != nullptr) {
recorder.Keep(counter);
recorder.OnComplete([counter, alignedFrom, alignedTo, regionBegin = region.begin, regionEnd = region.end] {
std::uint32_t diverged = 0;
std::memcpy(&diverged, counter->Bytes().data(), sizeof(diverged));
static const bool alwaysCopy = std::getenv("APS5_CHANGED_COPY_ALWAYS") != nullptr;
if (diverged != 0) std::fprintf(stderr, "[copy-back] 0x%llx+0x%llx (region 0x%llx+0x%llx): %u dwords where the shader and the CPU changed the same bytes; %s\n", static_cast<unsigned long long>(alignedFrom), static_cast<unsigned long long>(alignedTo - alignedFrom), static_cast<unsigned long long>(regionBegin), static_cast<unsigned long long>(regionEnd - regionBegin), diverged, alwaysCopy ? "the shader's bytes were stored (APS5_CHANGED_COPY_ALWAYS)" : "the CPU's bytes were kept");
});
}
if (from < alignedFrom) CopyBuffer(context, commands, region.buffer->Handle(), from - region.begin, region.copySource, from - region.copySourceBase, alignedFrom - from);
if (alignedTo < to) CopyBuffer(context, commands, region.buffer->Handle(), alignedTo - region.begin, region.copySource, alignedTo - region.copySourceBase, to - alignedTo);
whole = wholeEnd;
recorder.Keep(region.shadowCopy);
}
}
if (whole < wholeEnd) CopyBuffer(context, commands, region.buffer->Handle(), whole - region.begin, region.copySource, whole - region.copySourceBase, wholeEnd - whole);
copiedBytes += to - from;
recorder.Keep(region.buffer);
if (profile) {
@@ -6312,7 +6391,7 @@ void GuestBufferMemory::RecordCopyBacks(Recorder& recorder) {
// indirect dispatch's arguments) and to the host once the batch completed; the caller's
// pending-write note makes CPU readers wait for that.
constexpr VkAccessFlags copiedAccess = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_HOST_READ_BIT;
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | VK_PIPELINE_STAGE_HOST_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, copiedAccess);
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | VK_PIPELINE_STAGE_HOST_BIT, VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_WRITE_BIT, copiedAccess);
Recorder::CountBarriers(Recorder::CommandClass::StagingOut);
recorder.MarkCovered(copiedAccess);
recorder.EndGpuTiming(timing, copiedBytes);
@@ -6588,10 +6667,12 @@ void GuestBufferMemory::MarkDirectWrites() const {
namespace {
void storeChanged(std::uint64_t address, std::span<const std::byte> current, std::span<const std::byte> original) {
using ChangedStore = void (*)(std::uint64_t, std::span<const std::byte>, std::span<const std::byte>);
void storeChanged(std::uint64_t address, std::span<const std::byte> current, std::span<const std::byte> original, ChangedStore store) {
const auto writable = GuestMemory::DescribeCommitted(address, current.size(), true);
if (writable.whole) {
GuestMemory::WriteChanged(address, current, original);
store(address, current, original);
return;
}
const auto unchanged = [&](std::uint64_t from, std::uint64_t to) {
@@ -6606,7 +6687,7 @@ void storeChanged(std::uint64_t address, std::span<const std::byte> current, std
if (cursor < first) unchanged(cursor, first);
const auto at = static_cast<std::size_t>(first - address);
const auto length = static_cast<std::size_t>(last - first);
GuestMemory::WriteChanged(first, current.subspan(at, length), original.subspan(at, length));
store(first, current.subspan(at, length), original.subspan(at, length));
cursor = last;
}
if (cursor < address + current.size()) unchanged(cursor, address + current.size());
@@ -6676,7 +6757,8 @@ void GuestBufferMemory::WriteBack() {
Require(uploaded && !committed, "guest memory cannot be committed twice or before upload");
const auto merged = mergeWrites(writes);
// The CPU keeps running while the GPU works, so storing whole ranges would roll back its writes to
// bytes the shader never touched. Only runs that differ from the uploaded copy are stored.
// bytes the shader never touched. Only runs that differ from the uploaded copy are stored, and a
// host copy leaves the bytes the CPU changed since its upload as they are.
for (const auto& [begin, end] : merged) {
const auto* found = owner(begin, end);
Require(found != nullptr, "write-back range has no GPU owner");
@@ -6704,7 +6786,7 @@ void GuestBufferMemory::WriteBack() {
if (mirror.resident == nullptr) {
const auto current = mirror.buffer->Bytes().subspan(offset, length);
if (mirror.sparse) storeSparse(mirror, begin, current, reference->second);
else storeChanged(begin, current, reference->second);
else storeChanged(begin, current, reference->second, GuestMemory::WriteChanged);
continue;
}
std::vector<std::byte> current(length);
@@ -6716,7 +6798,7 @@ void GuestBufferMemory::WriteBack() {
}
mirror.resident->Store(begin, current);
if (mirror.sparse) storeSparse(mirror, begin, current, reference->second);
else storeChanged(begin, current, reference->second);
else storeChanged(begin, current, reference->second, GuestMemory::WriteChanged);
continue;
}
const auto current = mirror.buffer->Bytes().subspan(offset, length);
@@ -6752,7 +6834,7 @@ void GuestBufferMemory::WriteBack() {
if (!region.sparse) {
const auto first = static_cast<std::size_t>(begin - region.begin);
const auto length = static_cast<std::size_t>(end - begin);
storeChanged(begin, region.buffer->Bytes().subspan(first, length), std::span<const std::byte>(region.uploaded).subspan(first, length));
storeChanged(begin, region.buffer->Bytes().subspan(first, length), std::span<const std::byte>(region.uploaded).subspan(first, length), GuestMemory::WriteChangedKeepingGuest);
continue;
}
std::size_t packed = 0;
@@ -6761,7 +6843,7 @@ void GuestBufferMemory::WriteBack() {
const auto to = std::min(last, end);
if (from < to) {
const auto length = static_cast<std::size_t>(to - from);
storeChanged(from, region.buffer->Bytes().subspan(static_cast<std::size_t>(from - region.begin), length), std::span<const std::byte>(region.uploaded).subspan(packed + static_cast<std::size_t>(from - first), length));
storeChanged(from, region.buffer->Bytes().subspan(static_cast<std::size_t>(from - region.begin), length), std::span<const std::byte>(region.uploaded).subspan(packed + static_cast<std::size_t>(from - first), length), GuestMemory::WriteChangedKeepingGuest);
}
packed += static_cast<std::size_t>(last - first);
}
@@ -172,6 +172,16 @@ GuestSamplerResource DecodeSamplerResource(std::span<const std::uint32_t> words,
return result;
}
bool HoldsLodAtZero(std::span<const std::uint32_t, 4> words) {
return (words[0] & (1u << 15u)) == 0u && (((words[2] >> 26u) & 3u) == 0u || ((words[1] >> 12u) & 0xfffu) == 0u);
}
std::array<std::uint32_t, 4> PinnedLodSamplerWords(std::span<const std::uint32_t, 4> words, std::uint32_t lod) {
std::array<std::uint32_t, 4> pinned{words[0], (words[1] & ~0xffffffu) | lod | (lod << 12u), words[2], words[3]};
if (((pinned[2] >> 26u) & 3u) == 0u) pinned[2] |= 1u << 26u;
return pinned;
}
std::optional<std::array<std::uint32_t, 4>> SingleLevelSamplerWords(std::span<const std::uint32_t, 4> words, bool singleLevelImage, bool mipmappedImage) {
const auto filters = words[2];
if (((filters >> 29u) & 1u) == 0 || !singleLevelImage || (!isAnisoFilter((filters >> 20u) & 3u) && !isAnisoFilter((filters >> 22u) & 3u))) return std::nullopt;
Loaded 100 of 1068 files, more files were not shown because too many files have changed in this diff. Show more