mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-05 13:20:11 +00:00
Merge main into fix/agc-msaa-d32s8-separate-stencil
Beyond keeping both sides: - CMakeLists.txt:3149-3153: agc_driver_native_depth_buffer_clear joins the branch's set_tests_properties lists for the native depth tests (and the WIN32 list) instead of main's own line that re-lists clears and clear_refusals; the properties are the same. - NativeMultisampleDepth.cpp:1153-1170: main's two completionCandidate && fault == ClearFault::None blocks sit around ArmHtileDepthClear inside the branch's ClearSource::HtileDispatch path, where the branch moved that code; the fill paths make no HTILE clear candidate. - NativeMultisampleDepth.cpp:2556: main's --buffer-clear call passes ClearSource::HtileDispatch, the parameter the branch added to CheckDepthTarget.
This commit is contained in:
commit
071ca5b609
617 files changed
+23335
-1320
No files matched your search
@@ -26,8 +26,21 @@ jobs:
|
||||
state=$RUNNER_TEMP/area-state.json
|
||||
[ -s "$state" ] || echo '{}' > "$state"
|
||||
config=$(gh api "repos/$GITHUB_REPOSITORY/contents/.github/labeler.yml" --jq .sha)
|
||||
gh pr list -R "$GITHUB_REPOSITORY" --base "${{ github.event.repository.default_branch }}" -L 1000 --json number,headRefOid \
|
||||
--jq "map({key: (.number | tostring), value: (.headRefOid + \"-$config\")}) | from_entries" > "$RUNNER_TEMP/area-open.json"
|
||||
gh api graphql --paginate --slurp \
|
||||
-f owner="${GITHUB_REPOSITORY%/*}" -f name="${GITHUB_REPOSITORY#*/}" \
|
||||
-f base="${{ github.event.repository.default_branch }}" -f query='
|
||||
query($owner: String!, $name: String!, $base: String!, $endCursor: String) {
|
||||
repository(owner: $owner, name: $name) {
|
||||
pullRequests(states: OPEN, baseRefName: $base, first: 100, after: $endCursor,
|
||||
orderBy: {field: CREATED_AT, direction: DESC}) {
|
||||
pageInfo { hasNextPage endCursor }
|
||||
nodes { number headRefOid }
|
||||
}
|
||||
}
|
||||
}' | jq -c --arg config "$config" \
|
||||
'[.[].data.repository.pullRequests.nodes[]
|
||||
| {key: (.number | tostring), value: (.headRefOid + "-" + $config)}] | from_entries' \
|
||||
> "$RUNNER_TEMP/area-open.json"
|
||||
jq -r --slurpfile old "$state" 'to_entries[] | select($old[0][.key] != .value) | .key' "$RUNNER_TEMP/area-open.json" | head -n 40 > "$RUNNER_TEMP/area-todo"
|
||||
jq -c --slurpfile open "$RUNNER_TEMP/area-open.json" --rawfile todo "$RUNNER_TEMP/area-todo" \
|
||||
'with_entries(select(.key | in($open[0]))) + ($open[0] | with_entries(select(.key | IN($todo | split("\n")[]))))' "$state" > "$RUNNER_TEMP/area-next.json"
|
||||
|
||||
@@ -24,15 +24,15 @@ jobs:
|
||||
build:
|
||||
name: Build and test (${{ matrix.platform }})
|
||||
strategy:
|
||||
fail-fast: true
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- platform: linux
|
||||
runner: ubuntu-latest
|
||||
timeout: 30
|
||||
timeout: 60
|
||||
- platform: windows
|
||||
runner: windows-latest
|
||||
timeout: 45
|
||||
timeout: 60
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: ${{ matrix.timeout }}
|
||||
defaults:
|
||||
|
||||
@@ -207,6 +207,8 @@ if(BUILD_TESTING)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler ${CMAKE_COMMAND} --shard ${shard}/7)
|
||||
set_tests_properties(${shader_cache_sources_test_name} PROPERTIES TIMEOUT 180)
|
||||
endforeach()
|
||||
add_test(NAME tools_nid_name_audit COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/tests/test_audit_nid_names.py)
|
||||
set_tests_properties(tools_nid_name_audit PROPERTIES TIMEOUT 20)
|
||||
add_test(NAME pr_overlap_encoding COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_encoding.py)
|
||||
add_test(NAME pr_overlap_dependencies COMMAND ${Python3_EXECUTABLE}
|
||||
@@ -222,6 +224,8 @@ if(BUILD_TESTING)
|
||||
set_tests_properties(progress_history_output PROPERTIES TIMEOUT 20)
|
||||
add_test(NAME progress_report COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress.py)
|
||||
add_test(NAME tools_compdb_inventory COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/tests/test_compile_database_inventory.py)
|
||||
set_tests_properties(tools_compdb_inventory PROPERTIES TIMEOUT 20)
|
||||
add_test(NAME progress_encoding COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress_encoding.py)
|
||||
add_test(NAME progress_render_sliver COMMAND ${Python3_EXECUTABLE}
|
||||
@@ -267,6 +271,8 @@ if(BUILD_TESTING)
|
||||
set_tests_properties(preview_pad_timeline PROPERTIES TIMEOUT 20)
|
||||
add_test(NAME conventions_git_errors COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_git.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 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}
|
||||
@@ -282,6 +288,8 @@ if(BUILD_TESTING)
|
||||
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)
|
||||
add_test(NAME tools_pe_inventory COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/tests/test_pe_symbol_inventory.py)
|
||||
set_tests_properties(tools_pe_inventory PROPERTIES TIMEOUT 20)
|
||||
add_test(NAME check_skips COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_skips.py)
|
||||
add_test(NAME sanitizer_report COMMAND ${Python3_EXECUTABLE}
|
||||
@@ -458,6 +466,8 @@ if(BUILD_TESTING)
|
||||
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}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_pr_template.py)
|
||||
add_test(NAME check_compile_preprocessor COMMAND ${Python3_EXECUTABLE}
|
||||
|
||||
@@ -452,10 +452,21 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(guest_kernel_sys_tests PRIVATE libkernel_sys libSceAmpr libkernel libc)
|
||||
configure_windows_unwind(guest_kernel_sys_tests)
|
||||
add_test(NAME guest_kernel_sys COMMAND guest_kernel_sys_tests)
|
||||
set_tests_properties(guest_kernel_sys PROPERTIES TIMEOUT 20)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_kernel_sys PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAmpr>")
|
||||
endif()
|
||||
add_test_executable(guest_kernel_sys_vm_map_timestamp_tests tests/GuestKernelSysVmMapTimestamp.cpp)
|
||||
target_include_directories(guest_kernel_sys_vm_map_timestamp_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_kernel_sys_vm_map_timestamp_tests PRIVATE libkernel_sys libkernel libc)
|
||||
configure_windows_unwind(guest_kernel_sys_vm_map_timestamp_tests)
|
||||
add_test(NAME guest_kernel_sys_vm_map_timestamp COMMAND guest_kernel_sys_vm_map_timestamp_tests)
|
||||
set_tests_properties(guest_kernel_sys_vm_map_timestamp PROPERTIES TIMEOUT 20)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_kernel_sys_vm_map_timestamp PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel_sys>")
|
||||
endif()
|
||||
add_test_executable(guest_kernel_sys_thread_defaults_tests tests/GuestKernelSysThreadDefaults.cpp)
|
||||
target_include_directories(guest_kernel_sys_thread_defaults_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_kernel_sys_thread_defaults_tests PRIVATE libkernel_sys libkernel libc)
|
||||
@@ -743,6 +754,17 @@ if(BUILD_TESTING)
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpCommon>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_xml_value_types_tests tests/GuestXmlValueTypes.cpp)
|
||||
target_include_directories(guest_xml_value_types_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_xml_value_types_tests PRIVATE libSceXml libkernel libc)
|
||||
configure_windows_unwind(guest_xml_value_types_tests)
|
||||
add_test(NAME guest_xml_value_types COMMAND guest_xml_value_types_tests)
|
||||
set_tests_properties(guest_xml_value_types PROPERTIES TIMEOUT 20)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_xml_value_types PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceXml>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_offline_imports_tests tests/GuestOfflineImports.cpp)
|
||||
target_include_directories(guest_offline_imports_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_offline_imports_tests PRIVATE libSceHttp libSceNpEntitlementAccess libSceRudp libSceVideoRecordingP libc)
|
||||
@@ -1037,6 +1059,16 @@ if(BUILD_TESTING)
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel_sys>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_src_utility_tests tests/GuestSrcUtility.cpp)
|
||||
target_include_directories(guest_src_utility_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_src_utility_tests PRIVATE libSceSrcUtl libc)
|
||||
configure_windows_unwind(guest_src_utility_tests)
|
||||
add_test(NAME guest_src_utility COMMAND guest_src_utility_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_src_utility PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceSrcUtl>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_crt_tests tests/GuestCrt.cpp)
|
||||
target_include_directories(guest_crt_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_crt_tests PRIVATE libSceAmpr libc)
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
#include "prx/libCprm/include/InventoryExports.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libCprmUnknown__plus_Eh9ZNYi6zo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Eh9ZNYi6zo", libCprmUnknown__plus_Eh9ZNYi6zo_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown__plus_X9TC_plus_1sw8c_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+X9TC+1sw8c", libCprmUnknown__plus_X9TC_plus_1sw8c_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_1M23A00Z5YY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("1M23A00Z5YY", libCprmUnknown_1M23A00Z5YY_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_9Blq0Y1cfC4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("9Blq0Y1cfC4", libCprmUnknown_9Blq0Y1cfC4_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_C_plus_UDpkvBfq0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("C+UDpkvBfq0", libCprmUnknown_C_plus_UDpkvBfq0_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_Dxqbh2fid_minus_0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Dxqbh2fid-0", libCprmUnknown_Dxqbh2fid_minus_0_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_GYIfXUO2DQM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("GYIfXUO2DQM", libCprmUnknown_GYIfXUO2DQM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_GzdjmaMs2ec_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("GzdjmaMs2ec", libCprmUnknown_GzdjmaMs2ec_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_Ja2HmL89pQk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Ja2HmL89pQk", libCprmUnknown_Ja2HmL89pQk_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_N1QA8ydpT5s_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("N1QA8ydpT5s", libCprmUnknown_N1QA8ydpT5s_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_Qqt9wsrnORY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Qqt9wsrnORY", libCprmUnknown_Qqt9wsrnORY_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_SebG2x8vugA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("SebG2x8vugA", libCprmUnknown_SebG2x8vugA_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_Sz5wfo9uoQo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Sz5wfo9uoQo", libCprmUnknown_Sz5wfo9uoQo_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_UXwPU6S3K3M_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("UXwPU6S3K3M", libCprmUnknown_UXwPU6S3K3M_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_Ut6wGp0l_minus_EU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Ut6wGp0l-EU", libCprmUnknown_Ut6wGp0l_minus_EU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_Uv_minus_1Y7ctRPg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Uv-1Y7ctRPg", libCprmUnknown_Uv_minus_1Y7ctRPg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_WWfjXT2d7SM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("WWfjXT2d7SM", libCprmUnknown_WWfjXT2d7SM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_YhPUdyQoZ2w_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("YhPUdyQoZ2w", libCprmUnknown_YhPUdyQoZ2w_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_YvBd1vant8Y_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("YvBd1vant8Y", libCprmUnknown_YvBd1vant8Y_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_aoE6klVaQmo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("aoE6klVaQmo", libCprmUnknown_aoE6klVaQmo_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_fb1srL_plus__plus_42M_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("fb1srL++42M", libCprmUnknown_fb1srL_plus__plus_42M_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_gnClz0AOgtw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("gnClz0AOgtw", libCprmUnknown_gnClz0AOgtw_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_h9jXWgBLon0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("h9jXWgBLon0", libCprmUnknown_h9jXWgBLon0_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_hs4OD9CTzsU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("hs4OD9CTzsU", libCprmUnknown_hs4OD9CTzsU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_hvZH8f_plus_HBVg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("hvZH8f+HBVg", libCprmUnknown_hvZH8f_plus_HBVg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_i2aJI0V3U3A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("i2aJI0V3U3A", libCprmUnknown_i2aJI0V3U3A_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_iDCilRZjGRM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("iDCilRZjGRM", libCprmUnknown_iDCilRZjGRM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_lCmvZpz_minus_8Sg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("lCmvZpz-8Sg", libCprmUnknown_lCmvZpz_minus_8Sg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_llRRCXKDB8g_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("llRRCXKDB8g", libCprmUnknown_llRRCXKDB8g_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_mq_plus_QSu3eTDM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("mq+QSu3eTDM", libCprmUnknown_mq_plus_QSu3eTDM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_pa1PYEalrtU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("pa1PYEalrtU", libCprmUnknown_pa1PYEalrtU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_tsJszAZ7k_plus_A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("tsJszAZ7k+A", libCprmUnknown_tsJszAZ7k_plus_A_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_vR2Jy582NrI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("vR2Jy582NrI", libCprmUnknown_vR2Jy582NrI_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_x5bhPjRC_plus_WQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("x5bhPjRC+WQ", libCprmUnknown_x5bhPjRC_plus_WQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI libCprmUnknown_y2mH4WVl028_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("y2mH4WVl028", libCprmUnknown_y2mH4WVl028_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libCprmUnknown__plus_Eh9ZNYi6zo_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown__plus_X9TC_plus_1sw8c_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_1M23A00Z5YY_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_9Blq0Y1cfC4_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_C_plus_UDpkvBfq0_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_Dxqbh2fid_minus_0_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_GYIfXUO2DQM_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_GzdjmaMs2ec_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_Ja2HmL89pQk_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_N1QA8ydpT5s_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_Qqt9wsrnORY_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_SebG2x8vugA_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_Sz5wfo9uoQo_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_UXwPU6S3K3M_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_Ut6wGp0l_minus_EU_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_Uv_minus_1Y7ctRPg_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_WWfjXT2d7SM_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_YhPUdyQoZ2w_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_YvBd1vant8Y_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_aoE6klVaQmo_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_fb1srL_plus__plus_42M_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_gnClz0AOgtw_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_h9jXWgBLon0_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_hs4OD9CTzsU_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_hvZH8f_plus_HBVg_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_i2aJI0V3U3A_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_iDCilRZjGRM_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_lCmvZpz_minus_8Sg_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_llRRCXKDB8g_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_mq_plus_QSu3eTDM_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_pa1PYEalrtU_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_tsJszAZ7k_plus_A_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_vR2Jy582NrI_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_x5bhPjRC_plus_WQ_nid_no_patch();
|
||||
int APS5_VABI libCprmUnknown_y2mH4WVl028_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "prx/libCprm/include/InventoryExports.hpp"
|
||||
@@ -1,3 +1,6 @@
|
||||
#include "prx/libSceAbstractStorage/include/LegacyExports.hpp"
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceAbstractStorage/include/InventoryExports.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
@@ -557,3 +560,116 @@ int APS5_VABI sceAbstractStorageUnknown_1uryzAWFUuA_nid_no_patch() {
|
||||
APS5_EXPORT("1uryzAWFUuA", sceAbstractStorageUnknown_1uryzAWFUuA_nid_no_patch);
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAbstractStorageUnknown__plus_bCU7y60g28_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+bCU7y60g28", libSceAbstractStorageUnknown__plus_bCU7y60g28_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAbstractStorageUnknown_JwplLmzUrs0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("JwplLmzUrs0", libSceAbstractStorageUnknown_JwplLmzUrs0_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAbstractStorageUnknown_Nrv7BRYovYk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Nrv7BRYovYk", libSceAbstractStorageUnknown_Nrv7BRYovYk_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAbstractStorageUnknown_YBmeXvldPyg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("YBmeXvldPyg", libSceAbstractStorageUnknown_YBmeXvldPyg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAbstractStorageUnknown_jsjQnoZHra8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("jsjQnoZHra8", libSceAbstractStorageUnknown_jsjQnoZHra8_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAbstractStorageUnknown_lMU9P5mJtNM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("lMU9P5mJtNM", libSceAbstractStorageUnknown_lMU9P5mJtNM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAbstractStorageUnknown_scAYh9JGyYI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("scAYh9JGyYI", libSceAbstractStorageUnknown_scAYh9JGyYI_nid_no_patch);
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown__minus_lJCD9v3ShE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("-lJCD9v3ShE", abstractStorageLegacyUnknown__minus_lJCD9v3ShE_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_58hoiRX9eq0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("58hoiRX9eq0", abstractStorageLegacyUnknown_58hoiRX9eq0_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_5E95udm3i4A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("5E95udm3i4A", abstractStorageLegacyUnknown_5E95udm3i4A_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_5sF6O0X8XOg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("5sF6O0X8XOg", abstractStorageLegacyUnknown_5sF6O0X8XOg_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_7re96ARYiKU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("7re96ARYiKU", abstractStorageLegacyUnknown_7re96ARYiKU_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_8urQQ98mwcg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("8urQQ98mwcg", abstractStorageLegacyUnknown_8urQQ98mwcg_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_BcT4KRrLn2U_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("BcT4KRrLn2U", abstractStorageLegacyUnknown_BcT4KRrLn2U_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_EawgMNYrP2A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("EawgMNYrP2A", abstractStorageLegacyUnknown_EawgMNYrP2A_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_Gz6_plus_aMUIR44_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Gz6+aMUIR44", abstractStorageLegacyUnknown_Gz6_plus_aMUIR44_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_QieeCoOG9bQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("QieeCoOG9bQ", abstractStorageLegacyUnknown_QieeCoOG9bQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_YyubErxn_plus_aM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("YyubErxn+aM", abstractStorageLegacyUnknown_YyubErxn_plus_aM_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_njl_plus_S_plus_GCNOQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("njl+S+GCNOQ", abstractStorageLegacyUnknown_njl_plus_S_plus_GCNOQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_nkDADDAUxc4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("nkDADDAUxc4", abstractStorageLegacyUnknown_nkDADDAUxc4_nid_no_patch);
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown_pfToDbCVd_minus_Y_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("pfToDbCVd-Y", abstractStorageLegacyUnknown_pfToDbCVd_minus_Y_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAbstractStorageUnknown__plus_bCU7y60g28_nid_no_patch();
|
||||
int APS5_VABI libSceAbstractStorageUnknown_JwplLmzUrs0_nid_no_patch();
|
||||
int APS5_VABI libSceAbstractStorageUnknown_Nrv7BRYovYk_nid_no_patch();
|
||||
int APS5_VABI libSceAbstractStorageUnknown_YBmeXvldPyg_nid_no_patch();
|
||||
int APS5_VABI libSceAbstractStorageUnknown_jsjQnoZHra8_nid_no_patch();
|
||||
int APS5_VABI libSceAbstractStorageUnknown_lMU9P5mJtNM_nid_no_patch();
|
||||
int APS5_VABI libSceAbstractStorageUnknown_scAYh9JGyYI_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI abstractStorageLegacyUnknown__minus_lJCD9v3ShE_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_58hoiRX9eq0_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_5E95udm3i4A_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_5sF6O0X8XOg_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_7re96ARYiKU_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_8urQQ98mwcg_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_BcT4KRrLn2U_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_EawgMNYrP2A_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_Gz6_plus_aMUIR44_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_QieeCoOG9bQ_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_YyubErxn_plus_aM_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_njl_plus_S_plus_GCNOQ_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_nkDADDAUxc4_nid_no_patch();
|
||||
int APS5_VABI abstractStorageLegacyUnknown_pfToDbCVd_minus_Y_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
#pragma once
|
||||
#include "prx/libSceAbstractStorage/include/InventoryExports.hpp"
|
||||
#include "prx/libSceAbstractStorage/include/LegacyExports.hpp"
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceAcm/include/InventoryExports.hpp"
|
||||
#include "prx/libSceAcm/include/Api.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
@@ -422,3 +424,32 @@ int APS5_VABI sceAcmBatchJobNotification() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAcmUnknown_9_plus_f3tPdeyP0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("9+f3tPdeyP0", libSceAcmUnknown_9_plus_f3tPdeyP0_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAcmUnknown_DvsnlQr4yyk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("DvsnlQr4yyk", libSceAcmUnknown_DvsnlQr4yyk_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAcmUnknown_PLNywpi1zR4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("PLNywpi1zR4", libSceAcmUnknown_PLNywpi1zR4_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAcmUnknown_YpYvibqaqz0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("YpYvibqaqz0", libSceAcmUnknown_YpYvibqaqz0_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAcmUnknown_ngDRON91_plus__minus_Y_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("ngDRON91+-Y", libSceAcmUnknown_ngDRON91_plus__minus_Y_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAcmUnknown_9_plus_f3tPdeyP0_nid_no_patch();
|
||||
int APS5_VABI libSceAcmUnknown_DvsnlQr4yyk_nid_no_patch();
|
||||
int APS5_VABI libSceAcmUnknown_PLNywpi1zR4_nid_no_patch();
|
||||
int APS5_VABI libSceAcmUnknown_YpYvibqaqz0_nid_no_patch();
|
||||
int APS5_VABI libSceAcmUnknown_ngDRON91_plus__minus_Y_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "prx/libSceAcm/include/Api.hpp"
|
||||
#include "prx/libSceAcm/include/InventoryExports.hpp"
|
||||
@@ -635,6 +635,16 @@ if(BUILD_TESTING)
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
|
||||
add_test_executable(agc_adaptive_staging_tests tests/AdaptiveStaging.cpp)
|
||||
target_include_directories(agc_adaptive_staging_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(agc_adaptive_staging_tests PRIVATE libc)
|
||||
add_test(NAME agc_adaptive_staging COMMAND agc_adaptive_staging_tests)
|
||||
set_tests_properties(agc_adaptive_staging PROPERTIES TIMEOUT 30)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_adaptive_staging PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
|
||||
add_test_executable(agc_capture_trace_tests tests/CaptureTrace.cpp)
|
||||
target_include_directories(agc_capture_trace_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(agc_capture_trace_tests PRIVATE libc)
|
||||
@@ -3127,14 +3137,20 @@ if(BUILD_TESTING)
|
||||
set_tests_properties(agc_driver_native_depth_retirement PROPERTIES TIMEOUT 30 ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1" SKIP_RETURN_CODE 77 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
add_test(NAME agc_driver_native_depth_clears COMMAND agc_driver_native_multisample_depth_tests --clears)
|
||||
add_test(NAME agc_driver_native_depth_clear_refusals COMMAND agc_driver_native_multisample_depth_tests --clear-refusals)
|
||||
add_test(NAME agc_driver_htile_mask_lifetime COMMAND agc_driver_depth_fast_clear_submit_tests --mask-lifetime)
|
||||
set_tests_properties(agc_driver_htile_mask_lifetime PROPERTIES TIMEOUT 30 ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1" SKIP_RETURN_CODE 77 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_driver_htile_mask_lifetime PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test(NAME agc_driver_native_depth_stencil COMMAND agc_driver_native_multisample_depth_tests --stencil)
|
||||
add_test(NAME agc_driver_native_depth_separate_stencil COMMAND agc_driver_native_multisample_depth_tests --separate-stencil)
|
||||
add_test(NAME agc_driver_native_depth_aliased_stencil COMMAND agc_driver_native_multisample_depth_tests --aliased-stencil)
|
||||
add_test(NAME agc_driver_native_depth_expand_gate COMMAND agc_driver_native_multisample_depth_tests --expand-gate)
|
||||
set_tests_properties(agc_driver_native_depth_clears agc_driver_native_depth_clear_refusals agc_driver_native_depth_stencil agc_driver_native_depth_separate_stencil agc_driver_native_depth_aliased_stencil agc_driver_native_depth_expand_gate PROPERTIES TIMEOUT 30 ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1" SKIP_RETURN_CODE 77 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
add_test(NAME agc_driver_native_depth_buffer_clear COMMAND agc_driver_native_multisample_depth_tests --buffer-clear)
|
||||
set_tests_properties(agc_driver_native_depth_clears agc_driver_native_depth_clear_refusals agc_driver_native_depth_stencil agc_driver_native_depth_separate_stencil agc_driver_native_depth_aliased_stencil agc_driver_native_depth_expand_gate agc_driver_native_depth_buffer_clear PROPERTIES TIMEOUT 30 ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1" SKIP_RETURN_CODE 77 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_driver_native_depth_retirement PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
set_tests_properties(agc_driver_native_depth_clears agc_driver_native_depth_clear_refusals agc_driver_native_depth_stencil agc_driver_native_depth_separate_stencil agc_driver_native_depth_aliased_stencil agc_driver_native_depth_expand_gate PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
set_tests_properties(agc_driver_native_depth_clears agc_driver_native_depth_clear_refusals agc_driver_native_depth_stencil agc_driver_native_depth_separate_stencil agc_driver_native_depth_aliased_stencil agc_driver_native_depth_expand_gate agc_driver_native_depth_buffer_clear PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test(NAME agc_driver_native_depth_driver_path COMMAND agc_driver_native_multisample_depth_tests --driver-path)
|
||||
add_test(NAME agc_driver_native_depth_driver_queued_fill COMMAND agc_driver_native_multisample_depth_tests --driver-queued-fill)
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace AgcDriver {
|
||||
|
||||
namespace Graphics {
|
||||
class StorageTexture;
|
||||
struct HtileMaskClear;
|
||||
}
|
||||
|
||||
// Stage A of a dispatch's resource build (see VulkanDevice::PrepareDispatch); opaque to callers.
|
||||
@@ -145,6 +146,7 @@ public:
|
||||
// every recorded store over the range.
|
||||
bool FillBuffer(std::uint64_t address, std::size_t bytes, std::span<const std::uint32_t, 4> pattern);
|
||||
bool DumpSamplesOnGpu(std::uint64_t address);
|
||||
void NoteHtileMask(const Graphics::HtileMaskClear& clear) const;
|
||||
// Copies `bytes` of guest memory from `source` to `destination` (disjoint ranges) in place of the
|
||||
// engine's memcpy kernel (Driver.cpp copyBuffer). `path` 0: copied on the CPU at once, when
|
||||
// every test of the rule holds (each a pure query, nothing flushed or recorded before the
|
||||
@@ -296,7 +298,7 @@ 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::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);
|
||||
// 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);
|
||||
|
||||
@@ -136,6 +136,7 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
|
||||
const bool pipelineCandidate = !resolving && !fromAhead && DispatchItemsEnabled() && DrawPipeline::Active() && indirectArguments == 0 && deferredLabels().labels.empty() && !matchesCopyKernel(std::span(snapshot.code).subspan(codeOffset), userData, compute) && !MatchesStreamCopyKernel(std::span(snapshot.code).subspan(codeOffset), userData, compute) && !MatchesIndexedCopyKernel(std::span(snapshot.code).subspan(codeOffset), userData, compute);
|
||||
const bool partialLastGroup = partialGroups != std::array<std::uint32_t, 3>{};
|
||||
std::optional<std::pair<std::uint64_t, std::size_t>> htileClearCompletion;
|
||||
Graphics::HtileMaskClear htileMask;
|
||||
if (resolving) {
|
||||
if (indirectArguments == 0 && Graphics::MatchMultisampledSingleClear(std::span(snapshot.code).subspan(codeOffset), userData, compute.numThreads)) return;
|
||||
if (!partialLastGroup && matchesFillKernel(std::span(snapshot.code).subspan(codeOffset), userData, compute)) return;
|
||||
@@ -158,6 +159,10 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
|
||||
const auto nativeBytes = Graphics::HtileDepthClearBytes_nid_no_patch(std::span(snapshot.code).subspan(codeOffset), userData, compute, packet, indirectArguments);
|
||||
const auto bytes = static_cast<std::size_t>(threads * 16u);
|
||||
if (Graphics::NoteHtileDepthClear(htile, bytes, nativeBytes)) htileClearCompletion = std::pair{htile, bytes};
|
||||
if (nativeBytes != 0u) htileMask = {htile, nativeBytes, userData[5], userData[4]};
|
||||
} else if (const auto buffered = Graphics::MatchHtileBufferMaskClear(std::span(snapshot.code).subspan(codeOffset), userData, compute, packet, indirectArguments)) {
|
||||
if (Graphics::NoteHtileDepthClear(buffered->address, buffered->bytes, buffered->bytes)) htileClearCompletion = std::pair{buffered->address, buffered->bytes};
|
||||
htileMask = *buffered;
|
||||
}
|
||||
if (!partialLastGroup && indirectArguments == 0 && copyBuffer(queue, submission.queue, packet, std::span(snapshot.code).subspan(codeOffset), userData, compute, localDevice, address)) {
|
||||
pendingDispatchPhases().outcome = DispatchOutcome::CopyHle;
|
||||
@@ -493,7 +498,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] {
|
||||
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::FollowEpoch(epoch);
|
||||
GuestMemory::SetCurrentPacket(0x15, queueId);
|
||||
const auto& compiledCommit = *result;
|
||||
@@ -504,7 +509,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);
|
||||
if (recipeHit == nullptr || VulkanDevice::VerifyRecipes() || htileClearCompletion.has_value()) prepared = localDevice->PrepareDispatch(compiledCommit, snapshots, 0, address, htileClearCompletion);
|
||||
GuestMemory::TagGpuLockSite(GuestMemory::GpuLockSite::Dispatch);
|
||||
std::lock_guard gpuLock(GuestMemory::GpuMutex());
|
||||
recordLabelsForPacket(localDevice.get(), queueId);
|
||||
@@ -524,6 +529,7 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
|
||||
} else {
|
||||
localDevice->Dispatch(compiledCommit, groups[0], groups[1], groups[2], snapshots, address, std::move(prepared), htileClearCompletion.has_value() ? nullptr : &builtRecipe, htileClearCompletion);
|
||||
}
|
||||
if (htileMask.bytes != 0u) localDevice->NoteHtileMask(htileMask);
|
||||
break;
|
||||
}
|
||||
if (noteWrites && !writerKeyedEvidence()) noteWrittenBuffers(address, queueId, compiledCommit);
|
||||
@@ -577,7 +583,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);
|
||||
prepared = localDevice->PrepareDispatch(compiled, snapshots, dispatchThreads, address, htileClearCompletion);
|
||||
} catch (const std::exception& error) {
|
||||
if (rethrow(error)) return;
|
||||
}
|
||||
@@ -635,6 +641,7 @@ void Driver::dispatch(QueueState& queue, std::span<const std::uint32_t> packet,
|
||||
const auto note = keysRecorder->LastWriteNote(keysFill->base, keysFill->bytes);
|
||||
if (note != 0 && note != keysNoteBefore) Graphics::NoteKeysFillOnGpu(keysFill->base, keysFill->bytes, *filledKeys);
|
||||
}
|
||||
if (htileMask.bytes != 0u) localDevice->NoteHtileMask(htileMask);
|
||||
if (builtRecipe != nullptr) {
|
||||
if (dataHit) {
|
||||
|
||||
|
||||
@@ -839,6 +839,7 @@ struct VulkanDevice::State {
|
||||
}
|
||||
const double gapMs = stamped ? (lastNs - firstNs) / 1e6 - busyMs : 0;
|
||||
if (auto* frame = PerformanceContext::Current()) frame->NoteRetired(0, busyMs, gapMs);
|
||||
if (stamped && missing == 0) Graphics::Recorder::NoteFrameGpuBusy(busyMs);
|
||||
presentCounters.gpuBusyMs += busyMs;
|
||||
presentCounters.gpuGapMs += gapMs;
|
||||
presentCounters.gpuUnread += missing;
|
||||
@@ -2389,16 +2390,33 @@ bool VulkanDevice::ReplayComputePipeline(const ShaderRecompiler::RecompileResult
|
||||
if (state->computePipelines.contains(key) || state->computePipelinesBuilding.contains(key)) return false;
|
||||
}
|
||||
const CompileBudget::Hold hold(BackgroundCompileBudget(), shader.spirv.size() * sizeof(std::uint32_t));
|
||||
std::promise<std::shared_ptr<ComputePipelineObjects>> building;
|
||||
{
|
||||
std::lock_guard pipelines(state->computePipelinesMutex);
|
||||
if (state->computePipelines.contains(key) || state->computePipelinesBuilding.contains(key)) return false;
|
||||
state->computePipelinesBuilding.emplace(key, building.get_future().share());
|
||||
}
|
||||
const auto context = graphicsContext();
|
||||
const std::array<Graphics::CompiledShader, 1> shaders{{{ShaderRecompiler::ShaderStage::Compute, &shader, 0}}};
|
||||
const auto layouts = Graphics::DescribeSetLayouts(context, shaders);
|
||||
auto objects = createComputePipeline(context, shader, layouts.layouts.main, layouts.mainKey, pushConstants ? VK_SHADER_STAGE_COMPUTE_BIT : 0u, 0);
|
||||
std::lock_guard pipelines(state->computePipelinesMutex);
|
||||
return state->computePipelines.try_emplace(key, std::move(objects)).second;
|
||||
std::shared_ptr<ComputePipelineObjects> objects;
|
||||
std::exception_ptr error;
|
||||
try {
|
||||
const auto context = graphicsContext();
|
||||
const std::array<Graphics::CompiledShader, 1> shaders{{{ShaderRecompiler::ShaderStage::Compute, &shader, 0}}};
|
||||
const auto layouts = Graphics::DescribeSetLayouts(context, shaders);
|
||||
objects = createComputePipeline(context, shader, layouts.layouts.main, layouts.mainKey, pushConstants ? VK_SHADER_STAGE_COMPUTE_BIT : 0u, 0);
|
||||
} catch (...) {
|
||||
error = std::current_exception();
|
||||
}
|
||||
{
|
||||
std::lock_guard pipelines(state->computePipelinesMutex);
|
||||
if (objects != nullptr) state->computePipelines.try_emplace(key, objects);
|
||||
state->computePipelinesBuilding.erase(key);
|
||||
}
|
||||
if (error != nullptr) {
|
||||
building.set_exception(error);
|
||||
std::rethrow_exception(error);
|
||||
}
|
||||
building.set_value(std::move(objects));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanDevice::HasComputePipeline(const ShaderRecompiler::RecompileResult& shader) const {
|
||||
@@ -2654,6 +2672,10 @@ bool VulkanDevice::AfterRecordedWork(std::function<void()> action, bool reapFirs
|
||||
return state->recorder->AfterRecordedWork(std::move(action));
|
||||
}
|
||||
|
||||
void VulkanDevice::NoteHtileMask(const Graphics::HtileMaskClear& clear) const {
|
||||
Graphics::NoteHtileMaskOnGpu(graphicsContext(), clear);
|
||||
}
|
||||
|
||||
bool VulkanDevice::DumpSamplesOnGpu(std::uint64_t address) {
|
||||
static const bool syncDumps = std::getenv("APS5_SYNC_SAMPLE_DUMPS") != nullptr || std::getenv("APS5_NO_GPU_SAMPLE_DUMPS") != nullptr;
|
||||
if (syncDumps) return false;
|
||||
@@ -5001,7 +5023,7 @@ 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::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) {
|
||||
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;
|
||||
@@ -5023,7 +5045,7 @@ std::shared_ptr<PreparedDispatch> VulkanDevice::PrepareDispatch(const ShaderReco
|
||||
prepared->phaseMs[which] += std::chrono::duration<double, std::milli>(now - phaseStart).count();
|
||||
phaseStart = now;
|
||||
};
|
||||
if (ResourceCacheEnabled() && shader.PipelineVariantId() != 0) {
|
||||
if (!htileClear.has_value() && ResourceCacheEnabled() && shader.PipelineVariantId() != 0) {
|
||||
prepared->key = DispatchContentKey(compute, context.device);
|
||||
phase(PreparedDispatch::PrepareKey);
|
||||
cached = state->resourceCache.Find(prepared->key);
|
||||
@@ -5040,7 +5062,7 @@ std::shared_ptr<PreparedDispatch> VulkanDevice::PrepareDispatch(const ShaderReco
|
||||
phase(PreparedDispatch::PrepareFind);
|
||||
}
|
||||
if (cached == nullptr) {
|
||||
prepared->resources = std::make_shared<Graphics::ShaderResources>(context, compute, snapshots, true, dispatchThreads);
|
||||
prepared->resources = std::make_shared<Graphics::ShaderResources>(context, compute, snapshots, true, dispatchThreads, htileClear);
|
||||
phase(PreparedDispatch::PrepareStageA);
|
||||
}
|
||||
if (cached != nullptr && CachedPrecollect()) {
|
||||
@@ -5594,7 +5616,7 @@ VulkanDevice::IndirectOutcome VulkanDevice::dispatch(const ShaderRecompiler::Rec
|
||||
const auto lookupsBefore = Graphics::DeviceProcLookups();
|
||||
std::shared_ptr<Graphics::ShaderResources> resources;
|
||||
ResourceCache::Key contentKey;
|
||||
const bool cacheable = ResourceCacheEnabled() && shader.PipelineVariantId() != 0;
|
||||
const bool cacheable = !htileClear.has_value() && ResourceCacheEnabled() && shader.PipelineVariantId() != 0;
|
||||
// The object came from the resource cache: a compute template whose data buffers take this
|
||||
// dispatch's words at the record (ShaderResources::RefreshData).
|
||||
bool fromCache = false;
|
||||
@@ -5751,7 +5773,7 @@ VulkanDevice::IndirectOutcome VulkanDevice::dispatch(const ShaderRecompiler::Rec
|
||||
}
|
||||
if (resources == nullptr) {
|
||||
const auto buildStart = profile ? std::chrono::steady_clock::now() : std::chrono::steady_clock::time_point{};
|
||||
resources = std::make_shared<Graphics::ShaderResources>(context, shaders[0], snapshots, false, prepared != nullptr ? prepared->dispatchThreads : 0);
|
||||
resources = std::make_shared<Graphics::ShaderResources>(context, shaders[0], snapshots, false, prepared != nullptr ? prepared->dispatchThreads : 0, htileClear);
|
||||
if (profile) timer.add(PhaseResourcesFullBuild, std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - buildStart).count());
|
||||
if (cacheable) {
|
||||
++d.cacheMisses;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceAgcDriver/include/AgcDriver.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
@@ -6,11 +7,6 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceAgcDriverAcquireRazorACQ(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverCreateQueue(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
@@ -36,11 +32,6 @@ int APS5_VABI sceAgcDriverDestroyQueue(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverGetPaDebugInterfaceVersion(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverGetRegShadowInfo(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
@@ -66,11 +57,6 @@ int APS5_VABI sceAgcDriverIDHSSubmit(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverModuleRegistration(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverNotifyDefaultStates(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
@@ -91,11 +77,6 @@ int APS5_VABI sceAgcDriverSetFlip(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSetHsOffchipParamDirect(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSetWorkloadComplete(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
@@ -116,31 +97,16 @@ int APS5_VABI sceAgcDriverSetupRegisterShadow(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSubmitMultiCommandBuffersDirect(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSubmitToHDRScopesACQ(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSubmitToRazorACQ(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSuspendPointSubmit(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSuspendPointSubmitDirect(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSysEnableSubmitDone45Exception(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
@@ -182,3 +148,87 @@ int APS5_VABI sceAgcDriverUserDataWriteSetMarker(void) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_6WO4CscVnfM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("6WO4CscVnfM", libSceAgcDriverUnknown_6WO4CscVnfM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_6v_minus_D6CQHA4Y_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("6v-D6CQHA4Y", libSceAgcDriverUnknown_6v_minus_D6CQHA4Y_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_8CXPPlNmvIc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("8CXPPlNmvIc", libSceAgcDriverUnknown_8CXPPlNmvIc_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_Cia3HgY0WiY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Cia3HgY0WiY", libSceAgcDriverUnknown_Cia3HgY0WiY_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_DGN_plus_IaHNR8o_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("DGN+IaHNR8o", libSceAgcDriverUnknown_DGN_plus_IaHNR8o_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_EqwPDQyh_plus_Ec_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("EqwPDQyh+Ec", libSceAgcDriverUnknown_EqwPDQyh_plus_Ec_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_IGYqP_plus_WKCgc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("IGYqP+WKCgc", libSceAgcDriverUnknown_IGYqP_plus_WKCgc_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_LgctzJSGy7s_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("LgctzJSGy7s", libSceAgcDriverUnknown_LgctzJSGy7s_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_NmE3PfE211o_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("NmE3PfE211o", libSceAgcDriverUnknown_NmE3PfE211o_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_O144kUYDSBo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("O144kUYDSBo", libSceAgcDriverUnknown_O144kUYDSBo_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_gpF0LZ3_plus_19c_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("gpF0LZ3+19c", libSceAgcDriverUnknown_gpF0LZ3_plus_19c_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_mxyUaQfPgb8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("mxyUaQfPgb8", libSceAgcDriverUnknown_mxyUaQfPgb8_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_oFb2hMcoJa4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("oFb2hMcoJa4", libSceAgcDriverUnknown_oFb2hMcoJa4_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_sW7yp7NVlrk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("sW7yp7NVlrk", libSceAgcDriverUnknown_sW7yp7NVlrk_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_tD2ECNSuTQQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("tD2ECNSuTQQ", libSceAgcDriverUnknown_tD2ECNSuTQQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAgcDriverUnknown_wxdcyVqXJEY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("wxdcyVqXJEY", libSceAgcDriverUnknown_wxdcyVqXJEY_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_GRAPHICS_INCLUDE_ADAPTIVESTAGING_HPP
|
||||
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_GRAPHICS_INCLUDE_ADAPTIVESTAGING_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace AgcDriver::Graphics {
|
||||
|
||||
class AdaptiveStaging {
|
||||
public:
|
||||
static constexpr std::uint64_t SettleFrames = 4;
|
||||
static constexpr std::uint64_t MeasuredFrames = 8;
|
||||
static constexpr std::uint64_t EarlyFrames = 3;
|
||||
static constexpr std::int64_t ReprobeMs = 20000;
|
||||
static constexpr std::int64_t MaxReprobeMs = 160000;
|
||||
static constexpr std::int64_t ShareWindowMs = 10000;
|
||||
static constexpr double SceneShift = 0.25;
|
||||
|
||||
std::function<void(const std::string&)> report;
|
||||
|
||||
bool InPlace(std::uint64_t begin, std::uint64_t end, bool use, std::uint64_t frames, double busyMs, std::int64_t nowMs) {
|
||||
const Key key{begin, end};
|
||||
auto& element = elements[key];
|
||||
if (use) element.bytes += end - begin;
|
||||
tick(frames, busyMs, nowMs);
|
||||
if (probe.active && probe.key == key) return probe.phase == 1 ? !element.inPlace : element.inPlace;
|
||||
return element.inPlace;
|
||||
}
|
||||
|
||||
private:
|
||||
using Key = std::pair<std::uint64_t, std::uint64_t>;
|
||||
|
||||
struct Element {
|
||||
std::uint64_t bytes = 0;
|
||||
bool inPlace = false;
|
||||
std::int64_t nextProbeMs = 0;
|
||||
std::int64_t intervalMs = ReprobeMs;
|
||||
};
|
||||
struct Probe {
|
||||
bool active = false;
|
||||
Key key{};
|
||||
int phase = 0;
|
||||
std::uint64_t phaseFrames = 0;
|
||||
std::vector<double> samples[3];
|
||||
};
|
||||
|
||||
void say(const char* format, auto... args) {
|
||||
if (!report) return;
|
||||
char text[256];
|
||||
std::snprintf(text, sizeof(text), format, args...);
|
||||
report(text);
|
||||
}
|
||||
|
||||
void tick(std::uint64_t frames, double busyMs, std::int64_t now) {
|
||||
if (frames == lastFrames) return;
|
||||
const auto newFrames = frames - lastFrames;
|
||||
const double perFrame = (busyMs - lastBusyMs) / static_cast<double>(newFrames);
|
||||
lastFrames = frames;
|
||||
lastBusyMs = busyMs;
|
||||
if (now - windowStartMs >= ShareWindowMs) {
|
||||
for (auto& [key, element] : elements) element.bytes /= 2;
|
||||
windowStartMs = now;
|
||||
}
|
||||
if (!probe.active) {
|
||||
watchScene(perFrame, newFrames, now);
|
||||
start(now);
|
||||
return;
|
||||
}
|
||||
auto& element = elements[probe.key];
|
||||
probe.phaseFrames += newFrames;
|
||||
if (probe.phaseFrames <= SettleFrames) return;
|
||||
if (perFrame > 0) probe.samples[probe.phase].push_back(perFrame);
|
||||
if (probe.phase == 1 && clearlySlower()) {
|
||||
decide(element, now);
|
||||
return;
|
||||
}
|
||||
if (probe.phaseFrames < SettleFrames + MeasuredFrames) return;
|
||||
if (++probe.phase < 3) {
|
||||
probe.phaseFrames = 0;
|
||||
return;
|
||||
}
|
||||
decide(element, now);
|
||||
}
|
||||
|
||||
bool clearlySlower() const {
|
||||
const auto& current = probe.samples[0];
|
||||
const auto& other = probe.samples[1];
|
||||
if (current.size() < MeasuredFrames || other.size() < EarlyFrames) return false;
|
||||
return *std::min_element(other.begin(), other.end()) > *std::max_element(current.begin(), current.end());
|
||||
}
|
||||
|
||||
void watchScene(double perFrame, std::uint64_t newFrames, std::int64_t now) {
|
||||
if (perFrame <= 0 || decidedMs <= 0) return;
|
||||
if (settling > 0) {
|
||||
settling -= std::min(settling, newFrames);
|
||||
return;
|
||||
}
|
||||
sceneMs = sceneMs * 0.9 + perFrame * 0.1;
|
||||
if (std::abs(sceneMs - decidedMs) <= SceneShift * decidedMs) return;
|
||||
say("[staging] adaptive: frame GPU %.1f -> %.1f ms, probing again", decidedMs, sceneMs);
|
||||
for (auto& [key, element] : elements) {
|
||||
element.nextProbeMs = std::min(element.nextProbeMs, now);
|
||||
element.intervalMs = ReprobeMs;
|
||||
}
|
||||
decidedMs = 0;
|
||||
}
|
||||
|
||||
void start(std::int64_t now) {
|
||||
std::uint64_t total = 0;
|
||||
for (const auto& [key, element] : elements) total += element.bytes;
|
||||
const Element* best = nullptr;
|
||||
Key bestKey{};
|
||||
for (const auto& [key, element] : elements) {
|
||||
if (element.nextProbeMs > now || element.bytes * 10 < total) continue;
|
||||
if (best == nullptr || element.bytes > best->bytes) {
|
||||
best = &element;
|
||||
bestKey = key;
|
||||
}
|
||||
}
|
||||
if (best == nullptr) return;
|
||||
probe = Probe{};
|
||||
probe.active = true;
|
||||
probe.key = bestKey;
|
||||
}
|
||||
|
||||
void decide(Element& element, std::int64_t now) {
|
||||
std::vector<double> current = probe.samples[0];
|
||||
current.insert(current.end(), probe.samples[2].begin(), probe.samples[2].end());
|
||||
const auto& other = probe.samples[1];
|
||||
const auto stats = [](const std::vector<double>& values) {
|
||||
double sum = 0, squares = 0;
|
||||
for (const auto value : values) sum += value;
|
||||
const double mean = values.empty() ? 0 : sum / static_cast<double>(values.size());
|
||||
for (const auto value : values) squares += (value - mean) * (value - mean);
|
||||
const double variance = values.size() > 1 ? squares / static_cast<double>(values.size() - 1) : 0;
|
||||
return std::pair{mean, values.empty() ? 0.0 : variance / static_cast<double>(values.size())};
|
||||
};
|
||||
const auto [currentMean, currentError] = stats(current);
|
||||
const auto [otherMean, otherError] = stats(other);
|
||||
const bool measured = current.size() >= MeasuredFrames && other.size() >= EarlyFrames;
|
||||
const bool flip = measured && otherMean < currentMean - 2.0 * std::sqrt(currentError + otherError);
|
||||
const double stagedMs = element.inPlace ? otherMean : currentMean;
|
||||
const double inPlaceMs = element.inPlace ? currentMean : otherMean;
|
||||
if (flip) element.inPlace = !element.inPlace;
|
||||
element.intervalMs = flip || !measured ? ReprobeMs : std::min(element.intervalMs * 2, MaxReprobeMs);
|
||||
element.nextProbeMs = now + element.intervalMs;
|
||||
decidedMs = flip ? otherMean : currentMean;
|
||||
sceneMs = decidedMs;
|
||||
settling = SettleFrames;
|
||||
say("[staging] adaptive: 0x%llx+0x%llx GPU %.1f ms/frame staged, %.1f in place (%zu/%zu frames) -> %s%s, next probe in %lld s", static_cast<unsigned long long>(probe.key.first), static_cast<unsigned long long>(probe.key.second - probe.key.first), stagedMs, inPlaceMs, current.size(), other.size(), element.inPlace ? "in place" : "staged", measured ? "" : " (not measured)", static_cast<long long>(element.intervalMs / 1000));
|
||||
probe = Probe{};
|
||||
}
|
||||
|
||||
std::map<Key, Element> elements;
|
||||
Probe probe;
|
||||
std::uint64_t lastFrames = 0;
|
||||
double lastBusyMs = 0;
|
||||
double decidedMs = 0;
|
||||
double sceneMs = 0;
|
||||
std::uint64_t settling = 0;
|
||||
std::int64_t windowStartMs = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -38,7 +38,7 @@ bool DirectDepthCopy(const Context& context, VkFormat depthFormat, VkImageAspect
|
||||
void SetDirectDepthCopy(bool enabled);
|
||||
std::uint64_t DirectDepthCopyCount();
|
||||
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);
|
||||
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);
|
||||
bool HasResidentDepthGuards_nid_no_patch();
|
||||
void RetireUnmappedDepth_nid_no_patch(std::uintptr_t address, std::size_t bytes);
|
||||
@@ -63,6 +63,15 @@ bool NoteHtileDepthClear(std::uint64_t htileAddress, std::size_t bytes, std::siz
|
||||
void ArmHtileDepthClear(std::uint64_t htileAddress, std::size_t bytes);
|
||||
void QueueHtileDepthClear(std::uint64_t htileAddress, std::size_t bytes);
|
||||
void CompleteHtileDepthClear(std::uint64_t htileAddress, std::size_t bytes);
|
||||
struct HtileMaskClear {
|
||||
std::uint64_t address = 0;
|
||||
std::size_t bytes = 0;
|
||||
std::uint32_t mask = 0;
|
||||
std::uint32_t value = 0;
|
||||
};
|
||||
std::optional<HtileMaskClear> MatchHtileBufferMaskClear(std::span<const std::uint32_t> code, std::span<const std::uint32_t> userData, const ShaderRecompiler::ShaderComputeStageInfo& compute, std::span<const std::uint32_t> packet, std::uint64_t indirectArguments);
|
||||
void NoteHtileMaskOnGpu(const Context& context, const HtileMaskClear& clear);
|
||||
void ForgetHtileMasks_nid_no_patch(std::uint64_t recorderId);
|
||||
struct MemoryValueFill {
|
||||
std::uint64_t address;
|
||||
std::size_t bytes;
|
||||
|
||||
@@ -38,6 +38,7 @@ void BindPixelFunctionLds(const Context& context, VkCommandBuffer commands, VkPi
|
||||
void CheckPixelFunctionLds(const Context& context);
|
||||
void ReleasePixelFunctionLds(VkDevice device);
|
||||
bool UsesMeshWindow(std::span<const CompiledShader> shaders);
|
||||
bool ValidationKey(const Context& context, std::span<const CompiledShader> shaders, const State& state, std::vector<std::uint64_t>& key);
|
||||
VkDescriptorSetLayout MeshWindowSetLayout(const Context& context);
|
||||
void PrepareMeshWindow(const Context& context);
|
||||
void BindMeshWindow(const Context& context, VkCommandBuffer commands, VkPipelineLayout layout);
|
||||
|
||||
@@ -326,6 +326,7 @@ public:
|
||||
// were confirmed unchanged): the previous use's copy-back left the shadow behind, and the next
|
||||
// RecordCopyBacks copies it back again. Nothing to do without staged regions.
|
||||
void RecordStagingCopies(Recorder& recorder);
|
||||
bool StagingDecisionsCurrent() const;
|
||||
void AddSnapshot(const GuestMemorySnapshot& snapshot);
|
||||
// Upload is the two stages below back to back. UploadPrepare needs no device lock: it merges the
|
||||
// regions, binds the image mirrors and host imports that already serve them (an import pointer is
|
||||
@@ -336,7 +337,7 @@ public:
|
||||
// and the recorder's pending-write note stays closed.
|
||||
void Upload(bool addressable);
|
||||
void UploadPrepare(bool addressable);
|
||||
void UploadFinish(bool addressable);
|
||||
void UploadFinish(bool addressable, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear = std::nullopt);
|
||||
VkDescriptorBufferInfo Descriptor(std::uint64_t address, std::size_t bytes, std::uint32_t& adjustment) const;
|
||||
static std::uint64_t ViewBytes(std::uint64_t bytes, std::uint32_t adjustment);
|
||||
std::vector<ShaderRecompiler::BdaAbi::Range> AddressRanges() const;
|
||||
@@ -457,6 +458,7 @@ private:
|
||||
// path it would take without staging, in both upload stages.
|
||||
bool unstaged = false;
|
||||
bool overlay = false;
|
||||
bool adaptiveInPlace = false;
|
||||
};
|
||||
|
||||
// How [begin, end) lies against the space's base regions.
|
||||
@@ -502,6 +504,8 @@ private:
|
||||
// written element inside, and an atomic element or a size within the written-shadow window.
|
||||
// Independent of the import, so UploadPrepare and UploadFinish decide alike.
|
||||
bool stagingEligible(const Region& region, bool addressable) const;
|
||||
bool stagingWanted(const Region& region, bool addressable) const;
|
||||
bool adaptiveInPlace(const Region& region, bool use) const;
|
||||
bool overlayCandidate(const Region& inside, bool readOnly) const;
|
||||
void resolveOverlays();
|
||||
bool bindableInPlace(std::uint64_t offset, bool addressable) const;
|
||||
|
||||
@@ -425,6 +425,7 @@ public:
|
||||
// and for helpers that must not recycle resources the recorded work still uses.
|
||||
static Recorder* Active();
|
||||
VkDevice Device() const { return context.device; }
|
||||
std::uint64_t Id() const { return id; }
|
||||
// Whether the calling thread runs inside a batch's completion action (finish()): a store made
|
||||
// there must not have a publish recorded for it (UnitShadow), see SyncThrough.
|
||||
static bool InCompletion();
|
||||
@@ -529,6 +530,9 @@ public:
|
||||
// Presentations so far (never reset): a frame clock for policies that count per frame, such as
|
||||
// StorageTexture's write-back hysteresis.
|
||||
static std::uint64_t Presents();
|
||||
static void NoteFrameGpuBusy(double milliseconds);
|
||||
static std::pair<std::uint64_t, double> FrameGpuBusy();
|
||||
static void RequestBatchStamps();
|
||||
|
||||
// What the presenter learns about finished batches (Driver::Present's [present] line and the
|
||||
// frame record): finish() writes an entry per submitted batch into a ring of the last 128,
|
||||
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
// then no other member may be used. `compute` and `snapshots` must outlive Complete(). An
|
||||
// address-based shader (BDA tables) builds entirely in Complete(): its lease acquisition
|
||||
// reconciles imports and refreshes mirrors, which needs the lock.
|
||||
ShaderResources(const Context& context, const CompiledShader& compute, std::span<const GuestMemorySnapshot> snapshots, bool deferred, std::uint64_t dispatchThreads = 0);
|
||||
ShaderResources(const Context& context, const CompiledShader& compute, std::span<const GuestMemorySnapshot> snapshots, bool deferred, std::uint64_t dispatchThreads = 0, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear = std::nullopt);
|
||||
void Complete();
|
||||
bool Completed() const { return completed; }
|
||||
~ShaderResources();
|
||||
@@ -622,6 +622,7 @@ private:
|
||||
std::vector<std::pair<std::uint64_t, std::uint64_t>> writeOnlyRanges;
|
||||
bool drawBuild = false;
|
||||
std::uint64_t dispatchThreads = 0;
|
||||
std::optional<std::pair<std::uint64_t, std::size_t>> htileClear;
|
||||
std::vector<std::shared_ptr<Texture>> textures;
|
||||
std::vector<bool> textureFirstLayer;
|
||||
std::vector<bool> textureBaseLevel;
|
||||
|
||||
@@ -683,9 +683,14 @@ bool FillDccClear(VkFormat format, DccKeys keys, bool alphaOnMsb, std::span<std:
|
||||
if (((value >> i) & 1u) != 0) element[bit / 8u] |= static_cast<std::byte>(1u << (bit % 8u));
|
||||
}
|
||||
}
|
||||
std::size_t offset = 0;
|
||||
for (; offset + element.size() <= bytes.size(); offset += element.size()) std::memcpy(bytes.data() + offset, element.data(), element.size());
|
||||
std::fill(bytes.begin() + offset, bytes.end(), std::byte{0});
|
||||
const std::size_t whole = bytes.size() / element.size() * element.size();
|
||||
if (whole != 0) std::memcpy(bytes.data(), element.data(), element.size());
|
||||
for (std::size_t filled = element.size(); filled < whole;) {
|
||||
const auto chunk = std::min(filled, whole - filled);
|
||||
std::memcpy(bytes.data() + filled, bytes.data(), chunk);
|
||||
filled += chunk;
|
||||
}
|
||||
std::fill(bytes.begin() + static_cast<std::ptrdiff_t>(whole), bytes.end(), std::byte{0});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2000,6 +2000,42 @@ std::optional<std::uint32_t> htileAfterPendingFills(const Recorder& recorder, st
|
||||
return landed;
|
||||
}
|
||||
|
||||
struct HtileMaskWrite {
|
||||
HtileMaskClear clear;
|
||||
std::uint64_t note;
|
||||
std::uint64_t recorderId;
|
||||
VkDevice device;
|
||||
};
|
||||
|
||||
std::mutex& htileMasksMutex() {
|
||||
static std::mutex mutex;
|
||||
return mutex;
|
||||
}
|
||||
|
||||
std::vector<HtileMaskWrite>& htileMasks() {
|
||||
static auto* masks = new std::vector<HtileMaskWrite>();
|
||||
return *masks;
|
||||
}
|
||||
|
||||
std::optional<std::pair<VkImageAspectFlags, std::uint32_t>> htileAfterMaskClear(const Recorder& recorder, const DepthTarget& target, std::size_t bytes) {
|
||||
const auto newest = recorder.NewestWriteNote(target.htileAddress, bytes);
|
||||
if (newest == 0) return std::nullopt;
|
||||
std::optional<HtileMaskClear> clear;
|
||||
{
|
||||
std::lock_guard lock(htileMasksMutex());
|
||||
for (const auto& write : htileMasks()) {
|
||||
if (write.recorderId == recorder.Id() && write.note == newest && write.clear.address <= target.htileAddress && write.clear.address + write.clear.bytes >= target.htileAddress + bytes) clear = write.clear;
|
||||
}
|
||||
}
|
||||
if (!clear.has_value() || (clear->mask & 0xfu) != 0 || (clear->value & 0xfu) != 0) return std::nullopt;
|
||||
if (target.firstSlice != 0 && clear->mask != 0) return std::nullopt;
|
||||
if (!target.htileStencil) return std::pair<VkImageAspectFlags, std::uint32_t>{VK_IMAGE_ASPECT_DEPTH_BIT, 0xfffc000fu};
|
||||
if ((clear->mask & 0x300u) != 0) return std::nullopt;
|
||||
if (((clear->value >> 8u) & 0x3u) == 0) return std::pair<VkImageAspectFlags, std::uint32_t>{VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0xfffff3ffu};
|
||||
if ((clear->mask & 0x3f0u) != 0) return std::nullopt;
|
||||
return std::pair<VkImageAspectFlags, std::uint32_t>{VK_IMAGE_ASPECT_DEPTH_BIT, (clear->value & 0x3f0u) | 0xfffff00fu};
|
||||
}
|
||||
|
||||
bool storeHtileOnGpu(const Context& context, Recorder& recorder, std::uint64_t address, std::size_t bytes, std::uint32_t word) {
|
||||
if (address % 4u != 0 || bytes % 4u != 0) return false;
|
||||
const auto* import = HostImportFor(context, address, bytes);
|
||||
@@ -2049,6 +2085,11 @@ VkImageAspectFlags storeBackClearedHtile(const Context& context, const DepthTarg
|
||||
htileReads()[target.htileAddress] = generation;
|
||||
return cleared;
|
||||
}
|
||||
} else if (const auto known = htileAfterMaskClear(*recorder, target, bytes); known.has_value() && storeHtileOnGpu(context, *recorder, target.htileAddress, bytes, known->second)) {
|
||||
const auto generation = GuestMemory::CollectWrites(target.htileAddress, bytes);
|
||||
std::lock_guard lock(htileReadsMutex());
|
||||
htileReads()[target.htileAddress] = generation;
|
||||
return known->first;
|
||||
}
|
||||
}
|
||||
std::vector<std::uint32_t> words(bytes / 4u);
|
||||
@@ -2234,10 +2275,22 @@ std::uint64_t MultisampledDepthBytes_nid_no_patch(VkExtent2D extent, std::uint32
|
||||
return width * height * bytesPerTexel * samples;
|
||||
}
|
||||
|
||||
void RequireNoResidentDepthRead_nid_no_patch(std::uint64_t address, std::size_t bytes) {
|
||||
void RequireNoResidentDepthRead_nid_no_patch(std::uint64_t address, std::size_t bytes, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear) {
|
||||
if (bytes == 0u || !anyDepthGuard().load(std::memory_order_acquire)) return;
|
||||
Require(address <= std::numeric_limits<std::uint64_t>::max() - bytes, "native depth read range overflows");
|
||||
const auto overlaps = [&](const DepthGuard& range) { return address < range.address + range.bytes && range.address < address + bytes; };
|
||||
if (htileClear.has_value() && htileClear->second <= std::numeric_limits<std::uint64_t>::max() - htileClear->first && htileClear->first <= address && bytes <= htileClear->second && address - htileClear->first <= htileClear->second - bytes) {
|
||||
std::lock_guard lock(surfacesMutex());
|
||||
std::shared_lock guardLock(depthGuardMutex());
|
||||
const bool accepted = std::ranges::all_of(depthGuards(), [&](const auto& range) {
|
||||
if (!overlaps(range)) return true;
|
||||
return std::ranges::any_of(surfaces(), [&](const auto& surface) {
|
||||
const auto& metadata = surface->sampling.initial[1];
|
||||
return surface->active == range.active && surface->active->load(std::memory_order_acquire) && surface->samplingActive && surface->sampling.refusal.empty() && surface->clearPending && metadata.address == range.address && metadata.bytes == range.bytes && metadata.address == htileClear->first && metadata.bytes <= htileClear->second;
|
||||
});
|
||||
});
|
||||
if (accepted) return;
|
||||
}
|
||||
{
|
||||
std::shared_lock lock(depthGuardMutex());
|
||||
if (std::ranges::none_of(depthGuards(), overlaps)) return;
|
||||
@@ -2580,6 +2633,30 @@ std::uint64_t HtileDepthClearAddress(std::span<const std::uint32_t> code, std::s
|
||||
return userData[2] | (static_cast<std::uint64_t>(userData[3]) << 32u);
|
||||
}
|
||||
|
||||
std::optional<HtileMaskClear> MatchHtileBufferMaskClear(std::span<const std::uint32_t> code, std::span<const std::uint32_t> userData, const ShaderRecompiler::ShaderComputeStageInfo& compute, std::span<const std::uint32_t> packet, std::uint64_t indirectArguments) {
|
||||
static constexpr std::array<std::uint32_t, 16> kernel{0xd7460004u, 0x04010c0cu, 0xe00c2000u, 0x80000004u, 0xbf8c3f70u, 0xd7710000u, 0x00120008u, 0xd7710001u, 0x00160209u, 0xd7710002u, 0x001a040au, 0xd7710003u, 0x001e060bu, 0xe01c2000u, 0x80000004u, 0xbf810000u};
|
||||
if (userData.size() != 12u || packet.size() < 5u || indirectArguments != 0u) return std::nullopt;
|
||||
if (code.size() < kernel.size() || !std::equal(kernel.begin(), kernel.end(), code.begin())) return std::nullopt;
|
||||
if (compute.numThreads != std::array<std::uint32_t, 3>{64u, 1u, 1u} || !compute.groupIdEnable[0] || compute.threadIdComponentCount == 0u || compute.threadIdComponentCount > 3u) return std::nullopt;
|
||||
if (packet[1] == 0u || packet[2] != 1u || packet[3] != 1u || (packet[4] & 0x3u) != 0x1u) return std::nullopt;
|
||||
for (std::size_t word = 1; word < 4; ++word) {
|
||||
if (userData[4 + word] != userData[4] || userData[8 + word] != userData[8]) return std::nullopt;
|
||||
}
|
||||
if ((userData[8] & 0xfu) != 0u || (userData[4] & 0xfu) != 0u) return std::nullopt;
|
||||
const auto stride = (userData[1] >> 16u) & 0x3fffu;
|
||||
const bool swizzled = ((userData[1] >> 31u) & 1u) != 0u;
|
||||
const bool addTid = ((userData[3] >> 23u) & 1u) != 0u;
|
||||
const auto type = userData[3] >> 30u;
|
||||
const auto format = (userData[3] >> 12u) & 0x7fu;
|
||||
const auto selects = userData[3] & 0xfffu;
|
||||
if (stride != 16u || swizzled || addTid || type != 0u || format != 75u || selects != 0xfacu) return std::nullopt;
|
||||
const auto address = userData[0] | (static_cast<std::uint64_t>(userData[1] & 0xffffu) << 32u);
|
||||
const std::uint64_t threads = (packet[4] & 0x20u) != 0u ? packet[1] : static_cast<std::uint64_t>(packet[1]) * 64u;
|
||||
const auto records = std::min<std::uint64_t>(threads, userData[2]);
|
||||
if (address == 0u || (address & 15u) != 0u || records == 0u || records > 0x400000u) return std::nullopt;
|
||||
return HtileMaskClear{address, static_cast<std::size_t>(records * 16u), userData[8], userData[4]};
|
||||
}
|
||||
|
||||
std::optional<MemoryValueFill> MatchMemoryValueFill(std::span<const std::uint32_t> code, std::span<const std::uint32_t> userData, const std::array<std::uint32_t, 3>& numThreads, const std::array<std::uint32_t, 3>& groups) {
|
||||
static constexpr std::array<std::uint32_t, 9> kernel{0xd7460000u, 0x04010c08u, 0xf4201a82u, 0xfa000000u, 0xbf8cc07fu, 0x7e02026au, 0xe0102000u, 0x80000100u, 0xbf810000u};
|
||||
if (userData.size() < 8 || numThreads != std::array<std::uint32_t, 3>{64u, 1u, 1u} || groups[1] != 1u || groups[2] != 1u) return std::nullopt;
|
||||
@@ -2672,6 +2749,31 @@ std::size_t HtileDepthClearBytes_nid_no_patch(std::span<const std::uint32_t> cod
|
||||
return address <= std::numeric_limits<std::uint64_t>::max() - bytes ? static_cast<std::size_t>(bytes) : 0u;
|
||||
}
|
||||
|
||||
void NoteHtileMaskOnGpu(const Context& context, const HtileMaskClear& clear) {
|
||||
const auto* recorder = RecorderFor(context);
|
||||
if (recorder == nullptr || clear.bytes == 0) return;
|
||||
const auto end = clear.address + clear.bytes;
|
||||
std::uint64_t note = 0;
|
||||
bool covers = false;
|
||||
for (const auto& write : recorder->PendingWritesOver(clear.address, clear.bytes)) {
|
||||
if (write.note <= note) continue;
|
||||
note = write.note;
|
||||
covers = write.begin <= clear.address && write.end >= end;
|
||||
}
|
||||
std::lock_guard lock(htileMasksMutex());
|
||||
auto& masks = htileMasks();
|
||||
std::erase_if(masks, [&](const HtileMaskWrite& write) { return clear.address < write.clear.address + write.clear.bytes && write.clear.address < end; });
|
||||
if (!covers) return;
|
||||
constexpr std::size_t KeptMasks = 64;
|
||||
if (masks.size() >= KeptMasks) masks.erase(masks.begin());
|
||||
masks.push_back({clear, note, recorder->Id(), context.device});
|
||||
}
|
||||
|
||||
void ForgetHtileMasks_nid_no_patch(std::uint64_t recorderId) {
|
||||
std::lock_guard lock(htileMasksMutex());
|
||||
std::erase_if(htileMasks(), [&](const HtileMaskWrite& write) { return write.recorderId == recorderId; });
|
||||
}
|
||||
|
||||
bool NoteHtileDepthClear(std::uint64_t htileAddress, std::size_t bytes, std::size_t nativeBytes) {
|
||||
std::lock_guard lock(surfacesMutex());
|
||||
forgetHtileReads(htileAddress, bytes);
|
||||
@@ -2740,6 +2842,10 @@ void CompleteHtileDepthClear(std::uint64_t htileAddress, std::size_t bytes) {
|
||||
|
||||
void ClearDepthSurfaces(VkDevice device) {
|
||||
std::lock_guard gpu(GuestMemory::GpuMutex());
|
||||
{
|
||||
std::lock_guard lock(htileMasksMutex());
|
||||
std::erase_if(htileMasks(), [&](const HtileMaskWrite& write) { return write.device == device; });
|
||||
}
|
||||
std::lock_guard lock(surfacesMutex());
|
||||
drawnDepth = nullptr;
|
||||
surfacesSerial.fetch_add(1, std::memory_order_release);
|
||||
|
||||
@@ -950,6 +950,8 @@ void countCache(std::uint64_t DrawProfile::*counter) {
|
||||
++(stats.*counter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ValidateShaders decodes every SPIR-V instruction of every stage on every draw. Its outcome depends
|
||||
// only on the stages' compiled variants (a variant id names identical SPIR-V and binding layout),
|
||||
// their push constant placement and vertex attribute shapes, and the state fields it checks, so the
|
||||
@@ -967,10 +969,12 @@ bool ValidationKey(const Context& context, std::span<const CompiledShader> shade
|
||||
if (keyed) {
|
||||
key.reserve(40 + shaders.size() * 12);
|
||||
add(shaders.size());
|
||||
const bool patches = BarycentricPatches(state, shaders);
|
||||
add(patches ? static_cast<std::uint64_t>(state.provokingVertexMode) + 1u : 0u);
|
||||
for (const auto& shader : shaders) {
|
||||
Require(shader.program != nullptr, "missing compiled shader");
|
||||
const auto& program = *shader.program;
|
||||
const bool generated = (state.rectList && (shader.stage == Stage::TessellationControl || shader.stage == Stage::TessellationEvaluation)) || shader.stage == Stage::Geometry;
|
||||
const bool generated = ((state.rectList || patches) && (shader.stage == Stage::TessellationControl || shader.stage == Stage::TessellationEvaluation)) || shader.stage == Stage::Geometry;
|
||||
if (!generated && program.PipelineVariantId() == 0) {
|
||||
keyed = false;
|
||||
break;
|
||||
@@ -1037,6 +1041,8 @@ bool ValidationKey(const Context& context, std::span<const CompiledShader> shade
|
||||
return keyed;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
AgcDriver::Mutex& validationMutex() {
|
||||
static AgcDriver::Mutex mutex;
|
||||
return mutex;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "prx/libSceAgcDriver/Execution/include/ProfileOutput.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/AdaptiveStaging.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/Mutex.hpp"
|
||||
#include "ThreadOwned.hpp"
|
||||
@@ -5164,6 +5165,37 @@ void traceStaged(std::uint64_t begin, std::uint64_t end, bool atomic) {
|
||||
std::fprintf(stderr, "[staging] 0x%llx+0x%llx (%.1f KiB)%s\n", static_cast<unsigned long long>(begin), static_cast<unsigned long long>(end - begin), (end - begin) / 1024.0, atomic ? " atomic" : "");
|
||||
}
|
||||
|
||||
class AdaptiveStagingGate {
|
||||
public:
|
||||
static AdaptiveStagingGate& Get() {
|
||||
static AdaptiveStagingGate instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
static bool Enabled() {
|
||||
static const bool disabled = std::getenv("APS5_NO_ADAPTIVE_STAGING") != nullptr;
|
||||
return !disabled;
|
||||
}
|
||||
|
||||
bool InPlace(std::uint64_t begin, std::uint64_t end, bool use) {
|
||||
if (!Enabled()) return false;
|
||||
std::lock_guard lock(mutex);
|
||||
if (!stampsRequested) {
|
||||
Recorder::RequestBatchStamps();
|
||||
policy.report = [](const std::string& line) { std::fprintf(stderr, "%s\n", line.c_str()); };
|
||||
stampsRequested = true;
|
||||
}
|
||||
const auto [frames, busyMs] = Recorder::FrameGpuBusy();
|
||||
const auto nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
return policy.InPlace(begin, end, use, frames, busyMs, nowMs);
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex;
|
||||
AdaptiveStaging policy;
|
||||
bool stampsRequested = false;
|
||||
};
|
||||
|
||||
void reportStaging() {
|
||||
auto& stats = Copies();
|
||||
const auto nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
@@ -5207,6 +5239,24 @@ bool GuestBufferMemory::bindableInPlace(std::uint64_t offset, bool addressable)
|
||||
}
|
||||
|
||||
bool GuestBufferMemory::stagingEligible(const Region& region, bool addressable) const {
|
||||
return !region.adaptiveInPlace && stagingWanted(region, addressable);
|
||||
}
|
||||
|
||||
bool GuestBufferMemory::adaptiveInPlace(const Region& region, bool use) const {
|
||||
if (!region.swept || region.atomic || region.overlay) return false;
|
||||
return AdaptiveStagingGate::Get().InPlace(region.begin, region.end, use);
|
||||
}
|
||||
|
||||
bool GuestBufferMemory::StagingDecisionsCurrent() const {
|
||||
if (!AdaptiveStagingGate::Enabled()) return true;
|
||||
for (const auto& region : regions) {
|
||||
if (!(region.gpuCopy && region.deviceLocal) && !region.adaptiveInPlace) continue;
|
||||
if (adaptiveInPlace(region, true) != region.adaptiveInPlace) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuestBufferMemory::stagingWanted(const Region& region, bool addressable) const {
|
||||
if (!stagingAllowed || (addressable && !region.overlay) || region.unstaged || !gpuCopiesEnabled() || region.sparse || region.mirror != nullptr) return false;
|
||||
const auto bytes = region.end - region.begin;
|
||||
if (!WritesOverlap(region.begin, static_cast<std::size_t>(bytes))) return false;
|
||||
@@ -5378,6 +5428,7 @@ void GuestBufferMemory::UploadPrepare(bool addressable) {
|
||||
// staged region (see stagingEligible) takes the same path, aligned or not, with a
|
||||
// device-local buffer that the CPU fallback replaces (none without a recorder to
|
||||
// record the copies: UploadFinish then binds the region in place).
|
||||
region.adaptiveInPlace = Recorder::Active() != nullptr && stagingWanted(region, addressable) && adaptiveInPlace(region, true);
|
||||
bool staged = Recorder::Active() != nullptr && stagingEligible(region, addressable);
|
||||
const bool misaligned = !bindableInPlace(HostImportOffset(*entry, region.begin), addressable);
|
||||
if (staged) {
|
||||
@@ -5442,7 +5493,7 @@ void GuestBufferMemory::completeSpaceWrites() const {
|
||||
}
|
||||
}
|
||||
|
||||
void GuestBufferMemory::UploadFinish(bool addressable) {
|
||||
void GuestBufferMemory::UploadFinish(bool addressable, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear) {
|
||||
Require(prepared && !uploaded, "guest memory upload was not prepared");
|
||||
static const bool profile = std::getenv("APS5_PROFILE_DRAW") != nullptr;
|
||||
const auto started = std::chrono::steady_clock::now();
|
||||
@@ -5450,7 +5501,7 @@ void GuestBufferMemory::UploadFinish(bool addressable) {
|
||||
if (space != nullptr) completeSpaceWrites();
|
||||
uploaded = true;
|
||||
for (const auto& region : regions) static_cast<void>(FlushDepthPlanes(region.begin, static_cast<std::size_t>(region.end - region.begin)));
|
||||
for (const auto& [begin, end] : writes) RequireNoResidentDepthRead_nid_no_patch(begin, static_cast<std::size_t>(end - begin));
|
||||
for (const auto& [begin, end] : writes) RequireNoResidentDepthRead_nid_no_patch(begin, static_cast<std::size_t>(end - begin), htileClear);
|
||||
for (const auto& [begin, end] : writes) StorageTexture::FlushPending(begin, static_cast<std::size_t>(end - begin), nullptr, "written buffer range");
|
||||
if (context.hostImportAlignment != 0) {
|
||||
auto& state = Imports();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "prx/libSceAgcDriver/Execution/include/Mutex.hpp"
|
||||
#include "prx/libc/include/HostThreadLocal.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Recorder.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp"
|
||||
#include "prx/libkernel/Time/include/SleepWake.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Resources.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/RuntimeSwitches.hpp"
|
||||
@@ -1190,6 +1191,7 @@ Recorder::~Recorder() {
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "[gpu] recorder teardown: %s\n", error.what());
|
||||
}
|
||||
ForgetHtileMasks_nid_no_patch(id);
|
||||
progressWatcher.reset();
|
||||
holdKept.clear();
|
||||
if (activeRecorder == this) {
|
||||
@@ -1854,6 +1856,9 @@ std::atomic<std::int64_t> traceBarriersLeft{[] {
|
||||
}()};
|
||||
std::atomic<std::uint64_t> timingPresents{0};
|
||||
std::atomic<std::uint64_t> presentSerial{0};
|
||||
std::atomic<std::uint64_t> settledFrames{0};
|
||||
std::atomic<std::uint64_t> settledFrameBusyNs{0};
|
||||
std::atomic<bool> batchStampsRequested{false};
|
||||
std::atomic<std::uint64_t> timingDropped{0};
|
||||
struct TimingTotals { std::uint64_t count = 0; double ms = 0; std::uint64_t bytes = 0; };
|
||||
AgcDriver::Mutex timingMutex;
|
||||
@@ -1919,7 +1924,7 @@ bool Recorder::GpuTimingEnabled() {
|
||||
}
|
||||
|
||||
bool Recorder::BatchStampsEnabled() {
|
||||
return GpuTimingEnabled() || DrawProfiled() || PerformanceTrace::Configured();
|
||||
return GpuTimingEnabled() || DrawProfiled() || PerformanceTrace::Configured() || batchStampsRequested.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void Recorder::CountBarriers(CommandClass which, std::uint32_t count) {
|
||||
@@ -2004,6 +2009,20 @@ std::uint64_t Recorder::Presents() {
|
||||
return presentSerial.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void Recorder::NoteFrameGpuBusy(double milliseconds) {
|
||||
settledFrameBusyNs.fetch_add(static_cast<std::uint64_t>(milliseconds * 1e6), std::memory_order_relaxed);
|
||||
settledFrames.fetch_add(1, std::memory_order_release);
|
||||
}
|
||||
|
||||
std::pair<std::uint64_t, double> Recorder::FrameGpuBusy() {
|
||||
const auto frames = settledFrames.load(std::memory_order_acquire);
|
||||
return {frames, static_cast<double>(settledFrameBusyNs.load(std::memory_order_relaxed)) / 1e6};
|
||||
}
|
||||
|
||||
void Recorder::RequestBatchStamps() {
|
||||
batchStampsRequested.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void Recorder::AddGpuTiming(CommandClass which, double nanoseconds, std::uint64_t bytes) {
|
||||
std::lock_guard lock(timingMutex);
|
||||
auto& totals = timingByKey[ClassKey(which)];
|
||||
|
||||
@@ -1670,7 +1670,7 @@ bool UsesAddressTables(const CompiledShader& compute) {
|
||||
|
||||
}
|
||||
|
||||
ShaderResources::ShaderResources(const Context& context, const CompiledShader& compute, std::span<const GuestMemorySnapshot> snapshots, bool deferred, std::uint64_t dispatchThreads) : context(context), guestMemory(context), dispatchThreads(dispatchThreads), deferredCompute(compute), deferredSnapshots(snapshots) {
|
||||
ShaderResources::ShaderResources(const Context& context, const CompiledShader& compute, std::span<const GuestMemorySnapshot> snapshots, bool deferred, std::uint64_t dispatchThreads, std::optional<std::pair<std::uint64_t, std::size_t>> htileClear) : context(context), guestMemory(context), dispatchThreads(dispatchThreads), htileClear(htileClear), deferredCompute(compute), deferredSnapshots(snapshots) {
|
||||
Require(compute.stage == ShaderRecompiler::ShaderStage::Compute, "compute resources require a compute shader");
|
||||
// Every use of a compute build is a recorded dispatch that calls MarkGpuWrites, which staged
|
||||
// buffers need (a synchronous draw's use would not).
|
||||
@@ -2448,7 +2448,7 @@ void ShaderResources::buildComplete() {
|
||||
resolveImageTables();
|
||||
timing.bindingsMs += phase(BuildPhase::Images);
|
||||
requireGuestBuffers();
|
||||
guestMemory.UploadFinish(usesBda);
|
||||
guestMemory.UploadFinish(usesBda, htileClear);
|
||||
timing.uploadMs += phase(BuildPhase::Upload);
|
||||
if (usesBda) bda = std::make_unique<BdaResources>(context, guestMemory);
|
||||
else if (usesFaultBuffer) bda = std::make_unique<BdaResources>(context);
|
||||
@@ -2652,7 +2652,7 @@ void ShaderResources::noteReusable() {
|
||||
captureValidation();
|
||||
reusable = false;
|
||||
directRegions.clear();
|
||||
if (guestMemory.HasCopiedWrites() || HoldsLease() || usesBda || !multisampleSources.empty() || (bda != nullptr && LoopGuardEnabled())) return;
|
||||
if (htileClear.has_value() || guestMemory.HasCopiedWrites() || HoldsLease() || usesBda || !multisampleSources.empty() || (bda != nullptr && LoopGuardEnabled())) return;
|
||||
if (std::any_of(textures.begin(), textures.end(), [](const std::shared_ptr<Texture>& texture) { return texture != nullptr && texture->RefreshedPerUse(); })) return;
|
||||
if (TemplateDataRefresh() && std::any_of(allocations.begin(), allocations.end(), [](const Allocation& allocation) { return allocation.buffer != nullptr && !allocation.guest && allocation.role != ShaderRecompiler::DescriptorRole::ImageTableMap && allocation.size > MaxRefreshBytes; })) return;
|
||||
const auto regions = guestMemory.DirectRegions();
|
||||
@@ -3819,6 +3819,7 @@ bool ShaderResources::revalidateFull(std::span<const CompiledShader> shaders, Pr
|
||||
// (3) Buffers staged in device memory (GuestBufferMemory::AllowDeviceStaging) are copied in
|
||||
// from their imports anew for this use, after the flushes above and before the work is
|
||||
// recorded; a failure to record leaves the object unusable for this dispatch, not the batch.
|
||||
if (!guestMemory.StagingDecisionsCurrent()) return finish(fast, false, ProofFailure::Changed);
|
||||
if (auto* recorder = Recorder::Active(); recorder != nullptr) {
|
||||
try {
|
||||
guestMemory.RecordStagingCopies(*recorder);
|
||||
@@ -5910,7 +5911,8 @@ void ShaderResources::requireGuestBuffers(std::span<const MovedBuffer> moved) co
|
||||
const auto override = std::find_if(moved.begin(), moved.end(), [&](const MovedBuffer& entry) { return entry.allocation == index; });
|
||||
const auto address = override != moved.end() ? override->address : item.address;
|
||||
const auto bytes = override != moved.end() ? override->size : item.size;
|
||||
RequireNoMultisampleTarget(address, bytes, "a shader buffer access");
|
||||
RequireNoResidentDepthRead_nid_no_patch(address, bytes, htileClear);
|
||||
RequireNoMultisampleColorTarget(address, bytes, "a shader buffer access");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ struct Module {
|
||||
return;
|
||||
}
|
||||
// One gl_ClipDistance array holds the guest clip distances and the recompiler's all-zero position distance.
|
||||
if (!input && ((value == spv::BuiltInClipDistance && (vertex || stage == Stage::TessellationControl || stage == Stage::TessellationEvaluation || stage == Stage::Mesh)) || (value == spv::BuiltInCullDistance && (vertex || stage == Stage::Mesh)))) {
|
||||
if (!input && ((value == spv::BuiltInClipDistance && (vertex || stage == Stage::TessellationControl || stage == Stage::TessellationEvaluation || stage == Stage::Mesh)) || (value == spv::BuiltInCullDistance && (vertex || stage == Stage::TessellationEvaluation || stage == Stage::Mesh)))) {
|
||||
const auto signature = Signature(type);
|
||||
auto& count = value == spv::BuiltInClipDistance ? clipDistances : cullDistances;
|
||||
Require(count == 0 && signature.size() == 6 && signature.starts_with("f32[") && signature[4] >= '1' && signature[4] <= '8' && signature[5] == ']', "invalid or duplicate clip or cull distance output");
|
||||
@@ -273,7 +273,7 @@ Module Inspect(const CompiledShader& compiled, const State& state, const VkPhysi
|
||||
if ((vertex || control || evaluation || mesh) && (capability == spv::CapabilityClipDistance || capability == spv::CapabilityCullDistance)) {
|
||||
char word[16];
|
||||
std::snprintf(word, sizeof(word), "0x%08x", state.paClVsOutCntl);
|
||||
Require(capability == spv::CapabilityClipDistance ? shaderClipDistance : (vertex || mesh) && shaderCullDistance, std::string("vertex clip or cull distance needs shaderClipDistance or shaderCullDistance, which the device lacks (PA_CL_VS_OUT_CNTL=") + word + ")");
|
||||
Require(capability == spv::CapabilityClipDistance ? shaderClipDistance : (vertex || evaluation || mesh) && shaderCullDistance, std::string("vertex clip or cull distance needs shaderClipDistance or shaderCullDistance, which the device lacks (PA_CL_VS_OUT_CNTL=") + word + ")");
|
||||
}
|
||||
|
||||
// Enabled unconditionally or by the device setup in VulkanDevice.
|
||||
@@ -289,7 +289,7 @@ Module Inspect(const CompiledShader& compiled, const State& state, const VkPhysi
|
||||
(fragment && sampleRateShading && capability == spv::CapabilityInterpolationFunction) ||
|
||||
capability == spv::CapabilityImageMSArray ||
|
||||
capability == spv::CapabilityStorageImageMultisample ||
|
||||
((vertex || mesh) && shaderCullDistance && capability == spv::CapabilityCullDistance) ||
|
||||
((vertex || evaluation || mesh) && shaderCullDistance && capability == spv::CapabilityCullDistance) ||
|
||||
capability == spv::CapabilityStorageImageWriteWithoutFormat ||
|
||||
capability == spv::CapabilityStorageImageReadWithoutFormat ||
|
||||
capability == spv::CapabilityInt64 ||
|
||||
|
||||
@@ -11,6 +11,7 @@ constexpr int DEBUG_UNAVAILABLE = static_cast<int>(0x8A6C1000);
|
||||
constexpr int DRIVER_FEATURE_UNAVAILABLE = static_cast<int>(0x8A6D0001);
|
||||
constexpr int DRIVER_NULL_OUTPUT = static_cast<int>(0x8A6D0003);
|
||||
constexpr int GPU_RESET_UNAVAILABLE = static_cast<int>(0x8A6C0045);
|
||||
constexpr int MODULE_REGISTRATION_FAILED = static_cast<int>(0x8A6D0003);
|
||||
constexpr std::size_t TOOL_MEMORY_RANGE_SIZE = 12;
|
||||
|
||||
}
|
||||
@@ -193,6 +194,34 @@ int APS5_VABI sceAgcDriverSetTargetRingForDiag() {
|
||||
return DRIVER_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverAcquireRazorACQ() {
|
||||
return DRIVER_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverGetPaDebugInterfaceVersion() {
|
||||
return DRIVER_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSetHsOffchipParamDirect() {
|
||||
return DRIVER_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSubmitMultiCommandBuffersDirect() {
|
||||
return DRIVER_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSubmitToRazorACQ() {
|
||||
return DRIVER_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSuspendPointSubmitDirect() {
|
||||
return DRIVER_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverModuleRegistration() {
|
||||
return MODULE_REGISTRATION_FAILED;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSetValueToSharedGds() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#include "prx/libSceAgcDriver/Graphics/include/AdaptiveStaging.hpp"
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::AdaptiveStaging;
|
||||
|
||||
void Require(bool condition, const std::string& message) {
|
||||
if (!condition) throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
constexpr std::uint64_t Begin = 0x200000000;
|
||||
constexpr std::uint64_t End = Begin + 0xca80000;
|
||||
constexpr std::int64_t FrameMs = 100;
|
||||
|
||||
struct Title {
|
||||
AdaptiveStaging policy;
|
||||
std::vector<std::string> lines;
|
||||
std::uint64_t frames = 0;
|
||||
double busyMs = 0;
|
||||
std::int64_t nowMs = 1;
|
||||
|
||||
Title() {
|
||||
policy.report = [this](const std::string& line) { lines.push_back(line); };
|
||||
}
|
||||
|
||||
std::uint64_t Run(std::uint64_t count, const std::function<double(bool, std::int64_t)>& cost) {
|
||||
std::uint64_t inPlace = 0;
|
||||
for (std::uint64_t frame = 0; frame < count; ++frame) {
|
||||
const bool kept = policy.InPlace(Begin, End, true, frames, busyMs, nowMs);
|
||||
inPlace += kept ? 1 : 0;
|
||||
busyMs += cost(kept, nowMs);
|
||||
++frames;
|
||||
nowMs += FrameMs;
|
||||
}
|
||||
return inPlace;
|
||||
}
|
||||
|
||||
bool InPlaceNow() {
|
||||
return policy.InPlace(Begin, End, false, frames, busyMs, nowMs);
|
||||
}
|
||||
|
||||
std::uint64_t Count(const std::string& text) const {
|
||||
std::uint64_t count = 0;
|
||||
for (const auto& line : lines) count += line.find(text) != std::string::npos ? 1 : 0;
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
void CheckFasterInPlaceIsKept() {
|
||||
Title title;
|
||||
title.Run(200, [](bool inPlace, std::int64_t) { return inPlace ? 73.0 : 91.0; });
|
||||
Require(title.InPlaceNow(), "an element 18 ms faster per frame in place is still staged");
|
||||
Require(title.Count("-> in place") >= 1, "no decision line chose in place");
|
||||
}
|
||||
|
||||
void CheckFasterStagedStaysStaged() {
|
||||
Title title;
|
||||
title.Run(200, [](bool inPlace, std::int64_t) { return inPlace ? 114.0 : 84.0; });
|
||||
Require(!title.InPlaceNow(), "an element 30 ms faster per frame staged was moved in place");
|
||||
Require(title.Count("-> staged") >= 1, "no decision line kept it staged");
|
||||
}
|
||||
|
||||
void CheckNoiseKeepsTheMode() {
|
||||
Title title;
|
||||
std::uint64_t frame = 0;
|
||||
const auto inPlace = title.Run(3000, [&](bool, std::int64_t) { return 80.0 + static_cast<double>((frame++ * 7) % 11) - 5.0; });
|
||||
Require(title.Count("-> in place") == 0, "frame noise alone moved the element in place");
|
||||
Require(inPlace < 3000 / 4, "frame noise kept the element in place for " + std::to_string(inPlace) + " of 3000 frames");
|
||||
}
|
||||
|
||||
void CheckBackOffGrowsToTheCap() {
|
||||
Title title;
|
||||
title.Run(6000, [](bool inPlace, std::int64_t) { return inPlace ? 114.0 : 84.0; });
|
||||
Require(title.Count("next probe in 40 s") >= 1, "the second repeated answer did not wait 40 s");
|
||||
Require(title.Count("next probe in 160 s") >= 1, "the back-off never reached 160 s");
|
||||
Require(title.Count("next probe in 320 s") == 0, "the back-off grew past 160 s");
|
||||
}
|
||||
|
||||
void CheckSceneChangeProbesAgain() {
|
||||
Title title;
|
||||
const std::int64_t changeMs = 60000;
|
||||
const auto cost = [&](bool inPlace, std::int64_t nowMs) {
|
||||
if (nowMs < changeMs) return inPlace ? 73.0 : 91.0;
|
||||
return inPlace ? 300.0 : 200.0;
|
||||
};
|
||||
title.Run(600, cost);
|
||||
Require(title.InPlaceNow(), "the first scene did not keep the element in place");
|
||||
title.Run(400, cost);
|
||||
Require(title.Count("probing again") >= 1, "a scene change from 73 to about 300 ms per frame did not probe again");
|
||||
Require(!title.InPlaceNow(), "after the scene change the element is still in place although staged is faster");
|
||||
}
|
||||
|
||||
void CheckSmallElementIsNotProbed() {
|
||||
AdaptiveStaging policy;
|
||||
std::uint64_t frames = 0;
|
||||
double busyMs = 0;
|
||||
std::int64_t nowMs = 1;
|
||||
constexpr std::uint64_t SmallBegin = 0x100000000;
|
||||
constexpr std::uint64_t SmallEnd = SmallBegin + 0x10000;
|
||||
bool smallInPlace = false;
|
||||
for (int frame = 0; frame < 2000; ++frame) {
|
||||
const bool bigInPlace = policy.InPlace(Begin, End, true, frames, busyMs, nowMs);
|
||||
smallInPlace = smallInPlace || policy.InPlace(SmallBegin, SmallEnd, true, frames, busyMs, nowMs);
|
||||
busyMs += bigInPlace ? 73.0 : 91.0;
|
||||
++frames;
|
||||
nowMs += FrameMs;
|
||||
}
|
||||
Require(!smallInPlace, "a 64 KiB element next to a 202 MiB one was probed in place");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
CheckFasterInPlaceIsKept();
|
||||
CheckFasterStagedStaysStaged();
|
||||
CheckNoiseKeepsTheMode();
|
||||
CheckBackOffGrowsToTheCap();
|
||||
CheckSceneChangeProbesAgain();
|
||||
CheckSmallElementIsNotProbed();
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
std::cout << "adaptive staging tests passed\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "ControlFlow/ControlFlowHelpers.hpp"
|
||||
#include "ControlFlow/GraphBuilder.hpp"
|
||||
#include "ControlFlow/RequestSerializer.hpp"
|
||||
#include "ControlFlow/Structurizer.hpp"
|
||||
@@ -174,6 +175,17 @@ ControlFlowGraph makeGraph(const std::vector<std::vector<std::uint32_t>>& succes
|
||||
return graph;
|
||||
}
|
||||
|
||||
void verifyPredecessorRebuild() {
|
||||
auto graph = makeGraph({{2, 1, 2}, {2, 2}, {2}, {}});
|
||||
for (auto& block : graph.blocks) block.predecessors = {3u, 3u};
|
||||
const std::vector<std::vector<std::uint32_t>> expected{{}, {0u}, {0u, 1u, 2u}, {}};
|
||||
for (unsigned repeat = 0; repeat < 2u; ++repeat) {
|
||||
rebuildPredecessors(graph);
|
||||
require(graph.blocks[0].successors == std::vector<std::uint32_t>{1u, 2u} && graph.blocks[1].successors == std::vector<std::uint32_t>{2u}, "predecessor rebuild lost successor normalization");
|
||||
for (std::size_t index = 0; index < expected.size(); ++index) require(graph.blocks[index].predecessors == expected[index], "predecessor rebuild changed the incoming edges");
|
||||
}
|
||||
}
|
||||
|
||||
void verifyLoopMergeDoesNotEnterNestedSelection() {
|
||||
auto graph = makeGraph({{1, 5}, {2, 3}, {5}, {5, 4}, {1}, {}});
|
||||
Structurizer{}.Structurize(graph);
|
||||
@@ -1445,6 +1457,7 @@ done:
|
||||
}
|
||||
}
|
||||
try {
|
||||
verifyPredecessorRebuild();
|
||||
verifyNullSwappc();
|
||||
verifyScheduledJumpTable();
|
||||
VerifyUserDataTail();
|
||||
|
||||
@@ -2785,6 +2785,48 @@ void multisampledSingleClearTests() {
|
||||
Require(!match(std::span(kernel).first(21), userData, group), "a truncated kernel was taken for RADV's comp-to-single clear");
|
||||
}
|
||||
|
||||
void htileBufferMaskClearTests() {
|
||||
static constexpr std::array<std::uint32_t, 16> kernel{0xd7460004u, 0x04010c0cu, 0xe00c2000u, 0x80000004u, 0xbf8c3f70u, 0xd7710000u, 0x00120008u, 0xd7710001u, 0x00160209u, 0xd7710002u, 0x001a040au, 0xd7710003u, 0x001e060bu, 0xe01c2000u, 0x80000004u, 0xbf810000u};
|
||||
ShaderRecompiler::ShaderComputeStageInfo compute{};
|
||||
compute.numThreads = {64u, 1u, 1u};
|
||||
compute.groupIdEnable = {true, false, false};
|
||||
compute.threadIdComponentCount = 1u;
|
||||
const std::array<std::uint32_t, 12> userData{0x8e350000u, 0x00100050u, 0x00004000u, 0x0004bfacu, 0u, 0u, 0u, 0u, 0x3f0u, 0x3f0u, 0x3f0u, 0x3f0u};
|
||||
const std::array<std::uint32_t, 5> packet{0u, 0x4000u, 1u, 1u, 0x61u};
|
||||
const auto match = [&](std::span<const std::uint32_t> code, std::span<const std::uint32_t> words, const ShaderRecompiler::ShaderComputeStageInfo& info, std::span<const std::uint32_t> dispatch, std::uint64_t indirect) {
|
||||
return AgcDriver::Graphics::MatchHtileBufferMaskClear(code, words, info, dispatch, indirect);
|
||||
};
|
||||
const auto found = match(kernel, userData, compute, packet, 0);
|
||||
Require(found.has_value() && found->address == 0x508e350000ull && found->bytes == 0x40000u && found->mask == 0x3f0u && found->value == 0u, "the buffer variant of the HTILE mask kernel was not recognized with its range, mask and value");
|
||||
auto groups = packet;
|
||||
groups[4] = 0x41u;
|
||||
groups[1] = 0x100u;
|
||||
const auto byGroups = match(kernel, userData, compute, groups, 0);
|
||||
Require(byGroups.has_value() && byGroups->bytes == 0x40000u, "a group-count dispatch of the buffer HTILE kernel did not cover 0x100 groups of 64 records");
|
||||
groups[1] = 0x80u;
|
||||
Require(match(kernel, userData, compute, groups, 0)->bytes == 0x20000u, "fewer threads than records did not limit the buffer HTILE kernel's range");
|
||||
auto other = kernel;
|
||||
other[6] ^= 1u;
|
||||
Require(!match(other, userData, compute, packet, 0).has_value(), "another kernel was taken for the buffer HTILE mask kernel");
|
||||
Require(!match(std::span(kernel).first(15), userData, compute, packet, 0).has_value(), "a truncated kernel was taken for the buffer HTILE mask kernel");
|
||||
auto mixed = userData;
|
||||
mixed[10] = 0x3ffu;
|
||||
Require(!match(kernel, mixed, compute, packet, 0).has_value(), "a buffer HTILE kernel with per-word masks was recognized");
|
||||
auto format = userData;
|
||||
format[3] = 0x0004dfacu;
|
||||
Require(!match(kernel, format, compute, packet, 0).has_value(), "a buffer HTILE kernel through a float descriptor was recognized");
|
||||
auto stride = userData;
|
||||
stride[1] = 0x00080050u;
|
||||
Require(!match(kernel, stride, compute, packet, 0).has_value(), "a buffer HTILE kernel with an 8-byte stride was recognized");
|
||||
auto wave32 = compute;
|
||||
wave32.numThreads = {32u, 1u, 1u};
|
||||
Require(!match(kernel, userData, wave32, packet, 0).has_value(), "the buffer HTILE kernel matched with another group size");
|
||||
Require(!match(kernel, userData, compute, packet, 0x1000u).has_value(), "an indirect buffer HTILE kernel dispatch was recognized");
|
||||
auto partial = packet;
|
||||
partial[4] = 0x63u;
|
||||
Require(!match(kernel, userData, compute, partial, 0).has_value(), "a partial-group buffer HTILE kernel dispatch was recognized");
|
||||
}
|
||||
|
||||
void htileDepthClearTests() {
|
||||
static constexpr std::array<std::uint32_t, 17> kernel{0xd7460000u, 0x04010c06u, 0x34000084u, 0xdc388000u, 0x04020000u, 0xbf8c3f70u, 0xd7710008u, 0x00120805u, 0xd7710009u, 0x00120a05u, 0xd771000au, 0x00120c05u, 0xd771000bu, 0x00120e05u, 0xdc788000u, 0x00020800u, 0xbf810000u};
|
||||
const std::array<std::uint32_t, 3> wave{64, 1, 1};
|
||||
@@ -7557,6 +7599,7 @@ struct ModuleShape {
|
||||
std::uint32_t floatControlsWidth = 0;
|
||||
std::uint32_t clipDistanceLength = 0;
|
||||
std::uint32_t cullDistanceLength = 0;
|
||||
std::optional<spv::ExecutionModel> tessellationModel;
|
||||
bool layerOutput = false;
|
||||
bool terminateInvocation = false;
|
||||
bool omitTerminateExtension = false;
|
||||
@@ -7762,6 +7805,7 @@ std::vector<std::uint32_t> makeModule(const ModuleShape& shape) {
|
||||
if (shape.layer) emit(words, spv::OpCapability, {spv::CapabilityGeometry});
|
||||
if (shape.clipDistanceLength != 0) emit(words, spv::OpCapability, {spv::CapabilityClipDistance});
|
||||
if (shape.cullDistanceLength != 0) emit(words, spv::OpCapability, {spv::CapabilityCullDistance});
|
||||
if (shape.tessellationModel) emit(words, spv::OpCapability, {spv::CapabilityTessellation});
|
||||
if (shape.layerOutput) {
|
||||
emit(words, spv::OpCapability, {spv::CapabilityShaderViewportIndexLayerEXT});
|
||||
const std::string extension = "SPV_EXT_shader_viewport_index_layer";
|
||||
@@ -7791,10 +7835,14 @@ std::vector<std::uint32_t> makeModule(const ModuleShape& shape) {
|
||||
emit(words, spv::OpMemoryModel, {spv::AddressingModelLogical, spv::MemoryModelGLSL450});
|
||||
const auto entryPointOffset = words.size();
|
||||
if (shape.vertexInput) emit(words, spv::OpEntryPoint, {spv::ExecutionModelVertex, main, 0x6e69616du, 0, output, input});
|
||||
else emit(words, spv::OpEntryPoint, {shape.fragment ? spv::ExecutionModelFragment : spv::ExecutionModelVertex, main, 0x6e69616du, 0, output});
|
||||
else emit(words, spv::OpEntryPoint, {shape.tessellationModel ? *shape.tessellationModel : shape.fragment ? spv::ExecutionModelFragment : spv::ExecutionModelVertex, main, 0x6e69616du, 0, output});
|
||||
words[entryPointOffset] += static_cast<std::uint32_t>(extraInterface.size()) << 16u;
|
||||
words.insert(words.end(), extraInterface.begin(), extraInterface.end());
|
||||
if (shape.fragmentMode) emit(words, spv::OpExecutionMode, {main, *shape.fragmentMode});
|
||||
if (shape.tessellationModel == spv::ExecutionModelTessellationControl) emit(words, spv::OpExecutionMode, {main, spv::ExecutionModeOutputVertices, 3});
|
||||
if (shape.tessellationModel == spv::ExecutionModelTessellationEvaluation) {
|
||||
for (const auto mode : {spv::ExecutionModeQuads, spv::ExecutionModeSpacingFractionalOdd, spv::ExecutionModeVertexOrderCw}) emit(words, spv::OpExecutionMode, {main, mode});
|
||||
}
|
||||
if (shape.fragment) emit(words, spv::OpExecutionMode, {main, spv::ExecutionModeOriginUpperLeft});
|
||||
if (shape.fragDepth) emit(words, spv::OpExecutionMode, {main, spv::ExecutionModeDepthReplacing});
|
||||
if (shape.floatControlsWidth != 0) {
|
||||
@@ -8732,6 +8780,23 @@ void barycentricEmulationTests() {
|
||||
const std::array<CompiledShader, 4> flatPatchShaders{{{ShaderStage::Vertex, &vertex, 0}, {ShaderStage::TessellationControl, &patches.control, 0}, {ShaderStage::TessellationEvaluation, &patches.evaluation, 0}, {ShaderStage::Fragment, &flatVertices, 0}}};
|
||||
expectFailure([&] { ValidateProvokingVertex(context, lastState, flatPatchShaders); }, "explicit per-vertex flat interpolation");
|
||||
}
|
||||
{
|
||||
const auto context = mockContext();
|
||||
auto namedVertex = vertex;
|
||||
namedVertex.variantId = 11u;
|
||||
auto namedFragment = fragment;
|
||||
namedFragment.variantId = 12u;
|
||||
const std::array<CompiledShader, 4> namedPatchShaders{{{ShaderStage::Vertex, &namedVertex, 0}, {ShaderStage::TessellationControl, &patches.control, 0}, {ShaderStage::TessellationEvaluation, &patches.evaluation, 0}, {ShaderStage::Fragment, &namedFragment, 0}}};
|
||||
auto lastState = state;
|
||||
lastState.provokingVertexMode = VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
|
||||
std::vector<std::uint64_t> firstKey;
|
||||
std::vector<std::uint64_t> lastKey;
|
||||
Require(ValidationKey(context, namedPatchShaders, state, firstKey) && ValidationKey(context, namedPatchShaders, lastState, lastKey), "a draw through generated barycentric tessellation stages skipped the shader validation memo");
|
||||
Require(firstKey != lastKey, "the shader validation memo did not tell barycentric patches built for different provoking vertices apart");
|
||||
const std::array<CompiledShader, 4> unnamedPatchShaders{{{ShaderStage::Vertex, &vertex, 0}, {ShaderStage::TessellationControl, &patches.control, 0}, {ShaderStage::TessellationEvaluation, &patches.evaluation, 0}, {ShaderStage::Fragment, &namedFragment, 0}}};
|
||||
std::vector<std::uint64_t> unnamedKey;
|
||||
Require(!ValidationKey(context, unnamedPatchShaders, state, unnamedKey), "a vertex stage without a variant id entered the shader validation memo");
|
||||
}
|
||||
|
||||
RecompileResult clipped;
|
||||
clipped.spirv = makeModule({.parameterOutput = true, .clipDistanceLength = 2});
|
||||
@@ -11170,6 +11235,16 @@ void validationTests() {
|
||||
vertex.spirv = makeModule({.parameterOutput = true, .cullDistanceLength = 4});
|
||||
expectFailure([&] { AgcDriver::Graphics::ValidateShaders(shaders, state, subgroup, false, false, false, false, false, false, true, false); }, "PA_CL_VS_OUT_CNTL=0x0040000f");
|
||||
AgcDriver::Graphics::ValidateShaders(shaders, state, subgroup, false, false, false, false, false, false, false, true);
|
||||
ShaderRecompiler::RecompileResult tessVertex, tessControl, tessEvaluation;
|
||||
tessVertex.spirv = makeModule({});
|
||||
tessControl.spirv = makeModule({.push = true, .tessellationModel = spv::ExecutionModelTessellationControl});
|
||||
tessEvaluation.spirv = makeModule({.cullDistanceLength = 4, .tessellationModel = spv::ExecutionModelTessellationEvaluation});
|
||||
const std::array<AgcDriver::Graphics::CompiledShader, 4> tessShaders{{{ShaderRecompiler::ShaderStage::Local, &tessVertex, 0}, {ShaderRecompiler::ShaderStage::TessellationControl, &tessControl, 0}, {ShaderRecompiler::ShaderStage::TessellationEvaluation, &tessEvaluation, 0}, {ShaderRecompiler::ShaderStage::Fragment, &pixel, 0}}};
|
||||
auto tessState = state;
|
||||
tessState.stages.path = AgcDriver::Graphics::ShaderPath::Tessellation;
|
||||
tessState.stages.tessellation = ShaderRecompiler::TessellationConfiguration{3, 3, 2, 1, 4, 128, 16, false};
|
||||
AgcDriver::Graphics::ValidateShaders(tessShaders, tessState, subgroup, false, false, false, false, false, false, false, true);
|
||||
expectFailure([&] { AgcDriver::Graphics::ValidateShaders(tessShaders, tessState, subgroup, false, false, false, false, false, false, true, false); }, "PA_CL_VS_OUT_CNTL=0x0040000f");
|
||||
state.paClVsOutCntl = 0;
|
||||
vertex.spirv = makeModule({.parameterOutput = true, .clipDistanceLength = 9});
|
||||
expectFailure([&] { AgcDriver::Graphics::ValidateShaders(shaders, state, subgroup, false, false, false, false, false, false, true, true); }, "clip or cull distance");
|
||||
@@ -12874,6 +12949,7 @@ int main(int argc, char** argv) {
|
||||
OneDimensionalColorTests();
|
||||
htileDepthClearTests();
|
||||
multisampledSingleClearTests();
|
||||
htileBufferMaskClearTests();
|
||||
memoryValueFillTests();
|
||||
ZExportTests();
|
||||
unorm10_11_11TargetTests();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "IntermediateRepresentation/IrProgram.hpp"
|
||||
#include "Optimization/ShaderStageInputInfo.hpp"
|
||||
#include "SpirvBackend/SpirvEmitter.hpp"
|
||||
#include "SpirvBackend/SpirvAnalysis.hpp"
|
||||
#include "PipelineSpecialization.hpp"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -30,12 +31,15 @@ struct LoadCase {
|
||||
IrType type;
|
||||
std::uint32_t bits = 32;
|
||||
std::uint32_t components = 1;
|
||||
IrShaderStage stage = IrShaderStage::Compute;
|
||||
bool coherent = true;
|
||||
bool written = false;
|
||||
};
|
||||
|
||||
std::vector<std::uint32_t> emitLoad(const LoadCase& test, bool active, std::uint32_t offset, std::uint32_t records, bool robust, bool exact = false, bool valid = true, bool coherent = true) {
|
||||
std::vector<std::uint32_t> emitLoad(const LoadCase& test, bool active, std::uint32_t offset, std::uint32_t records, bool robust, bool exact = false, bool valid = true) {
|
||||
IrProgram program;
|
||||
program.SetWaveSize(32);
|
||||
program.Resources().stage = IrShaderStage::Compute;
|
||||
program.Resources().stage = test.stage;
|
||||
program.Resources().srtPlanComplete = true;
|
||||
program.Resources().resourceTrackingComplete = true;
|
||||
program.Metadata().shaderInfoComplete = true;
|
||||
@@ -70,8 +74,9 @@ std::vector<std::uint32_t> emitLoad(const LoadCase& test, bool active, std::uint
|
||||
auto& handle = emit(IrOpcode::GetScratchResource, IrType::AddressResource, {});
|
||||
emit(test.opcode, test.type, {&handle, &address, &zero, &enabled});
|
||||
} else if (test.kind == ResourceKind::Buffer) {
|
||||
program.Resources().memoryInfo.front().coherent = coherent;
|
||||
program.Resources().memoryInfo.front().coherent = test.coherent;
|
||||
program.Info().buffers.emplace_back().read = true;
|
||||
program.Info().buffers.front().written = test.written;
|
||||
program.Metadata().bindings.descriptors.push_back({DescriptorBindingKind::Buffers, {0}});
|
||||
program.Metadata().bindings.pushDataStartDword = 0;
|
||||
program.Metadata().bindings.memoryOffsetCount = 1;
|
||||
@@ -92,7 +97,9 @@ std::vector<std::uint32_t> emitLoad(const LoadCase& test, bool active, std::uint
|
||||
compute.hostSubgroupSize = 32;
|
||||
compute.waveSize = 32;
|
||||
ShaderStageInputInfo inputs;
|
||||
inputs.compute = &compute;
|
||||
ShaderPixelInputInfo pixel;
|
||||
if (test.stage == IrShaderStage::Pixel) inputs.pixel = &pixel;
|
||||
else inputs.compute = &compute;
|
||||
CompiledBindingLayout bindings;
|
||||
bindings.layout = program.Metadata().bindings;
|
||||
SpirvTargetOptions target{};
|
||||
@@ -386,6 +393,52 @@ int main() {
|
||||
const auto plain = emitLoad(test, true, 8, 64, false, true);
|
||||
require(AccessTrace(plain, 0).Run() == std::vector<std::uint32_t>({2}), "exact request without robustBufferAccess2 changed the plain variant");
|
||||
});
|
||||
run("read-only pixel robust buffer result", [] {
|
||||
const auto selections = [](const std::vector<std::uint32_t>& module) {
|
||||
unsigned count = 0;
|
||||
for (std::size_t offset = 5; offset < module.size(); offset += module[offset] >> 16u) count += (module[offset] & 0xffffu) == spv::OpSelect;
|
||||
return count;
|
||||
};
|
||||
LoadCase test{ResourceKind::Buffer, IrOpcode::LoadBufferU32, IrType::U32, 32, 1, IrShaderStage::Pixel, false};
|
||||
for (const bool robust : {false, true}) {
|
||||
for (const bool exact : {false, true}) {
|
||||
const auto readOnly = selections(emitLoad(test, true, 8, 64, robust, exact));
|
||||
test.written = true;
|
||||
const auto writing = selections(emitLoad(test, true, 8, 64, robust, exact));
|
||||
require(writing == readOnly + (robust && !exact ? 1u : 0u), "only read-only robust pixel loads may omit the result selection");
|
||||
test.written = false;
|
||||
test.coherent = true;
|
||||
require(selections(emitLoad(test, true, 8, 64, robust, exact)) == readOnly, "coherent loads must retain the upstream volatile result folding");
|
||||
test.coherent = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
run("storage writers keep guarded results", [] {
|
||||
IrProgram program;
|
||||
program.Resources().stage = IrShaderStage::Pixel;
|
||||
require(AnalyzeProgramRequirements(program).readOnlyStorage, "read-only pixel program lost its storage proof");
|
||||
program.Resources().stage = IrShaderStage::Compute;
|
||||
require(!AnalyzeProgramRequirements(program).readOnlyStorage, "compute entry bookkeeping must keep result guards");
|
||||
program.Resources().stage = IrShaderStage::Pixel;
|
||||
program.Info().usesFaultBuffer = true;
|
||||
require(!AnalyzeProgramRequirements(program).readOnlyStorage, "fault-buffer writes must keep result guards");
|
||||
program.Info().usesFaultBuffer = false;
|
||||
program.Info().runtimeImageModes.emplace_back().emplace_back().targetMerge = true;
|
||||
require(!AnalyzeProgramRequirements(program).readOnlyStorage, "runtime target merge writes must keep result guards");
|
||||
program.Info().runtimeImageModes.clear();
|
||||
auto& block = program.CreateBlock();
|
||||
program.BlockOrder().push_back(&block);
|
||||
program.Resources().memoryInfo.emplace_back().kind = ResourceKind::Lds;
|
||||
auto& address = program.CreateValue(IrOpcode::Void, IrType::U32);
|
||||
address.SetImmediateU32(0u);
|
||||
auto& active = program.CreateValue(IrOpcode::Void, IrType::Bool);
|
||||
active.SetImmediateBool(true);
|
||||
auto& load = program.CreateValue(IrOpcode::LoadSharedU32, IrType::U32);
|
||||
load.AddArgument(&address);
|
||||
load.AddArgument(&active);
|
||||
block.AppendInstruction(&load);
|
||||
require(!AnalyzeProgramRequirements(program).readOnlyStorage, "read-only LDS may allocate storage and must keep result guards");
|
||||
});
|
||||
run("volatile robust buffer omits repeated zero selection", [] {
|
||||
const LoadCase test{ResourceKind::Buffer, IrOpcode::LoadBufferU32, IrType::U32};
|
||||
const auto selections = [](const std::vector<std::uint32_t>& module) {
|
||||
@@ -397,7 +450,9 @@ int main() {
|
||||
};
|
||||
for (const bool robust : {false, true}) {
|
||||
for (const bool exact : {false, true}) {
|
||||
const auto plain = emitLoad(test, true, 8, 64, robust, exact, true, false);
|
||||
auto plainTest = test;
|
||||
plainTest.coherent = false;
|
||||
const auto plain = emitLoad(plainTest, true, 8, 64, robust, exact);
|
||||
const auto coherent = emitLoad(test, true, 8, 64, robust, exact);
|
||||
require(selections(plain) == selections(coherent) + (robust && !exact ? 1u : 0u), "only volatile guarded robust loads may omit the repeated zero selection");
|
||||
}
|
||||
|
||||
@@ -402,6 +402,28 @@ int main() {
|
||||
return b.eliminate() == 1u && !readOtherwise.HasUses() && readHead.UseCount() == 2u && AllUsed({&readHead, &readThenAfterStore, &readMerge});
|
||||
});
|
||||
|
||||
passed &= run("a loop without a clobber reuses its dominating ReadConst", [] {
|
||||
Builder b;
|
||||
IrBlock& header = b.newBlock();
|
||||
IrBlock& body = b.newBlock();
|
||||
IrBlock& exit = b.newBlock();
|
||||
b.block->AddBranch(&header);
|
||||
header.AddBranch(&body);
|
||||
header.AddBranch(&exit);
|
||||
body.AddBranch(&header);
|
||||
auto& srt = b.emit(IrOpcode::GetSrtResource, IrType::SrtResource, {});
|
||||
auto& beforeLoop = b.emit(IrOpcode::ReadConst, IrType::U32, {&srt, &b.constant(0u)});
|
||||
b.keep(beforeLoop);
|
||||
std::vector<IrValue*> reads;
|
||||
for (auto* block : {&header, &body, &exit}) {
|
||||
b.block = block;
|
||||
auto& read = b.emit(IrOpcode::ReadConst, IrType::U32, {&srt, &b.constant(0u)});
|
||||
b.keep(read);
|
||||
reads.push_back(&read);
|
||||
}
|
||||
return b.eliminate() == 3u && beforeLoop.UseCount() == 4u && std::ranges::none_of(reads, [](const auto* read) { return read->HasUses(); });
|
||||
});
|
||||
|
||||
passed &= run("a store on a loop backedge prevents reusing a pre-loop ReadConst in the loop header", [] {
|
||||
Builder b;
|
||||
IrBlock& header = b.newBlock();
|
||||
|
||||
@@ -8215,11 +8215,18 @@ void verifyWaveUniformValues() {
|
||||
auto& fromGlobalLoad = emit(IrOpcode::IAdd32, IrType::U32, {&globalLoad, &uniformSum});
|
||||
auto& compare = emit(IrOpcode::ULessThan32, IrType::U1, {&laneSum, &userData});
|
||||
auto& ballot = emit(IrOpcode::Ballot, IrType::U32x4, {&compare});
|
||||
auto& uniformPhi = emit(IrOpcode::Phi, IrType::U32, {&userData});
|
||||
auto& uniformNext = emit(IrOpcode::IAdd32, IrType::U32, {&uniformPhi, &userData});
|
||||
uniformPhi.AddArgument(&uniformNext);
|
||||
auto& varyingPhi = emit(IrOpcode::Phi, IrType::U32, {&userData});
|
||||
auto& varyingNext = emit(IrOpcode::IAdd32, IrType::U32, {&varyingPhi, &lane});
|
||||
varyingPhi.AddArgument(&varyingNext);
|
||||
auto& fromVaryingPhi = emit(IrOpcode::IAdd32, IrType::U32, {&varyingPhi, &userData});
|
||||
const auto uniform = WaveUniformValues(program);
|
||||
for (const auto* value : {&userData, &uniformSum, &address, &scalarLoad, &fromScalarLoad, &ballot}) {
|
||||
for (const auto* value : {&userData, &uniformSum, &address, &scalarLoad, &fromScalarLoad, &ballot, &uniformPhi, &uniformNext}) {
|
||||
require(uniform.contains(value), "wave-uniform values: a value every lane of the wave computes alike was not found uniform");
|
||||
}
|
||||
for (const auto* value : {&lane, &laneSum, &laneOffsetLoad, &globalLoad, &fromGlobalLoad, &compare}) {
|
||||
for (const auto* value : {&lane, &laneSum, &laneOffsetLoad, &globalLoad, &fromGlobalLoad, &compare, &varyingPhi, &varyingNext, &fromVaryingPhi}) {
|
||||
require(!uniform.contains(value), "wave-uniform values: a value that may differ between lanes was found uniform");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +250,10 @@ void fillContractTests() {
|
||||
Require(FillDccClear(VK_FORMAT_B10G11R11_UFLOAT_PACK32, DccKeys::Clear1111, false, partial), "packed float fast clear was not encoded");
|
||||
const std::array<std::byte, 4> white{std::byte{0xc0}, std::byte{0x03}, std::byte{0x1e}, std::byte{0x78}};
|
||||
for (std::size_t index = 0; index < partial.size(); ++index) Require(partial[index] == (index < 8u ? white[index % 4u] : std::byte{0}), "a clear fill over a partial trailing element did not zero the tail");
|
||||
std::vector<std::byte> large(1003, std::byte{0x5a});
|
||||
Require(FillDccClear(VK_FORMAT_R16G16B16A16_SFLOAT, DccKeys::Clear1111, false, large), "half float fast clear was not encoded");
|
||||
const std::array<std::byte, 8> halfOne{std::byte{0x00}, std::byte{0x3c}, std::byte{0x00}, std::byte{0x3c}, std::byte{0x00}, std::byte{0x3c}, std::byte{0x00}, std::byte{0x3c}};
|
||||
for (std::size_t index = 0; index < large.size(); ++index) Require(large[index] == (index < 1000u ? halfOne[index % 8u] : std::byte{0}), "a clear fill over many elements did not repeat the element up to the last whole one");
|
||||
}
|
||||
|
||||
void guestFormatLookupTests() {
|
||||
|
||||
@@ -6,5 +6,12 @@ int main() {
|
||||
if (sceAgcDriverSetTargetRingForDiag() != static_cast<int>(0x8A6D0001)) return 2;
|
||||
auto* volatile linked = &sceAgcDriverSetFlip;
|
||||
if (linked == nullptr) return 3;
|
||||
if (sceAgcDriverAcquireRazorACQ() != static_cast<int>(0x8A6D0001)) return 4;
|
||||
if (sceAgcDriverGetPaDebugInterfaceVersion() != static_cast<int>(0x8A6D0001)) return 5;
|
||||
if (sceAgcDriverSetHsOffchipParamDirect() != static_cast<int>(0x8A6D0001)) return 6;
|
||||
if (sceAgcDriverSubmitMultiCommandBuffersDirect() != static_cast<int>(0x8A6D0001)) return 7;
|
||||
if (sceAgcDriverSubmitToRazorACQ() != static_cast<int>(0x8A6D0001)) return 8;
|
||||
if (sceAgcDriverSuspendPointSubmitDirect() != static_cast<int>(0x8A6D0001)) return 9;
|
||||
if (sceAgcDriverModuleRegistration() != static_cast<int>(0x8A6D0003)) return 10;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "prx/libSceAgcDriver/Execution/include/Driver.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Recorder.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Resources.hpp"
|
||||
#include "prx/libSceAgcDriver/Submit/include/Dcb.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "prx/libc/include/Shutdown.hpp"
|
||||
@@ -22,6 +25,7 @@
|
||||
#include <initializer_list>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -269,6 +273,176 @@ void RecordedFillClearsWithoutWait(AgcDriver::VulkanDevice& device, const Shader
|
||||
}
|
||||
}
|
||||
|
||||
void RecordedMaskClearClearsWithoutWait(AgcDriver::VulkanDevice& device, const Shaders& shaders) {
|
||||
const VkStencilOpState writeFive{VK_STENCIL_OP_KEEP, VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0xffu, 0xffu, 5u};
|
||||
const VkStencilOpState equalZero{VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffu, 0u, 0u};
|
||||
for (const bool stencil : {false, true}) {
|
||||
auto& htile = NewBlock();
|
||||
const Surface surface{NewBlock().Address(), stencil ? NewBlock().Address() : 0, htile.Address(), stencil, stencil ? VK_FORMAT_D32_SFLOAT_S8_UINT : VK_FORMAT_D32_SFLOAT};
|
||||
Require(Draw(device, shaders, surface, {.depthWrite = true, .stencilTest = stencil, .stencil = writeFive}) == Covered, "a new depth surface was not cleared to DB_DEPTH_CLEAR (1.0)");
|
||||
Require(Draw(device, shaders, surface, {}) == 0u, "a draw at depth 0.5 passed LESS against the 0.5 written before it");
|
||||
const auto mask = stencil ? 0x0f0u : 0x3f0u;
|
||||
{
|
||||
std::lock_guard lock(AgcDriver::GuestMemory::GpuMutex());
|
||||
const std::array<std::uint32_t, 4> words{0x010u & mask, 0x0a0u & mask, 0x150u & mask, 0x3f0u & mask};
|
||||
Require(device.FillBuffer(htile.Address(), HtileFillBytes, words), "the words of the HTILE mask clear were not recorded on the GPU");
|
||||
device.NoteHtileMask({htile.Address(), HtileFillBytes, mask, 0u});
|
||||
}
|
||||
const auto waits = AgcDriver::Graphics::Recorder::ThreadHookWaits();
|
||||
Require(Draw(device, shaders, surface, {.depthWrite = true}) == Covered, stencil ? "a depth and stencil clear by an HTILE mask clear did not clear the depth to DB_DEPTH_CLEAR (1.0)" : "a depth clear by an HTILE mask clear did not clear the depth to DB_DEPTH_CLEAR (1.0)");
|
||||
Require(AgcDriver::Graphics::Recorder::ThreadHookWaits() == waits, "the bind of the depth target waited for the GPU to run the HTILE mask clear recorded over its HTILE");
|
||||
const auto expanded = stencil ? 0xfffff3ffu : 0xfffc000fu;
|
||||
Require(AllWords(WordsAt(htile, 0), expanded), stencil ? "the bind after a depth and stencil HTILE mask clear did not store it back as expanded (0xfffff3ff)" : "the bind after a depth HTILE mask clear did not store it back as expanded (0xfffc000f)");
|
||||
if (stencil) Require(Draw(device, shaders, surface, {.depthTest = false, .stencilTest = true, .stencil = equalZero}) == Covered, "a depth and stencil HTILE mask clear did not clear the stencil to 0");
|
||||
Require(Draw(device, shaders, surface, {}) == 0u, "the depth drawn after the clear by the HTILE mask clear was cleared again");
|
||||
}
|
||||
}
|
||||
|
||||
void RecordedMaskKeepingZMaskReadsBack(AgcDriver::VulkanDevice& device, const Shaders& shaders) {
|
||||
for (const bool stencil : {false, true}) {
|
||||
auto& htile = NewBlock();
|
||||
const Surface surface{NewBlock().Address(), stencil ? NewBlock().Address() : 0, htile.Address(), stencil, stencil ? VK_FORMAT_D32_SFLOAT_S8_UINT : VK_FORMAT_D32_SFLOAT};
|
||||
Require(Draw(device, shaders, surface, {.depthWrite = true}) == Covered, "a new depth surface was not cleared to DB_DEPTH_CLEAR (1.0)");
|
||||
Require(Draw(device, shaders, surface, {}) == 0u, "a draw at depth 0.5 passed LESS against the 0.5 written before it");
|
||||
const auto mask = stencil ? 0x0ffu : 0x3ffu;
|
||||
{
|
||||
std::lock_guard lock(AgcDriver::GuestMemory::GpuMutex());
|
||||
const std::array<std::uint32_t, 4> words{0x015u & mask, 0x0a0u & mask, 0x15au & mask, 0x3ffu & mask};
|
||||
Require(device.FillBuffer(htile.Address(), HtileFillBytes, words), "the words of the HTILE mask clear were not recorded on the GPU");
|
||||
device.NoteHtileMask({htile.Address(), HtileFillBytes, mask, 0u});
|
||||
}
|
||||
const auto waits = AgcDriver::Graphics::Recorder::ThreadHookWaits();
|
||||
Require(Draw(device, shaders, surface, {.depthWrite = true}) == 0u, "an HTILE mask clear that keeps non-zero ZMask bits cleared the depth");
|
||||
Require(AgcDriver::Graphics::Recorder::ThreadHookWaits() != waits, "the bind after an HTILE mask clear that keeps the ZMask did not read the HTILE back");
|
||||
}
|
||||
}
|
||||
|
||||
void RecordHtileWords(const AgcDriver::Graphics::Context& context, AgcDriver::Graphics::Recorder& recorder, const GuestBlock& htile, std::uint32_t word) {
|
||||
using namespace AgcDriver::Graphics;
|
||||
recorder.Activate();
|
||||
const auto* import = HostImportFor(context, htile.Address(), HtileBytes);
|
||||
Require(import != nullptr, "the recorder lifetime fixture requires an imported HTILE");
|
||||
const auto commands = recorder.Commands();
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
context.Function<PFN_vkCmdFillBuffer>("vkCmdFillBuffer")(commands, import->buffer, htile.Address() - import->base, HtileBytes, word);
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | VK_PIPELINE_STAGE_HOST_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_HOST_READ_BIT);
|
||||
recorder.NotePendingWrite(htile.Address(), HtileBytes);
|
||||
AgcDriver::GuestMemory::MarkWritten(htile.Address(), HtileBytes);
|
||||
}
|
||||
|
||||
void RecreatedRecorderReadsHtile(AgcDriver::VulkanDevice& device, bool clearSurfaces) {
|
||||
using namespace AgcDriver::Graphics;
|
||||
device.WaitIdle();
|
||||
std::lock_guard lock(AgcDriver::GuestMemory::GpuMutex());
|
||||
const auto context = device.graphicsContext();
|
||||
auto* previous = Recorder::Active();
|
||||
auto& htile = NewBlock();
|
||||
const DepthTarget target{NewBlock().Address(), 0, {64, 32}, VK_FORMAT_D32_SFLOAT, 1.0f, 0, htile.Address(), false};
|
||||
std::optional<Recorder> recorder;
|
||||
recorder.emplace(context);
|
||||
const auto* address = &*recorder;
|
||||
RecordHtileWords(context, *recorder, htile, 0xf0u);
|
||||
const auto note = recorder->NewestWriteNote(htile.Address(), HtileBytes);
|
||||
NoteHtileMaskOnGpu(context, {htile.Address(), HtileBytes, 0x3f0u, 0u});
|
||||
recorder.reset();
|
||||
if (clearSurfaces) ClearDepthSurfaces(context.device);
|
||||
recorder.emplace(context);
|
||||
Require(&*recorder == address, "the replacement recorder did not reuse the original storage");
|
||||
RecordHtileWords(context, *recorder, htile, 0xfu);
|
||||
Require(recorder->NewestWriteNote(htile.Address(), HtileBytes) == note, "the replacement recorder did not reuse the original note");
|
||||
const auto waits = Recorder::ThreadHookWaits();
|
||||
Require(DepthSurfaceView(context, target) != VK_NULL_HANDLE, "the replacement recorder could not bind the depth surface");
|
||||
const auto waited = Recorder::ThreadHookWaits() != waits;
|
||||
recorder->Sync();
|
||||
const auto words = WordsAt(htile, 0);
|
||||
const auto preserved = AllWords(words, 0xfu);
|
||||
std::printf("HTILE recorder reuse: cleanup=%d note=%llu waited=%d preserved=%d first=0x%08x\n", clearSurfaces, static_cast<unsigned long long>(note), waited, preserved, words[0]);
|
||||
recorder.reset();
|
||||
ClearDepthSurfaces(context.device);
|
||||
if (previous != nullptr) previous->Activate();
|
||||
Require(waited && preserved, "a replacement recorder reused a stale mask proof instead of reading back its ordinary HTILE write");
|
||||
}
|
||||
|
||||
void CheckRecordedHtile(const AgcDriver::Graphics::Context& context, AgcDriver::Graphics::Recorder& recorder, GuestBlock& htile, bool expectedWait, std::uint32_t expectedWord, const std::string& label) {
|
||||
using namespace AgcDriver::Graphics;
|
||||
RecordHtileWords(context, recorder, NewBlock(), 0u);
|
||||
const DepthTarget target{NewBlock().Address(), 0, {64, 32}, VK_FORMAT_D32_SFLOAT, 1.0f, 0, htile.Address(), false};
|
||||
const auto waits = Recorder::ThreadHookWaits();
|
||||
Require(DepthSurfaceView(context, target) != VK_NULL_HANDLE, label + ": could not bind the depth surface");
|
||||
const bool waited = Recorder::ThreadHookWaits() != waits;
|
||||
recorder.Sync();
|
||||
const auto* words = WordsAt(htile, 0);
|
||||
const bool correct = AllWords(words, expectedWord);
|
||||
std::printf("HTILE %s: waited=%d correct=%d first=0x%08x\n", label.c_str(), waited, correct, words[0]);
|
||||
Require(waited == expectedWait && correct, label + ": wrong HTILE readback or metadata bytes");
|
||||
}
|
||||
|
||||
void LiveRecorderMaskIsolation(AgcDriver::VulkanDevice& device) {
|
||||
using namespace AgcDriver::Graphics;
|
||||
device.WaitIdle();
|
||||
std::lock_guard lock(AgcDriver::GuestMemory::GpuMutex());
|
||||
const auto context = device.graphicsContext();
|
||||
auto* previous = Recorder::Active();
|
||||
{
|
||||
auto& htile = NewBlock();
|
||||
Recorder first(context);
|
||||
Recorder second(context);
|
||||
RecordHtileWords(context, first, htile, 0xf0u);
|
||||
NoteHtileMaskOnGpu(context, {htile.Address(), HtileBytes, 0x3f0u, 0u});
|
||||
RecordHtileWords(context, second, htile, 0xfu);
|
||||
Require(first.NewestWriteNote(htile.Address(), HtileBytes) == second.NewestWriteNote(htile.Address(), HtileBytes), "live recorders did not reuse the same note");
|
||||
CheckRecordedHtile(context, second, htile, true, 0xfu, "live owner isolation");
|
||||
CheckRecordedHtile(context, first, htile, false, 0xfffc000fu, "same owner mask");
|
||||
}
|
||||
ClearDepthSurfaces(context.device);
|
||||
if (previous != nullptr) previous->Activate();
|
||||
}
|
||||
|
||||
void MaskCleanupIsolation(AgcDriver::VulkanDevice& device, AgcDriver::VulkanDevice& otherDevice) {
|
||||
using namespace AgcDriver::Graphics;
|
||||
device.WaitIdle();
|
||||
otherDevice.WaitIdle();
|
||||
std::lock_guard lock(AgcDriver::GuestMemory::GpuMutex());
|
||||
const auto context = device.graphicsContext();
|
||||
const auto otherContext = otherDevice.graphicsContext();
|
||||
Require(context.device != otherContext.device, "the device cleanup fixture requires distinct Vulkan devices");
|
||||
auto* previous = Recorder::Active();
|
||||
{
|
||||
auto& firstHtile = NewBlock();
|
||||
auto& secondHtile = NewBlock();
|
||||
std::optional<Recorder> first;
|
||||
first.emplace(context);
|
||||
Recorder second(context);
|
||||
RecordHtileWords(context, *first, firstHtile, 0xf0u);
|
||||
NoteHtileMaskOnGpu(context, {firstHtile.Address(), HtileBytes, 0x3f0u, 0u});
|
||||
RecordHtileWords(context, second, secondHtile, 0xf0u);
|
||||
NoteHtileMaskOnGpu(context, {secondHtile.Address(), HtileBytes, 0x3f0u, 0u});
|
||||
first.reset();
|
||||
CheckRecordedHtile(context, second, secondHtile, false, 0xfffc000fu, "other owner survives recorder cleanup");
|
||||
}
|
||||
{
|
||||
auto& firstHtile = NewBlock();
|
||||
auto& secondHtile = NewBlock();
|
||||
auto& otherHtile = NewBlock();
|
||||
Recorder first(context);
|
||||
Recorder second(context);
|
||||
Recorder other(otherContext);
|
||||
RecordHtileWords(context, first, firstHtile, 0xf0u);
|
||||
NoteHtileMaskOnGpu(context, {firstHtile.Address(), HtileBytes, 0x3f0u, 0u});
|
||||
RecordHtileWords(context, second, secondHtile, 0xf0u);
|
||||
NoteHtileMaskOnGpu(context, {secondHtile.Address(), HtileBytes, 0x3f0u, 0u});
|
||||
RecordHtileWords(otherContext, other, otherHtile, 0xf0u);
|
||||
NoteHtileMaskOnGpu(otherContext, {otherHtile.Address(), HtileBytes, 0x3f0u, 0u});
|
||||
ClearDepthSurfaces(context.device);
|
||||
CheckRecordedHtile(context, first, firstHtile, true, 0xfffc000fu, "device cleanup first owner");
|
||||
CheckRecordedHtile(context, second, secondHtile, true, 0xfffc000fu, "device cleanup second owner");
|
||||
CheckRecordedHtile(otherContext, other, otherHtile, false, 0xfffc000fu, "other device survives cleanup");
|
||||
}
|
||||
ClearDepthSurfaces(context.device);
|
||||
ClearDepthSurfaces(otherContext.device);
|
||||
if (previous != nullptr) previous->Activate();
|
||||
}
|
||||
|
||||
void DepthOnlyFillKeepsStencil(AgcDriver::VulkanDevice& device, const Shaders& shaders) {
|
||||
const auto& htile = NewBlock();
|
||||
const Surface surface{NewBlock().Address(), NewBlock().Address(), htile.Address(), true, VK_FORMAT_D32_SFLOAT_S8_UINT};
|
||||
@@ -285,10 +459,25 @@ void DepthOnlyFillKeepsStencil(AgcDriver::VulkanDevice& device, const Shaders& s
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
int main(int argc, char** argv) {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
if (argc == 2 && std::string(argv[1]) == "--mask-lifetime") {
|
||||
const auto otherDevice = OpenVulkanTestDevice();
|
||||
if (!otherDevice) return VulkanTestSkipped;
|
||||
if (!StoresFills(*device, NewBlock()) || !StoresFills(*otherDevice, NewBlock())) {
|
||||
std::puts("skipped HTILE mask lifetime: the Vulkan devices cannot fill imported guest memory");
|
||||
return VulkanTestSkipped;
|
||||
}
|
||||
RecreatedRecorderReadsHtile(*device, false);
|
||||
RecreatedRecorderReadsHtile(*device, true);
|
||||
LiveRecorderMaskIsolation(*device);
|
||||
MaskCleanupIsolation(*device, *otherDevice);
|
||||
LibcRunShutdown_nid_postfix();
|
||||
std::puts("HTILE mask recorder lifetime tests passed");
|
||||
return 0;
|
||||
}
|
||||
const auto shaders = Compile(*device);
|
||||
DmaFillClearsDepth(*device, shaders);
|
||||
DepthOnlyFillKeepsStencil(*device, shaders);
|
||||
@@ -299,6 +488,8 @@ int main() {
|
||||
MixedClearedSliceClears(*device, shaders);
|
||||
if (computeRan) {
|
||||
RecordedFillClearsWithoutWait(*device, shaders);
|
||||
RecordedMaskClearClearsWithoutWait(*device, shaders);
|
||||
RecordedMaskKeepingZMaskReadsBack(*device, shaders);
|
||||
DispatchFillClearsDepth(*device, shaders);
|
||||
DispatchBufferPatternFillClearsDepth(*device, shaders);
|
||||
UnknownKernelClearsTwice(*device, shaders);
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -35,7 +37,10 @@ constexpr std::uint32_t Format8_8Srgb = 129;
|
||||
constexpr std::uint32_t Format8888Srgb = 130;
|
||||
constexpr std::uint32_t Format8888UInt = 60;
|
||||
constexpr std::uint32_t Format32Float = 22;
|
||||
constexpr std::uint32_t Format16161616Float = 71;
|
||||
constexpr std::uint32_t Format111110UNorm = 30;
|
||||
constexpr std::uint32_t Type2D = 9;
|
||||
constexpr std::uint32_t Type2DArray = 13;
|
||||
constexpr std::uint32_t TypeCube = 11;
|
||||
constexpr std::uint32_t LessEqual = 3;
|
||||
constexpr std::uint32_t GreaterEqual = 6;
|
||||
@@ -55,11 +60,12 @@ constexpr std::uint32_t ReductionMin = 1;
|
||||
constexpr std::array<std::uint8_t, 4> Red{0, 64, 128, 255};
|
||||
|
||||
alignas(256) std::array<float, Threads * 3> Input{};
|
||||
alignas(256) std::array<float, Threads * 4> InputArray{};
|
||||
alignas(256) std::array<float, Threads * 4> CubeInput{};
|
||||
alignas(256) std::array<float, Threads * 4> Output{};
|
||||
std::uint32_t Swizzle = 0xfacu;
|
||||
alignas(256) std::array<std::uint32_t, Threads * 3> Extra{};
|
||||
alignas(4096) std::array<std::uint8_t, 4096> Texels{};
|
||||
alignas(4096) std::array<std::uint8_t, 65536> Texels{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 13> Code{
|
||||
0x1614008c, 0xe03c1000, 0x8000010a, 0xbf8c3f70, 0xf0bc0108, 0x00820401, 0xbf8c3f70,
|
||||
@@ -76,6 +82,16 @@ alignas(256) constexpr std::array<std::uint32_t, 13> CubeCode{
|
||||
0x34160082, 0xe0701000, 0x8001040b, 0xbf810000, 0xbf810000, 0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 13> LayerCode{
|
||||
0x16140090, 0xe0381000, 0x8000010a, 0xbf8c3f70, 0xf0bc0128, 0x00820501, 0xbf8c3f70,
|
||||
0x34160082, 0xe0701000, 0x8001050b, 0xbf810000, 0xbf810000, 0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 13> LayerSampleCode{
|
||||
0x16140090, 0xe0381000, 0x8000010a, 0xbf8c3f70, 0xf09c0128, 0x00820502, 0xbf8c3f70,
|
||||
0x34160082, 0xe0701000, 0x8001050b, 0xbf810000, 0xbf810000, 0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 16> OffsetCode{
|
||||
0x1614008c, 0xe03c1000, 0x8000030a, 0xe03c1000, 0x8005060a, 0xbf8c3f70, 0x7e020306, 0x7e040307,
|
||||
0x7e0c0308, 0xf0f80108, 0x00820901, 0xbf8c3f70, 0x34160082, 0xe0701000, 0x8001090b, 0xbf810000,
|
||||
@@ -97,6 +113,7 @@ struct Sampler {
|
||||
std::uint32_t lodBias = 0;
|
||||
bool disableCubeWrap = false;
|
||||
std::uint32_t function = LessEqual;
|
||||
bool truncCoord = false;
|
||||
};
|
||||
|
||||
std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t bytes) {
|
||||
@@ -104,20 +121,20 @@ std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t by
|
||||
return {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>((address >> 32u) & 0xffffu), bytes, 0x31016facu};
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 8> TextureDescriptor(std::uint32_t format, bool cube = false) {
|
||||
std::array<std::uint32_t, 8> TextureDescriptor(std::uint32_t format, bool cube = false, bool layered = false) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(Texels.data()));
|
||||
return {
|
||||
static_cast<std::uint32_t>(address >> 8u),
|
||||
static_cast<std::uint32_t>((address >> 40u) & 0xffu) | (format << 20u) | (((Side - 1u) & 3u) << 30u),
|
||||
((Side - 1u) >> 2u) | ((Side - 1u) << 14u),
|
||||
Swizzle | ((cube ? TypeCube : Type2D) << 28u),
|
||||
cube ? 5u : 0u, 0u, 0u, 0u,
|
||||
Swizzle | ((cube ? TypeCube : layered ? Type2DArray : Type2D) << 28u),
|
||||
cube ? 5u : layered ? 3u : 0u, 0u, 0u, 0u,
|
||||
};
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 4> SamplerDescriptor(const Sampler& sampler) {
|
||||
return {
|
||||
sampler.clamp | (sampler.clamp << 3u) | (ClampEdge << 6u) | (sampler.function << 12u) | (sampler.reduction << 29u) | (sampler.disableCubeWrap ? (1u << 28u) : 0u),
|
||||
sampler.clamp | (sampler.clamp << 3u) | (ClampEdge << 6u) | (sampler.function << 12u) | (sampler.reduction << 29u) | (sampler.disableCubeWrap ? (1u << 28u) : 0u) | (sampler.truncCoord ? (1u << 27u) : 0u),
|
||||
0u,
|
||||
sampler.lodBias | (sampler.filter << 20u) | (sampler.filter << 22u),
|
||||
sampler.border << 30u,
|
||||
@@ -179,11 +196,11 @@ void FillInput() {
|
||||
Extra[0] = 0x00001f20u;
|
||||
}
|
||||
|
||||
ShaderRecompiler::RecompileResult Compile(AgcDriver::VulkanDevice& device, std::uint32_t format, const Sampler& sampler, std::span<const std::uint32_t> code = Code, bool useCache = false, bool nativeSampleOffsets = true, bool cube = false) {
|
||||
ShaderRecompiler::RecompileResult Compile(AgcDriver::VulkanDevice& device, std::uint32_t format, const Sampler& sampler, std::span<const std::uint32_t> code = Code, bool useCache = false, bool nativeSampleOffsets = true, bool cube = false, bool layered = false) {
|
||||
std::vector<std::uint32_t> userData(24, 0u);
|
||||
const auto input = cube ? BufferDescriptor(CubeInput.data(), static_cast<std::uint32_t>(sizeof(CubeInput))) : BufferDescriptor(Input.data(), static_cast<std::uint32_t>(sizeof(Input)));
|
||||
const auto input = layered ? BufferDescriptor(InputArray.data(), static_cast<std::uint32_t>(sizeof(InputArray))) : cube ? BufferDescriptor(CubeInput.data(), static_cast<std::uint32_t>(sizeof(CubeInput))) : BufferDescriptor(Input.data(), static_cast<std::uint32_t>(sizeof(Input)));
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(sizeof(Output)));
|
||||
const auto texture = TextureDescriptor(format, cube);
|
||||
const auto texture = TextureDescriptor(format, cube, layered);
|
||||
const auto samplerWords = SamplerDescriptor(sampler);
|
||||
std::copy(input.begin(), input.end(), userData.begin());
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
@@ -225,6 +242,41 @@ constexpr std::uint32_t Select(std::uint32_t x, std::uint32_t y, std::uint32_t z
|
||||
return x | (y << 3u) | (z << 6u) | (w << 9u);
|
||||
}
|
||||
|
||||
void RunLayers(AgcDriver::VulkanDevice& device, bool converted) {
|
||||
constexpr std::array<float, 12> coordinates{-0.4f, 0.0f, 0.49999997f, 0.5f, 0.99f, 1.0f, 1.5f, 2.5f, 2.49f, 3.5f, 3.7f, 7.0f};
|
||||
constexpr std::array<std::uint32_t, 12> expectedLayers{0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
const auto format = converted ? Format111110UNorm : Format1616UNorm;
|
||||
Swizzle = Select(4, 5, 6, 1);
|
||||
const auto surface = AgcDriver::Graphics::DescribeSurface(AgcDriver::Graphics::DecodeTextureResource(TextureDescriptor(format, false, true)));
|
||||
Require(surface.layers == 4u && surface.guestBytes <= Texels.size(), "array descriptor exceeds texture storage");
|
||||
Texels.fill(0);
|
||||
const auto& mip = surface.mips.at(0);
|
||||
for (std::uint32_t layer = 0; layer < 4u; ++layer) {
|
||||
const std::uint32_t value = layer * 512u;
|
||||
for (std::uint32_t y = 0; y < Side; ++y) {
|
||||
for (std::uint32_t x = 0; x < Side; ++x) {
|
||||
std::memcpy(Texels.data() + surface.GuestLayerOffset(layer) + mip.tiledOffset + y * mip.pitchBytes + x * 4u, &value, sizeof(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
InputArray[tid * 4u] = 0.25f;
|
||||
InputArray[tid * 4u + 1u] = 0.5f;
|
||||
InputArray[tid * 4u + 2u] = 0.5f;
|
||||
InputArray[tid * 4u + 3u] = coordinates[tid % coordinates.size()];
|
||||
}
|
||||
const auto& code = converted ? LayerSampleCode : LayerCode;
|
||||
const auto result = Compile(device, format, {ClampEdge, FilterPoint}, code, false, true, false, true);
|
||||
Swizzle = 0xfacu;
|
||||
Output.fill(-1.0f);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto expected = converted ? static_cast<float>(expectedLayers[tid % expectedLayers.size()] * 512u) / 2047.0f : 0.0f;
|
||||
Require(std::fabs(Output[tid] - expected) <= 1e-5f, "array layer " + std::to_string(coordinates[tid % coordinates.size()]) + " returned " + std::to_string(Output[tid]) + ", expected " + std::to_string(expected));
|
||||
}
|
||||
}
|
||||
|
||||
void RunChannels(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, std::array<std::uint32_t, 4> channels, std::uint32_t registers, std::uint32_t firstChannel, const char* name) {
|
||||
const Sampler sampler{ClampEdge, FilterBilinear};
|
||||
Swizzle = Select(channels[0], channels[1], channels[2], channels[3]);
|
||||
@@ -400,6 +452,9 @@ int main() {
|
||||
Run(*device, {ClampEdge, FilterPoint}, "cached point comparison", false, true);
|
||||
if (lodClamp) Run(*device, {ClampWrap, FilterBilinear}, "cached bilinear comparison with offsets", true, true);
|
||||
}
|
||||
RunLayers(*device, false);
|
||||
RunLayers(*device, true);
|
||||
FillTexels();
|
||||
Reject(*device, Format32Float, {ClampEdge, FilterPoint}, "native comparison with a nonconstant texel offset requires", OffsetCode, false);
|
||||
RunChannels(*device, QuadCode, {4, 5, 6, 7}, 4, 0, "view R,G,B,A");
|
||||
RunChannels(*device, QuadCode, {0, 0, 0, 0}, 4, 0, "view 0,0,0,0");
|
||||
@@ -419,6 +474,29 @@ int main() {
|
||||
Reject(*device, Format8888UNorm, {ClampHalfBorder, FilterPoint}, "wrap, clamp-to-edge or clamp-to-border");
|
||||
Reject(*device, Format8888UNorm, {ClampBorder, FilterPoint, BorderTable}, "border color table");
|
||||
Reject(*device, Format8888UNorm, {ClampEdge, FilterBilinear, BorderBlack, ReductionMin}, "min or max reduction");
|
||||
const auto half = AgcDriver::Graphics::DescribeSurface(AgcDriver::Graphics::DecodeTextureResource(TextureDescriptor(Format16161616Float)));
|
||||
Require(half.guestBytes <= Texels.size(), "half-float descriptor exceeds texture storage");
|
||||
Texels.fill(0);
|
||||
constexpr std::array<std::uint16_t, 4> values{0x7e00u, 0x0000u, 0x8000u, 0x3800u};
|
||||
for (std::uint32_t y = 0; y < Side; ++y) {
|
||||
for (std::uint32_t x = 0; x < Side; ++x) {
|
||||
const auto value = values[y * Side + x];
|
||||
std::memcpy(Texels.data() + half.mips[0].tiledOffset + y * half.mips[0].pitchBytes + x * 8u, &value, sizeof(value));
|
||||
}
|
||||
}
|
||||
constexpr std::array<float, 4> references{std::numeric_limits<float>::quiet_NaN(), 0.0f, -0.0f, 0.5f};
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Input[tid * 3u] = references[(tid / 4u) % references.size()];
|
||||
Input[tid * 3u + 1u] = (static_cast<float>(tid % Side) + 0.5f) / Side;
|
||||
Input[tid * 3u + 2u] = (static_cast<float>((tid / Side) % Side) + 0.5f) / Side;
|
||||
}
|
||||
for (const auto function : {3u, 4u, 5u}) {
|
||||
for (const auto filter : {FilterPoint, FilterBilinear}) {
|
||||
for (const bool truncate : {false, true}) {
|
||||
RunZero(*device, Format16161616Float, {ClampEdge, filter, BorderBlack, 0u, 0u, false, function, truncate}, "half-float comparison with NaN, signed zero and TRUNC_COORD", false, 0u);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::puts(lodClamp ? "emulated color compare tests passed" : "emulated color compare tests passed, the offset and LOD clamp cases were skipped without shaderResourceMinLod");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
||||
@@ -187,10 +187,7 @@ int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
const bool hasFloat64 = TargetHasCapability(device->Target(), spv::CapabilityFloat64);
|
||||
if (!hasFloat64) std::puts("v_cvt_f64_f32 skipped, the device has no shaderFloat64");
|
||||
for (const bool float64 : {false, true}) {
|
||||
if (float64 && !hasFloat64) continue;
|
||||
for (const bool ieee : {false, true}) {
|
||||
const auto flushed = Run(*device, float64, Mode(0u, ieee));
|
||||
CheckFlushed(flushed, float64, 0u, ieee);
|
||||
|
||||
@@ -192,10 +192,6 @@ int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
if (!TargetHasCapability(device->Target(), spv::CapabilityFloat64)) {
|
||||
std::puts("skipped, the device has no shaderFloat64");
|
||||
return VulkanTestSkipped;
|
||||
}
|
||||
const Mode modes[] = {
|
||||
{"without a known float mode", std::nullopt, 3u},
|
||||
{"f64 denormal mode 0, IEEE mode on", ShaderRecompiler::ShaderFloatMode{0x30u, true, true, false}, 0u},
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 256;
|
||||
constexpr std::uint32_t Inputs = 4;
|
||||
constexpr std::uint32_t Results = 8;
|
||||
constexpr std::uint32_t Batches = 64;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Inputs> Input{};
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 16> Code{
|
||||
0x34020084u, 0x34040085u, 0xe0381000u, 0x80000401u, 0xbf8c3f70u, 0xd564000au, 0x00020d04u, 0xd565000cu,
|
||||
0x00020d04u, 0x7e1c1f04u, 0x7e202106u, 0xe0781000u, 0x80010a02u, 0xe0781010u, 0x80010e02u, 0xbf810000u,
|
||||
};
|
||||
|
||||
constexpr std::uint64_t Edges[] = {
|
||||
0x0000000000000000ull, 0x8000000000000000ull, 0x0000000000000001ull, 0x8000000000000001ull, 0x000fffffffffffffull, 0x0008000000000000ull,
|
||||
0x0010000000000000ull, 0x0010000000000001ull, 0x001fffffffffffffull, 0x3ff0000000000000ull, 0x3ff0000000000001ull, 0x3fefffffffffffffull,
|
||||
0xbff0000000000000ull, 0x3fe0000000000000ull, 0x4000000000000000ull, 0x7fefffffffffffffull, 0xffefffffffffffffull, 0x7fe0000000000000ull,
|
||||
0x7ff0000000000000ull, 0xfff0000000000000ull, 0x7ff8000000000000ull, 0xfff8000000000001ull, 0x7ff0000000000001ull, 0xfff4000000000123ull,
|
||||
0x3ca0000000000000ull, 0x3cb0000000000000ull, 0x4330000000000000ull, 0x4340000000000000ull, 0x47efffffe0000000ull, 0x47efffff00000000ull,
|
||||
0x36a0000000000000ull, 0x3690000000000000ull, 0x3690000000000001ull, 0x380fffffe0000000ull, 0x3810000000000000ull, 0xc7f0000000000000ull,
|
||||
};
|
||||
|
||||
struct Random {
|
||||
std::uint64_t state = 0x9e3779b97f4a7c15ull;
|
||||
std::uint64_t Next() {
|
||||
state ^= state << 13u;
|
||||
state ^= state >> 7u;
|
||||
state ^= state << 17u;
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
std::uint64_t WithExponent(std::uint64_t bits, std::uint64_t exponent) {
|
||||
return (bits & 0x800fffffffffffffull) | ((exponent & 0x7ffu) << 52u);
|
||||
}
|
||||
|
||||
std::uint64_t Operand(Random& random) {
|
||||
const auto bits = random.Next();
|
||||
switch (random.Next() % 8u) {
|
||||
case 0: return Edges[random.Next() % std::size(Edges)];
|
||||
case 1: return WithExponent(bits, random.Next() % 4u);
|
||||
case 2: return WithExponent(bits, 2044u + random.Next() % 3u);
|
||||
case 3: return WithExponent(bits, 1023u - 160u + random.Next() % 300u);
|
||||
case 4: return WithExponent(bits, 1023u - 30u + random.Next() % 60u);
|
||||
default: return bits;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint64_t Partner(Random& random, std::uint64_t lhs) {
|
||||
switch (random.Next() % 6u) {
|
||||
case 0: return lhs ^ 0x8000000000000000ull;
|
||||
case 1: return (lhs ^ 0x8000000000000000ull) + (random.Next() % 5u) - 2u;
|
||||
case 2: return WithExponent(random.Next(), ((lhs >> 52u) & 0x7ffu) - 53u + random.Next() % 107u);
|
||||
case 3: return WithExponent(random.Next(), 2046u - ((lhs >> 52u) & 0x7ffu) + random.Next() % 5u);
|
||||
default: return Operand(random);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsNan64(std::uint64_t bits) {
|
||||
return (bits & 0x7fffffffffffffffull) > 0x7ff0000000000000ull;
|
||||
}
|
||||
|
||||
std::uint64_t ArithmeticResult(std::uint64_t lhs, std::uint64_t rhs, double result) {
|
||||
if (IsNan64(lhs)) return lhs | 0x0008000000000000ull;
|
||||
if (IsNan64(rhs)) return rhs | 0x0008000000000000ull;
|
||||
const auto bits = std::bit_cast<std::uint64_t>(result);
|
||||
return IsNan64(bits) ? 0xfff8000000000000ull : bits;
|
||||
}
|
||||
|
||||
std::uint32_t NarrowedResult(std::uint64_t value) {
|
||||
if (!IsNan64(value)) return std::bit_cast<std::uint32_t>(static_cast<float>(std::bit_cast<double>(value)));
|
||||
const auto high = static_cast<std::uint32_t>(value >> 32u);
|
||||
return (high & 0x80000000u) | 0x7fc00000u | ((high & 0x000fffffu) << 3u) | (static_cast<std::uint32_t>(value >> 29u) & 7u);
|
||||
}
|
||||
|
||||
std::uint64_t WidenedResult(std::uint32_t value) {
|
||||
if ((value & 0x7fffffffu) > 0x7f800000u) return (static_cast<std::uint64_t>(value & 0x80000000u) << 32u) | 0x7ff8000000000000ull | (static_cast<std::uint64_t>(value & 0x007fffffu) << 29u);
|
||||
return std::bit_cast<std::uint64_t>(static_cast<double>(std::bit_cast<float>(value)));
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t bytes) {
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(data);
|
||||
return {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>((address >> 32u) & 0xffffu), bytes, 0x31016facu};
|
||||
}
|
||||
|
||||
std::string Hex(std::uint64_t value) {
|
||||
char text[24];
|
||||
std::snprintf(text, sizeof(text), "0x%016llx", static_cast<unsigned long long>(value));
|
||||
return text;
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device, const ShaderRecompiler::SpirvTarget& target) {
|
||||
Output.fill(0xdeadbeefu);
|
||||
std::vector<std::uint32_t> userData(8, 0u);
|
||||
const auto input = BufferDescriptor(Input.data(), static_cast<std::uint32_t>(Input.size() * 4u));
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(input.begin(), input.end(), userData.begin());
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
const std::span<const std::uint32_t> code(Code);
|
||||
const std::array<ShaderRecompiler::MemoryRegion, 1> memory{{{reinterpret_cast<std::uintptr_t>(code.data()), std::as_bytes(code)}}};
|
||||
const ShaderRecompiler::ShaderComputeStageInfo compute{{Threads, 1, 1}, 0u, {false, false, false}, false, 1};
|
||||
ShaderRecompiler::RecompileRequest request{
|
||||
{ShaderStage::Compute, reinterpret_cast<std::uintptr_t>(code.data()), code, 0, {}},
|
||||
{32, 0, userData, compute, std::nullopt, std::nullopt, memory},
|
||||
target,
|
||||
{0, 0, 0, 128}
|
||||
};
|
||||
request.useCache = false;
|
||||
request.context.floatMode = ShaderRecompiler::ShaderFloatMode{0xf0u, true, true, false};
|
||||
const auto result = ShaderRecompiler::Recompile(request);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
auto target = device->Target();
|
||||
std::vector<std::uint32_t> capabilities(target.supportedCapabilities.begin(), target.supportedCapabilities.end());
|
||||
std::erase(capabilities, static_cast<std::uint32_t>(spv::CapabilityFloat64));
|
||||
target.supportedCapabilities = capabilities;
|
||||
Random random;
|
||||
std::uint32_t checked = 0;
|
||||
for (std::uint32_t batch = 0; batch < Batches; ++batch) {
|
||||
std::array<std::array<std::uint64_t, 2>, Threads> operands{};
|
||||
for (std::uint32_t lane = 0; lane < Threads; ++lane) {
|
||||
const std::size_t pairIndex = static_cast<std::size_t>(batch) * Threads + lane;
|
||||
const bool edges = pairIndex < std::size(Edges) * std::size(Edges);
|
||||
const auto lhs = edges ? Edges[pairIndex % std::size(Edges)] : Operand(random);
|
||||
const auto rhs = edges ? Edges[pairIndex / std::size(Edges)] : Partner(random, lhs);
|
||||
operands[lane] = {lhs, rhs};
|
||||
Input[lane * Inputs] = static_cast<std::uint32_t>(lhs);
|
||||
Input[lane * Inputs + 1u] = static_cast<std::uint32_t>(lhs >> 32u);
|
||||
Input[lane * Inputs + 2u] = static_cast<std::uint32_t>(rhs);
|
||||
Input[lane * Inputs + 3u] = static_cast<std::uint32_t>(rhs >> 32u);
|
||||
}
|
||||
Run(*device, target);
|
||||
for (std::uint32_t lane = 0; lane < Threads; ++lane) {
|
||||
const auto [lhs, rhs] = operands[lane];
|
||||
const auto word = [&](std::uint32_t index) { return static_cast<std::uint64_t>(Output[lane * Results + index]); };
|
||||
const auto where = " of " + Hex(lhs) + " and " + Hex(rhs);
|
||||
const auto sum = word(0) | (word(1) << 32u);
|
||||
const auto expectedSum = ArithmeticResult(lhs, rhs, std::bit_cast<double>(lhs) + std::bit_cast<double>(rhs));
|
||||
Require(sum == expectedSum, "v_add_f64" + where + " is " + Hex(sum) + ", expected " + Hex(expectedSum));
|
||||
const auto product = word(2) | (word(3) << 32u);
|
||||
const auto expectedProduct = ArithmeticResult(lhs, rhs, std::bit_cast<double>(lhs) * std::bit_cast<double>(rhs));
|
||||
Require(product == expectedProduct, "v_mul_f64" + where + " is " + Hex(product) + ", expected " + Hex(expectedProduct));
|
||||
const auto narrowed = static_cast<std::uint32_t>(word(4));
|
||||
Require(narrowed == NarrowedResult(lhs), "v_cvt_f32_f64 of " + Hex(lhs) + " is " + Hex(narrowed) + ", expected " + Hex(NarrowedResult(lhs)));
|
||||
const auto widened = word(6) | (word(7) << 32u);
|
||||
const auto source = static_cast<std::uint32_t>(rhs);
|
||||
Require(widened == WidenedResult(source), "v_cvt_f64_f32 of " + Hex(source) + " is " + Hex(widened) + ", expected " + Hex(WidenedResult(source)));
|
||||
checked += 4u;
|
||||
}
|
||||
}
|
||||
std::printf("f64 integer arithmetic tests passed, %u results checked\n", checked);
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -157,12 +157,31 @@ public:
|
||||
address.pNext = nullptr;
|
||||
address.bufferDeviceAddressCaptureReplay = VK_FALSE;
|
||||
address.bufferDeviceAddressMultiDevice = VK_FALSE;
|
||||
std::vector<const char*> enabledExtensions;
|
||||
if (externalHost) enabledExtensions.insert(enabledExtensions.end(), externalHostNames.begin(), externalHostNames.end());
|
||||
bool dmaBufImport = false;
|
||||
#ifndef _WIN32
|
||||
if (externalHost) {
|
||||
VkDriverId driverId{};
|
||||
if (supported(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) {
|
||||
VkPhysicalDeviceDriverProperties driver{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES};
|
||||
VkPhysicalDeviceProperties2 properties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &driver};
|
||||
function<PFN_vkGetPhysicalDeviceProperties2>("vkGetPhysicalDeviceProperties2")(context.physical, &properties);
|
||||
driverId = driver.driverID;
|
||||
}
|
||||
dmaBufImport = driverId != VK_DRIVER_ID_NVIDIA_PROPRIETARY && supported(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME) && supported(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME);
|
||||
if (dmaBufImport) {
|
||||
enabledExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
|
||||
enabledExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
VkDeviceCreateInfo device{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, externalHost ? &address : nullptr};
|
||||
device.queueCreateInfoCount = 1u;
|
||||
device.pQueueCreateInfos = &queue;
|
||||
device.pEnabledFeatures = &enabled;
|
||||
device.enabledExtensionCount = externalHost ? static_cast<std::uint32_t>(externalHostNames.size()) : 0u;
|
||||
device.ppEnabledExtensionNames = externalHost ? externalHostNames.data() : nullptr;
|
||||
device.enabledExtensionCount = static_cast<std::uint32_t>(enabledExtensions.size());
|
||||
device.ppEnabledExtensionNames = enabledExtensions.data();
|
||||
Check(function<PFN_vkCreateDevice>("vkCreateDevice")(context.physical, &device, nullptr, &context.device), "vkCreateDevice");
|
||||
if (externalHost) {
|
||||
VkPhysicalDeviceExternalMemoryHostPropertiesEXT host{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT};
|
||||
@@ -171,6 +190,7 @@ public:
|
||||
context.hostImportAlignment = host.minImportedHostPointerAlignment;
|
||||
context.bufferDeviceAddress = true;
|
||||
}
|
||||
context.dmaBufImport = dmaBufImport;
|
||||
context.deviceProc = function<PFN_vkGetDeviceProcAddr>("vkGetDeviceProcAddr");
|
||||
context.formatProperties = function<PFN_vkGetPhysicalDeviceFormatProperties>("vkGetPhysicalDeviceFormatProperties");
|
||||
context.imageFormatProperties = function<PFN_vkGetPhysicalDeviceImageFormatProperties>("vkGetPhysicalDeviceImageFormatProperties");
|
||||
@@ -299,14 +319,19 @@ alignas(256) constexpr std::array<std::uint32_t, 17> HtileMaskKernel{
|
||||
0xbf810000u,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 16> HtileBufferMaskKernel{
|
||||
0xd7460004u, 0x04010c0cu, 0xe00c2000u, 0x80000004u, 0xbf8c3f70u, 0xd7710000u, 0x00120008u, 0xd7710001u,
|
||||
0x00160209u, 0xd7710002u, 0x001a040au, 0xd7710003u, 0x001e060bu, 0xe01c2000u, 0x80000004u, 0xbf810000u,
|
||||
};
|
||||
|
||||
std::vector<std::uint32_t> DriverPm4Packet(std::uint32_t opcode, std::initializer_list<std::uint32_t> body) {
|
||||
std::vector<std::uint32_t> words{0xc0000000u | (static_cast<std::uint32_t>(body.size() - 1u) << 16u) | (opcode << 8u)};
|
||||
words.insert(words.end(), body);
|
||||
return words;
|
||||
}
|
||||
|
||||
Context SubmitDriverHtileClear(std::uint64_t address, std::unique_lock<AgcDriver::GuestMemory::GpuMutexType>& gpuLock) {
|
||||
const auto shader = reinterpret_cast<std::uintptr_t>(HtileMaskKernel.data());
|
||||
Context SubmitDriverHtileClear(std::uint64_t address, std::unique_lock<AgcDriver::GuestMemory::GpuMutexType>& gpuLock, bool buffer) {
|
||||
const auto shader = buffer ? reinterpret_cast<std::uintptr_t>(HtileBufferMaskKernel.data()) : reinterpret_cast<std::uintptr_t>(HtileMaskKernel.data());
|
||||
std::vector<std::uint32_t> commands;
|
||||
const auto append = [&commands](std::vector<std::uint32_t> packet) { commands.insert(commands.end(), packet.begin(), packet.end()); };
|
||||
append(DriverPm4Packet(0x76u, {0x20cu, static_cast<std::uint32_t>(shader >> 8u)}));
|
||||
@@ -314,13 +339,19 @@ Context SubmitDriverHtileClear(std::uint64_t address, std::unique_lock<AgcDriver
|
||||
append(DriverPm4Packet(0x76u, {0x207u, 64u}));
|
||||
append(DriverPm4Packet(0x76u, {0x208u, 1u}));
|
||||
append(DriverPm4Packet(0x76u, {0x209u, 1u}));
|
||||
append(DriverPm4Packet(0x76u, {0x213u, (6u << 1u) | 0x80u}));
|
||||
append(DriverPm4Packet(0x76u, {0x240u, 0u}));
|
||||
append(DriverPm4Packet(0x76u, {0x241u, 0u}));
|
||||
append(DriverPm4Packet(0x76u, {0x242u, static_cast<std::uint32_t>(address)}));
|
||||
append(DriverPm4Packet(0x76u, {0x243u, static_cast<std::uint32_t>(address >> 32u)}));
|
||||
append(DriverPm4Packet(0x76u, {0x244u, 0xfffc00f0u}));
|
||||
append(DriverPm4Packet(0x76u, {0x245u, 0u}));
|
||||
if (buffer) {
|
||||
append(DriverPm4Packet(0x76u, {0x213u, (12u << 1u) | 0x80u}));
|
||||
append(DriverPm4Packet(0x76u, {0x240u, static_cast<std::uint32_t>(address), (16u << 16u) | (static_cast<std::uint32_t>(address >> 32u) & 0xffffu), 2048u, 0x0004bfacu}));
|
||||
append(DriverPm4Packet(0x76u, {0x244u, 0xfffc00f0u, 0xfffc00f0u, 0xfffc00f0u, 0xfffc00f0u, 0u, 0u, 0u, 0u}));
|
||||
} else {
|
||||
append(DriverPm4Packet(0x76u, {0x213u, (6u << 1u) | 0x80u}));
|
||||
append(DriverPm4Packet(0x76u, {0x240u, 0u}));
|
||||
append(DriverPm4Packet(0x76u, {0x241u, 0u}));
|
||||
append(DriverPm4Packet(0x76u, {0x242u, static_cast<std::uint32_t>(address)}));
|
||||
append(DriverPm4Packet(0x76u, {0x243u, static_cast<std::uint32_t>(address >> 32u)}));
|
||||
append(DriverPm4Packet(0x76u, {0x244u, 0xfffc00f0u}));
|
||||
append(DriverPm4Packet(0x76u, {0x245u, 0u}));
|
||||
}
|
||||
append(DriverPm4Packet(0x15u, {32u, 1u, 1u, 0x41u}));
|
||||
Packet packet{commands.data(), static_cast<std::uint32_t>(commands.size()), 0u, {}};
|
||||
Require(sceAgcDriverSubmitDcb(&packet) == 0, "native depth HTILE clear: PM4 submission failed");
|
||||
@@ -908,7 +939,7 @@ void CheckStorageAliasRetirement() {
|
||||
std::puts("cached storage span retires only intersecting native depth owners");
|
||||
}
|
||||
|
||||
enum class ClearFault { None, PartialStore, CpuWrite, DepthWrite, BadMetadata, UnprovenDispatch, PendingWrite, Overlap, PossibleStore, CompletedPossibleStore, DriverDispatch, ImportWindowWrite, FillDuringClear };
|
||||
enum class ClearFault { None, PartialStore, CpuWrite, DepthWrite, BadMetadata, UnprovenDispatch, PendingWrite, Overlap, PossibleStore, CompletedPossibleStore, DriverDispatch, ImportWindowWrite, FillDuringClear, DriverBufferDispatch };
|
||||
enum class ClearSource { HtileDispatch, Fill, QueuedFill };
|
||||
|
||||
void CheckClearDispatch() {
|
||||
@@ -962,7 +993,7 @@ void CheckDepthTarget(Context context, VkFormat format, std::uint32_t fragments,
|
||||
const bool filling = source != ClearSource::HtileDispatch;
|
||||
const VkExtent2D extent{5u, 3u};
|
||||
const auto bytes = static_cast<std::size_t>(MultisampledDepthBytes_nid_no_patch(extent, format == VK_FORMAT_D16_UNORM ? 2u : 4u, fragments));
|
||||
TargetMemory memory(bytes), metadata(65536u, fault == ClearFault::DriverDispatch);
|
||||
TargetMemory memory(bytes), metadata(65536u, fault == ClearFault::DriverDispatch || fault == ClearFault::DriverBufferDispatch);
|
||||
const auto metadataBytes = HtileMetadataBytes(extent);
|
||||
const bool depthOnly = depthOnlyOverride.value_or(one);
|
||||
const std::uint32_t pattern = one ? (depthOnly ? 0xfffffff0u : 0xfffc00f0u) : 0u;
|
||||
@@ -1082,14 +1113,14 @@ void CheckDepthTarget(Context context, VkFormat format, std::uint32_t fragments,
|
||||
Require(DepthSurfaceView(context, target) == view, "updating the native clear value replaced its attachment");
|
||||
const std::uint32_t clearPattern = clearOne ? (depthOnly ? 0xfffffff0u : 0xfffc00f0u) : 0u;
|
||||
if (source == ClearSource::HtileDispatch) {
|
||||
if (fault == ClearFault::DriverDispatch && clearOne) {
|
||||
if ((fault == ClearFault::DriverDispatch || fault == ClearFault::DriverBufferDispatch) && clearOne) {
|
||||
struct ShutdownDriver {
|
||||
~ShutdownDriver() {
|
||||
try { AgcDriverShutdown_nid_postfix(); } catch (...) {}
|
||||
}
|
||||
} shutdownDriver;
|
||||
const auto generation = AgcDriver::GuestMemory::TrackerGeneration();
|
||||
const auto driverContext = SubmitDriverHtileClear(target.htileAddress, gpuLock);
|
||||
const auto driverContext = SubmitDriverHtileClear(target.htileAddress, gpuLock, fault == ClearFault::DriverBufferDispatch);
|
||||
recorder.Activate();
|
||||
Require(Recorder::Active() == &recorder, "driver idle did not restore the native depth fixture recorder");
|
||||
if (!AgcDriver::GuestMemory::Watched(target.htileAddress, metadataBytes)) {
|
||||
@@ -1119,7 +1150,24 @@ void CheckDepthTarget(Context context, VkFormat format, std::uint32_t fragments,
|
||||
}), "HTILE host import simulation failed");
|
||||
Require(AgcDriver::GuestMemory::CollectWritesUncached(target.htileAddress, static_cast<std::size_t>(metadataBytes)) > beforeImport, "HTILE import window did not stamp its changed page");
|
||||
}
|
||||
if (completionCandidate && fault == ClearFault::None) {
|
||||
TargetRefuses([&] {
|
||||
auto uploadContext = context;
|
||||
uploadContext.hostImportAlignment = 0;
|
||||
GuestBufferMemory buffer(uploadContext);
|
||||
buffer.AddWritable(target.htileAddress, metadataBytes);
|
||||
buffer.Upload(false);
|
||||
}, "sample-preserving guest publication");
|
||||
const auto accepted = std::pair{target.htileAddress, static_cast<std::size_t>(metadataBytes)};
|
||||
RequireNoResidentDepthRead_nid_no_patch(target.htileAddress, metadataBytes, accepted);
|
||||
TargetRefuses([&] { RequireNoResidentDepthRead_nid_no_patch(target.address, bytes, accepted); }, "sample-preserving guest publication");
|
||||
TargetRefuses([&] { RequireNoResidentDepthRead_nid_no_patch(target.htileAddress, metadataBytes + 1u, accepted); }, "sample-preserving guest publication");
|
||||
Require(DepthSurfaceAt(target.address), "an accepted HTILE buffer access retired its native depth owner");
|
||||
}
|
||||
if (completionCandidate) ArmHtileDepthClear(target.htileAddress, static_cast<std::size_t>(metadataBytes));
|
||||
if (completionCandidate && fault == ClearFault::None) {
|
||||
TargetRefuses([&] { RequireNoResidentDepthRead_nid_no_patch(target.htileAddress, metadataBytes, std::pair{target.htileAddress, static_cast<std::size_t>(metadataBytes)}); }, "sample-preserving guest publication");
|
||||
}
|
||||
if (fault == ClearFault::Overlap) NoteHtileDepthClear(target.htileAddress, static_cast<std::size_t>(metadataBytes), nativeBytes);
|
||||
const auto storedBytes = fault == ClearFault::PartialStore ? 4u : static_cast<std::size_t>(metadataBytes);
|
||||
if (fault == ClearFault::PossibleStore || fault == ClearFault::CompletedPossibleStore) {
|
||||
@@ -2504,6 +2552,11 @@ int main(int argc, char** argv) {
|
||||
std::printf("Native depth in-place expand gate cases checked=%u unavailable=%u\n", checked, unavailable);
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::string_view(argv[1]) == "--buffer-clear") {
|
||||
CheckDepthTarget(context, VK_FORMAT_D32_SFLOAT, 4u, false, true, false, ClearFault::DriverBufferDispatch, ClearSource::HtileDispatch, lock);
|
||||
std::puts("Native depth clear by the buffer HTILE mask kernel through PM4 checked");
|
||||
return 0;
|
||||
}
|
||||
Require(argc == 1 || (argc == 2 && std::string_view(argv[1]) == "--retirement"), "invalid native depth fixture arguments");
|
||||
if (argc == 2) {
|
||||
std::uint32_t checked = 0u, unavailable = 0u;
|
||||
|
||||
@@ -494,6 +494,37 @@ std::vector<ShaderRecompiler::PipelineIdentity> ReadJournalComputeIdentities(con
|
||||
return identities;
|
||||
}
|
||||
|
||||
void ReplayRacesDispatchTests() {
|
||||
using namespace NarrowConstantStoreFixture;
|
||||
constexpr std::uint32_t Pipelines = 32;
|
||||
Block compute(BlockBytes);
|
||||
const auto words = AddressWords(compute);
|
||||
std::vector<std::vector<std::uint32_t>> codes;
|
||||
for (std::uint32_t salt = 16; salt < 16 + Pipelines; ++salt) codes.push_back(ComputeCode(salt));
|
||||
{
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
Require(device != nullptr, "the device recording the raced pipelines could not be opened");
|
||||
device->WaitForPipelineJournalReplay();
|
||||
for (const auto& code : codes) device->Dispatch(CompileCompute(*device, code, words, 32), 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device->WaitIdle();
|
||||
AgcDriver::Graphics::FlushPipelineJournal();
|
||||
}
|
||||
const auto before = Snapshot();
|
||||
{
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
Require(device != nullptr, "the device racing the replay could not be opened");
|
||||
std::vector<ShaderRecompiler::RecompileResult> shaders;
|
||||
for (const auto& code : codes) shaders.push_back(CompileCompute(*device, code, words, 32));
|
||||
for (std::size_t index = 0; index < shaders.size(); ++index) device->Dispatch(shaders[index], 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(codes[index].data()));
|
||||
device->WaitIdle();
|
||||
device->WaitForPipelineJournalReplay();
|
||||
const auto after = Snapshot();
|
||||
Require(after.journal.replayRejected == before.journal.replayRejected && after.journal.replayFailed == before.journal.replayFailed, "the raced replay rejected or failed a compute pipeline");
|
||||
const auto visited = (after.journal.replayedCompute - before.journal.replayedCompute) + (after.journal.replayPresent - before.journal.replayPresent);
|
||||
Require(device->ComputePipelinesCreated() == visited, "a dispatch and the replay both built a compute pipeline: " + std::to_string(device->ComputePipelinesCreated()) + " built for " + std::to_string(visited) + " replayed");
|
||||
}
|
||||
}
|
||||
|
||||
void NewestEntriesTests() {
|
||||
using namespace NarrowConstantStoreFixture;
|
||||
Block compute(BlockBytes);
|
||||
@@ -743,6 +774,7 @@ int main(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
JournalTests();
|
||||
ReplayRacesDispatchTests();
|
||||
NewestEntriesTests();
|
||||
EvictionTests();
|
||||
EvictionWatermarkTests();
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceAjm.native/include/InventoryExports.hpp"
|
||||
#include "prx/libSceAjm.native/include/Api.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
@@ -143,3 +145,42 @@ int APS5_VABI sceAjmInstanceSwitch(uint32_t context, uint32_t codec, uint64_t fl
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAjm_nativeUnknown_IfQ_minus_AhcmW9k_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("IfQ-AhcmW9k", libSceAjm_nativeUnknown_IfQ_minus_AhcmW9k_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAjm_nativeUnknown_JAPya_minus_QyJlU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("JAPya-QyJlU", libSceAjm_nativeUnknown_JAPya_minus_QyJlU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAjm_nativeUnknown_MgTTRx1YSFw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("MgTTRx1YSFw", libSceAjm_nativeUnknown_MgTTRx1YSFw_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAjm_nativeUnknown_POOw6Y5luA8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("POOw6Y5luA8", libSceAjm_nativeUnknown_POOw6Y5luA8_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAjm_nativeUnknown_mKgie3ed4ao_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("mKgie3ed4ao", libSceAjm_nativeUnknown_mKgie3ed4ao_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAjm_nativeUnknown_mwtwIZb60YM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("mwtwIZb60YM", libSceAjm_nativeUnknown_mwtwIZb60YM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAjm_nativeUnknown_qkuXdR4_minus_Ihc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("qkuXdR4-Ihc", libSceAjm_nativeUnknown_qkuXdR4_minus_Ihc_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAjm_nativeUnknown_IfQ_minus_AhcmW9k_nid_no_patch();
|
||||
int APS5_VABI libSceAjm_nativeUnknown_JAPya_minus_QyJlU_nid_no_patch();
|
||||
int APS5_VABI libSceAjm_nativeUnknown_MgTTRx1YSFw_nid_no_patch();
|
||||
int APS5_VABI libSceAjm_nativeUnknown_POOw6Y5luA8_nid_no_patch();
|
||||
int APS5_VABI libSceAjm_nativeUnknown_mKgie3ed4ao_nid_no_patch();
|
||||
int APS5_VABI libSceAjm_nativeUnknown_mwtwIZb60YM_nid_no_patch();
|
||||
int APS5_VABI libSceAjm_nativeUnknown_qkuXdR4_minus_Ihc_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "prx/libSceAjm.native/include/Api.hpp"
|
||||
#include "prx/libSceAjm.native/include/InventoryExports.hpp"
|
||||
@@ -1,3 +1,6 @@
|
||||
#include "prx/libSceAppDbShellCoreClient/include/LegacyExports.hpp"
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceAppDbShellCoreClient/include/InventoryExports.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
@@ -8,3 +11,151 @@ extern "C" {
|
||||
APS5_DUMMY_FUN
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown__minus_NB6hsKeI2E_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("-NB6hsKeI2E", libSceAppDbShellCoreClientUnknown__minus_NB6hsKeI2E_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_0PevQGrqaXQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("0PevQGrqaXQ", libSceAppDbShellCoreClientUnknown_0PevQGrqaXQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_1rdpvtPYXUg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("1rdpvtPYXUg", libSceAppDbShellCoreClientUnknown_1rdpvtPYXUg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_3GBO83N9XYk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("3GBO83N9XYk", libSceAppDbShellCoreClientUnknown_3GBO83N9XYk_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_8ahcDF2NTFc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("8ahcDF2NTFc", libSceAppDbShellCoreClientUnknown_8ahcDF2NTFc_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_DdycECIaV2o_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("DdycECIaV2o", libSceAppDbShellCoreClientUnknown_DdycECIaV2o_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_SlsrwedLC34_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("SlsrwedLC34", libSceAppDbShellCoreClientUnknown_SlsrwedLC34_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_aqObO3I7PVk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("aqObO3I7PVk", libSceAppDbShellCoreClientUnknown_aqObO3I7PVk_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_gyhDBiNNvlg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("gyhDBiNNvlg", libSceAppDbShellCoreClientUnknown_gyhDBiNNvlg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_s3XFdWNwYD8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("s3XFdWNwYD8", libSceAppDbShellCoreClientUnknown_s3XFdWNwYD8_nid_no_patch);
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_2w_minus_4Qfgeulk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("2w-4Qfgeulk", appDbShellLegacyUnknown_2w_minus_4Qfgeulk_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_4YzoKzbnqTA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("4YzoKzbnqTA", appDbShellLegacyUnknown_4YzoKzbnqTA_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_7XU5GcYaVvo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("7XU5GcYaVvo", appDbShellLegacyUnknown_7XU5GcYaVvo_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_8WzmR1QoGB4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("8WzmR1QoGB4", appDbShellLegacyUnknown_8WzmR1QoGB4_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_B2Abqpi8Flw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("B2Abqpi8Flw", appDbShellLegacyUnknown_B2Abqpi8Flw_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_D9UmlP_minus_vhTE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("D9UmlP-vhTE", appDbShellLegacyUnknown_D9UmlP_minus_vhTE_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_Q1SQgkBH4t4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Q1SQgkBH4t4", appDbShellLegacyUnknown_Q1SQgkBH4t4_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_Q3MBiRV47c8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Q3MBiRV47c8", appDbShellLegacyUnknown_Q3MBiRV47c8_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_RcpGh3ephSU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("RcpGh3ephSU", appDbShellLegacyUnknown_RcpGh3ephSU_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_TTQUEfa06v0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("TTQUEfa06v0", appDbShellLegacyUnknown_TTQUEfa06v0_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_ho_plus_kN7UvBGE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("ho+kN7UvBGE", appDbShellLegacyUnknown_ho_plus_kN7UvBGE_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_hoVM4_plus_KgYkw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("hoVM4+KgYkw", appDbShellLegacyUnknown_hoVM4_plus_KgYkw_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_jfXIuAeQMvU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("jfXIuAeQMvU", appDbShellLegacyUnknown_jfXIuAeQMvU_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_pifcv58UX_minus_E_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("pifcv58UX-E", appDbShellLegacyUnknown_pifcv58UX_minus_E_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_rPZ5T_plus_JXT3U_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("rPZ5T+JXT3U", appDbShellLegacyUnknown_rPZ5T_plus_JXT3U_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_sSK9wz4h9aQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("sSK9wz4h9aQ", appDbShellLegacyUnknown_sSK9wz4h9aQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_wLp81Yv8Hi0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("wLp81Yv8Hi0", appDbShellLegacyUnknown_wLp81Yv8Hi0_nid_no_patch);
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_wPUeYDMn7_minus_A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("wPUeYDMn7-A", appDbShellLegacyUnknown_wPUeYDMn7_minus_A_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown__minus_NB6hsKeI2E_nid_no_patch();
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_0PevQGrqaXQ_nid_no_patch();
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_1rdpvtPYXUg_nid_no_patch();
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_3GBO83N9XYk_nid_no_patch();
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_8ahcDF2NTFc_nid_no_patch();
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_DdycECIaV2o_nid_no_patch();
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_SlsrwedLC34_nid_no_patch();
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_aqObO3I7PVk_nid_no_patch();
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_gyhDBiNNvlg_nid_no_patch();
|
||||
int APS5_VABI libSceAppDbShellCoreClientUnknown_s3XFdWNwYD8_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI appDbShellLegacyUnknown_2w_minus_4Qfgeulk_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_4YzoKzbnqTA_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_7XU5GcYaVvo_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_8WzmR1QoGB4_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_B2Abqpi8Flw_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_D9UmlP_minus_vhTE_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_Q1SQgkBH4t4_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_Q3MBiRV47c8_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_RcpGh3ephSU_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_TTQUEfa06v0_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_ho_plus_kN7UvBGE_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_hoVM4_plus_KgYkw_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_jfXIuAeQMvU_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_pifcv58UX_minus_E_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_rPZ5T_plus_JXT3U_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_sSK9wz4h9aQ_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_wLp81Yv8Hi0_nid_no_patch();
|
||||
int APS5_VABI appDbShellLegacyUnknown_wPUeYDMn7_minus_A_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
#pragma once
|
||||
#include "prx/libSceAppDbShellCoreClient/include/InventoryExports.hpp"
|
||||
#include "prx/libSceAppDbShellCoreClient/include/LegacyExports.hpp"
|
||||
@@ -1,3 +1,6 @@
|
||||
#include "prx/libSceAsyncStorageInternal/include/LegacyExports.hpp"
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceAsyncStorageInternal/include/InventoryExports.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
@@ -8,3 +11,121 @@ extern "C" {
|
||||
APS5_DUMMY_FUN
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown__plus_YiZLBbdEy8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+YiZLBbdEy8", libSceAsyncStorageInternalUnknown__plus_YiZLBbdEy8_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_65H7_minus_ohmD9c_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("65H7-ohmD9c", libSceAsyncStorageInternalUnknown_65H7_minus_ohmD9c_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_93CwGWrhf_plus_w_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("93CwGWrhf+w", libSceAsyncStorageInternalUnknown_93CwGWrhf_plus_w_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_9zqbh2tZtZg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("9zqbh2tZtZg", libSceAsyncStorageInternalUnknown_9zqbh2tZtZg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_EKjWxMVMPzY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("EKjWxMVMPzY", libSceAsyncStorageInternalUnknown_EKjWxMVMPzY_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_Knldkc0w9lI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Knldkc0w9lI", libSceAsyncStorageInternalUnknown_Knldkc0w9lI_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_TN9xRCVggRw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("TN9xRCVggRw", libSceAsyncStorageInternalUnknown_TN9xRCVggRw_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_hP_plus_HenjaOi8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("hP+HenjaOi8", libSceAsyncStorageInternalUnknown_hP_plus_HenjaOi8_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_iYDbqYNVajM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("iYDbqYNVajM", libSceAsyncStorageInternalUnknown_iYDbqYNVajM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_jR1uFCw8qwc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("jR1uFCw8qwc", libSceAsyncStorageInternalUnknown_jR1uFCw8qwc_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_mvZ_minus_UdW_plus_Z_minus_Q_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("mvZ-UdW+Z-Q", libSceAsyncStorageInternalUnknown_mvZ_minus_UdW_plus_Z_minus_Q_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_q4KNqhT5ibk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("q4KNqhT5ibk", libSceAsyncStorageInternalUnknown_q4KNqhT5ibk_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_r299OxwCYsY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("r299OxwCYsY", libSceAsyncStorageInternalUnknown_r299OxwCYsY_nid_no_patch);
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_AdTjrblPbkA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("AdTjrblPbkA", asyncStorageLegacyUnknown_AdTjrblPbkA_nid_no_patch);
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_AtEWh5hZJAI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("AtEWh5hZJAI", asyncStorageLegacyUnknown_AtEWh5hZJAI_nid_no_patch);
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_FlnrIbnUvyI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("FlnrIbnUvyI", asyncStorageLegacyUnknown_FlnrIbnUvyI_nid_no_patch);
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_GETCq_plus_kyXcA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("GETCq+kyXcA", asyncStorageLegacyUnknown_GETCq_plus_kyXcA_nid_no_patch);
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_J_minus_cJO5MPuwo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("J-cJO5MPuwo", asyncStorageLegacyUnknown_J_minus_cJO5MPuwo_nid_no_patch);
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_QM3_minus_5jVrNHg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("QM3-5jVrNHg", asyncStorageLegacyUnknown_QM3_minus_5jVrNHg_nid_no_patch);
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_qenXW57P9rU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("qenXW57P9rU", asyncStorageLegacyUnknown_qenXW57P9rU_nid_no_patch);
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_smItNfY3yHA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("smItNfY3yHA", asyncStorageLegacyUnknown_smItNfY3yHA_nid_no_patch);
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_yLYSOLZmYso_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("yLYSOLZmYso", asyncStorageLegacyUnknown_yLYSOLZmYso_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown__plus_YiZLBbdEy8_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_65H7_minus_ohmD9c_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_93CwGWrhf_plus_w_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_9zqbh2tZtZg_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_EKjWxMVMPzY_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_Knldkc0w9lI_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_TN9xRCVggRw_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_hP_plus_HenjaOi8_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_iYDbqYNVajM_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_jR1uFCw8qwc_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_mvZ_minus_UdW_plus_Z_minus_Q_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_q4KNqhT5ibk_nid_no_patch();
|
||||
int APS5_VABI libSceAsyncStorageInternalUnknown_r299OxwCYsY_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI asyncStorageLegacyUnknown_AdTjrblPbkA_nid_no_patch();
|
||||
int APS5_VABI asyncStorageLegacyUnknown_AtEWh5hZJAI_nid_no_patch();
|
||||
int APS5_VABI asyncStorageLegacyUnknown_FlnrIbnUvyI_nid_no_patch();
|
||||
int APS5_VABI asyncStorageLegacyUnknown_GETCq_plus_kyXcA_nid_no_patch();
|
||||
int APS5_VABI asyncStorageLegacyUnknown_J_minus_cJO5MPuwo_nid_no_patch();
|
||||
int APS5_VABI asyncStorageLegacyUnknown_QM3_minus_5jVrNHg_nid_no_patch();
|
||||
int APS5_VABI asyncStorageLegacyUnknown_qenXW57P9rU_nid_no_patch();
|
||||
int APS5_VABI asyncStorageLegacyUnknown_smItNfY3yHA_nid_no_patch();
|
||||
int APS5_VABI asyncStorageLegacyUnknown_yLYSOLZmYso_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
#pragma once
|
||||
#include "prx/libSceAsyncStorageInternal/include/InventoryExports.hpp"
|
||||
#include "prx/libSceAsyncStorageInternal/include/LegacyExports.hpp"
|
||||
@@ -33,7 +33,40 @@ if(BUILD_TESTING)
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
|
||||
add_test_executable(audio_out_vibration_device_tests tests/AudioOutVibrationDevice.cpp src/AudioOut.cpp src/AudioOut2PadMix.cpp src/AudioOutShutdown.cpp)
|
||||
add_test_executable(audio_out_host_volume_tests tests/HostVolume.cpp)
|
||||
target_include_directories(audio_out_host_volume_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out_host_volume_tests PRIVATE libc)
|
||||
configure_windows_unwind(audio_out_host_volume_tests)
|
||||
add_test(NAME audio_out_host_volume COMMAND audio_out_host_volume_tests)
|
||||
set_tests_properties(audio_out_host_volume PROPERTIES TIMEOUT 5)
|
||||
if(WIN32)
|
||||
set_tests_properties(audio_out_host_volume PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
|
||||
add_test_executable(audio_out_host_gain_tests tests/HostGain.cpp)
|
||||
target_include_directories(audio_out_host_gain_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out_host_gain_tests PRIVATE libc)
|
||||
configure_windows_unwind(audio_out_host_gain_tests)
|
||||
add_test(NAME audio_out_host_gain COMMAND audio_out_host_gain_tests)
|
||||
set_tests_properties(audio_out_host_gain PROPERTIES TIMEOUT 5)
|
||||
if(WIN32)
|
||||
set_tests_properties(audio_out_host_gain PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
|
||||
add_test_executable(audio_out_host_volume_state_tests tests/HostVolumeState.cpp ../libScePad/src/HostVolumeState.cpp)
|
||||
target_include_directories(audio_out_host_volume_state_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out_host_volume_state_tests PRIVATE libc)
|
||||
configure_windows_unwind(audio_out_host_volume_state_tests)
|
||||
add_test(NAME audio_out_host_volume_state COMMAND audio_out_host_volume_state_tests)
|
||||
set_tests_properties(audio_out_host_volume_state PROPERTIES TIMEOUT 10)
|
||||
if(WIN32)
|
||||
set_tests_properties(audio_out_host_volume_state PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
|
||||
add_test_executable(audio_out_vibration_device_tests tests/AudioOutVibrationDevice.cpp src/AudioOut.cpp src/AudioOut2PadMix.cpp src/AudioOutShutdown.cpp ../libScePad/src/HostVolumeState.cpp)
|
||||
target_compile_definitions(audio_out_vibration_device_tests PRIVATE SDL_MAIN_HANDLED)
|
||||
target_include_directories(audio_out_vibration_device_tests PRIVATE ${LIBS_INCLUDE_DIR} ${ANYPS5_SDL2_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out_vibration_device_tests PRIVATE libc libkernel libScePad)
|
||||
@@ -48,7 +81,7 @@ if(BUILD_TESTING)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_test_executable(audio_out_default_open_tests tests/AudioOutDefaultOpen.cpp src/AudioOut.cpp src/AudioOut2PadMix.cpp src/AudioOutShutdown.cpp)
|
||||
add_test_executable(audio_out_default_open_tests tests/AudioOutDefaultOpen.cpp src/AudioOut.cpp src/AudioOut2PadMix.cpp src/AudioOutShutdown.cpp ../libScePad/src/HostVolumeState.cpp)
|
||||
target_compile_definitions(audio_out_default_open_tests PRIVATE SDL_MAIN_HANDLED)
|
||||
target_include_directories(audio_out_default_open_tests PRIVATE ${LIBS_INCLUDE_DIR} ${ANYPS5_SDL2_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out_default_open_tests PRIVATE libc libkernel libScePad)
|
||||
@@ -63,7 +96,7 @@ if(BUILD_TESTING)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_test_executable(audio_out_buffer_size_tests tests/AudioOutBufferSize.cpp src/AudioOut.cpp src/AudioOut2PadMix.cpp src/AudioOutShutdown.cpp)
|
||||
add_test_executable(audio_out_buffer_size_tests tests/AudioOutBufferSize.cpp src/AudioOut.cpp src/AudioOut2PadMix.cpp src/AudioOutShutdown.cpp ../libScePad/src/HostVolumeState.cpp)
|
||||
target_compile_definitions(audio_out_buffer_size_tests PRIVATE SDL_MAIN_HANDLED)
|
||||
target_include_directories(audio_out_buffer_size_tests PRIVATE ${LIBS_INCLUDE_DIR} ${ANYPS5_SDL2_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out_buffer_size_tests PRIVATE libc libkernel libScePad)
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifndef CORE_LIBS_PRX_LIBSCEAUDIOOUT_INCLUDE_HOSTGAIN_HPP
|
||||
#define CORE_LIBS_PRX_LIBSCEAUDIOOUT_INCLUDE_HOSTGAIN_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
class HostGainRamp {
|
||||
public:
|
||||
static constexpr std::uint32_t Unity = 65536;
|
||||
static constexpr std::uint32_t DefaultRampFrames = 480;
|
||||
|
||||
explicit HostGainRamp(std::uint32_t rampFrames = DefaultRampFrames) {
|
||||
Configure(rampFrames);
|
||||
}
|
||||
|
||||
void Configure(std::uint32_t rampFrames) {
|
||||
step = rampFrames == 0 ? Unity : std::max<std::uint32_t>(1, Unity / rampFrames);
|
||||
}
|
||||
|
||||
std::uint32_t Current() const { return current; }
|
||||
std::uint32_t Step() const { return step; }
|
||||
|
||||
bool Bypass(std::uint32_t target) const {
|
||||
return current == Unity && target == Unity;
|
||||
}
|
||||
|
||||
void Apply(std::int16_t* samples, std::size_t frames, unsigned channels, std::uint32_t target) {
|
||||
if (Bypass(target)) return;
|
||||
for (std::size_t frame = 0; frame < frames; ++frame) {
|
||||
const std::int64_t gain = advance(target);
|
||||
for (unsigned channel = 0; channel < channels; ++channel) {
|
||||
std::int16_t& sample = samples[frame * channels + channel];
|
||||
const std::int64_t scaled = (static_cast<std::int64_t>(sample) * gain + Unity / 2) >> 16;
|
||||
sample = static_cast<std::int16_t>(std::clamp<std::int64_t>(scaled, std::numeric_limits<std::int16_t>::min(), std::numeric_limits<std::int16_t>::max()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Apply(float* samples, std::size_t frames, unsigned channels, std::uint32_t target) {
|
||||
if (Bypass(target)) return;
|
||||
for (std::size_t frame = 0; frame < frames; ++frame) {
|
||||
const float gain = static_cast<float>(advance(target)) / static_cast<float>(Unity);
|
||||
for (unsigned channel = 0; channel < channels; ++channel) samples[frame * channels + channel] *= gain;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint32_t advance(std::uint32_t target) {
|
||||
if (current < target) current = target - current <= step ? target : current + step;
|
||||
else if (current > target) current = current - target <= step ? target : current - step;
|
||||
return current;
|
||||
}
|
||||
|
||||
std::uint32_t current = Unity;
|
||||
std::uint32_t step = Unity;
|
||||
};
|
||||
|
||||
inline const void* HostGainFilter(HostGainRamp& ramp, std::uint32_t target, const void* data, bool isFloat, std::size_t frames, unsigned channels, std::vector<std::uint8_t>& scratch) {
|
||||
if (ramp.Bypass(target)) return data;
|
||||
const std::size_t bytes = frames * channels * (isFloat ? sizeof(float) : sizeof(std::int16_t));
|
||||
if (data != scratch.data()) {
|
||||
scratch.resize(bytes);
|
||||
std::memcpy(scratch.data(), data, bytes);
|
||||
}
|
||||
if (isFloat) ramp.Apply(reinterpret_cast<float*>(scratch.data()), frames, channels, target);
|
||||
else ramp.Apply(reinterpret_cast<std::int16_t*>(scratch.data()), frames, channels, target);
|
||||
return scratch.data();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -17,3 +17,39 @@ int APS5_VABI sceAudioOut2SetSpeakerInfo();
|
||||
int APS5_VABI sceAudioOut2SetTvCorrectionInfo();
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI libSceAudioOutUnknown__minus_3HTIXaIx7U_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_0Oz9yG27ovw_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_1pWftEwJg6w_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_4Ac_plus_2ezx1lY_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_6hw5LpQh6_minus_M_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_87IcZgIbuxQ_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_8qn2ceJ4HVg_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_96EqlBA6q4I_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_B88xqT6vI88_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_DEpjrJh_minus_flc_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_GIcJie_plus_rjvM_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_KeHpCnAvtGw_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_Oqn65W_minus_w8bo_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_PNeVjMfwq1M_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_PSg2qlLNCqM_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_UAk5DtTuUMo_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_WKpJvbBdcbU_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_WOfIge9NmBA_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_YSm2BXd3gfE_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_Zk1Cn7Z2tVs_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_bd5H255vnsk_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_f3xQNbru2m8_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_g33sQzMRRmQ_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_gaUU6uC15vs_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_jEcHKuQ4k8I_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_lyHeaetMYXg_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_r5LqvBxfG_plus_0_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_rSyeebu6wWI_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_rzjbvXzvDtE_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_spvw78DsDzU_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_tqTyWw6NgyU_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_tvPlXmc4MHs_nid_no_patch();
|
||||
int APS5_VABI libSceAudioOutUnknown_yt9g5kdJy1o_nid_no_patch();
|
||||
}
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "prx/libc/include/Shutdown.hpp"
|
||||
#include "prx/libkernel/Time/include/Time.hpp"
|
||||
#include "prx/libSceAudioOut/include/AudioOutSdl.hpp"
|
||||
#include "prx/libSceAudioOut/include/HostGain.hpp"
|
||||
#include "prx/libScePad/include/HostVolumeControl.hpp"
|
||||
#include "AudioOutShutdown.hpp"
|
||||
#include "AudioOut2PadMix.hpp"
|
||||
#include "prx/libScePad/include/PadState.hpp"
|
||||
@@ -124,6 +126,7 @@ struct Port {
|
||||
AudioOut2PadLayout padLayout;
|
||||
SDL_AudioDeviceID device = 0;
|
||||
SDL_AudioSpec spec = {};
|
||||
HostGainRamp hostGain;
|
||||
};
|
||||
|
||||
static std::mutex g_mutex;
|
||||
@@ -296,6 +299,7 @@ static void queueAudio(Port& port, const void* data, std::unique_lock<std::mutex
|
||||
queueData = padFrames.data();
|
||||
} else {
|
||||
queueData = prepareBuffer(port, data, prepareBuf);
|
||||
queueData = HostGainFilter(port.hostGain, HostVolumeGain_nid_no_patch(), queueData, formatIsFloat(port.format), port.samplesNum, static_cast<unsigned>(port.channels), prepareBuf);
|
||||
queueSize = checkedBufferSize(port.samplesNum, static_cast<std::uint32_t>(port.channels), bytesPerSample(port.format));
|
||||
}
|
||||
|
||||
@@ -383,6 +387,7 @@ static int allocatePort(int type, std::uint32_t len, std::uint32_t freq, Format
|
||||
port.format = format;
|
||||
port.channels = channelsForFormat(format);
|
||||
port.lastDataOutputTime = 0;
|
||||
port.hostGain = HostGainRamp(freq / 100);
|
||||
port.virtualQueueEnd = sceKernelGetProcessTime();
|
||||
port.mixLevel = type == PORT_TYPE_PADSPK ? DEFAULT_PADSPK_MIX_LEVEL : DEFAULT_VOLUME;
|
||||
if (type == PORT_TYPE_VIBRATION) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "prx/libc/include/PreciseWait.hpp"
|
||||
#include "prx/libc/include/Shutdown.hpp"
|
||||
#include "AudioOut2Internal.hpp"
|
||||
#include "prx/libScePad/include/HostVolumeControl.hpp"
|
||||
#include "AudioOutShutdown.hpp"
|
||||
#include "prx/libSceAudioOut/include/AudioOutSdl.hpp"
|
||||
#include "prx/libScePad/include/PadState.hpp"
|
||||
@@ -263,6 +264,7 @@ static void DeviceCallback(void* userdata, Uint8* stream, int length) {
|
||||
std::copy_n(context.output.begin(), count, out);
|
||||
context.output.erase(context.output.begin(), context.output.begin() + static_cast<std::ptrdiff_t>(count));
|
||||
std::fill(out + count, out + samples, 0.0f);
|
||||
context.hostGain.Apply(out, samples / AUDIO_OUT2_OUTPUT_CHANNELS, AUDIO_OUT2_OUTPUT_CHANNELS, HostVolumeGain_nid_no_patch());
|
||||
if (count < samples && !context.priming) {
|
||||
context.priming = true;
|
||||
context.primes++;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "SDL.h"
|
||||
#include "SceTypes.hpp"
|
||||
#include "AudioOut2PadMix.hpp"
|
||||
#include "prx/libSceAudioOut/include/HostGain.hpp"
|
||||
|
||||
// Shared by the AudioOut2 context and port files.
|
||||
//
|
||||
@@ -98,6 +99,7 @@ struct AudioOut2Context {
|
||||
std::uint32_t queued = 0;
|
||||
std::chrono::steady_clock::time_point playHead;
|
||||
SDL_AudioDeviceID device = 0;
|
||||
HostGainRamp hostGain{AUDIO_OUT2_SAMPLE_RATE / 100};
|
||||
// Stereo float mix of the ports for one grain.
|
||||
std::vector<float> mix;
|
||||
// Mixed stereo frames the device has not played yet; it plays silence until the cushion is mixed.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceAudioOut/include/InventoryExports.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
@@ -48,3 +49,172 @@ int APS5_VABI sceAudioOut2SetTvCorrectionInfo() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown__minus_3HTIXaIx7U_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("-3HTIXaIx7U", libSceAudioOutUnknown__minus_3HTIXaIx7U_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_0Oz9yG27ovw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("0Oz9yG27ovw", libSceAudioOutUnknown_0Oz9yG27ovw_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_1pWftEwJg6w_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("1pWftEwJg6w", libSceAudioOutUnknown_1pWftEwJg6w_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_4Ac_plus_2ezx1lY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("4Ac+2ezx1lY", libSceAudioOutUnknown_4Ac_plus_2ezx1lY_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_6hw5LpQh6_minus_M_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("6hw5LpQh6-M", libSceAudioOutUnknown_6hw5LpQh6_minus_M_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_87IcZgIbuxQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("87IcZgIbuxQ", libSceAudioOutUnknown_87IcZgIbuxQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_8qn2ceJ4HVg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("8qn2ceJ4HVg", libSceAudioOutUnknown_8qn2ceJ4HVg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_96EqlBA6q4I_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("96EqlBA6q4I", libSceAudioOutUnknown_96EqlBA6q4I_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_B88xqT6vI88_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("B88xqT6vI88", libSceAudioOutUnknown_B88xqT6vI88_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_DEpjrJh_minus_flc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("DEpjrJh-flc", libSceAudioOutUnknown_DEpjrJh_minus_flc_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_GIcJie_plus_rjvM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("GIcJie+rjvM", libSceAudioOutUnknown_GIcJie_plus_rjvM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_KeHpCnAvtGw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("KeHpCnAvtGw", libSceAudioOutUnknown_KeHpCnAvtGw_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_Oqn65W_minus_w8bo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Oqn65W-w8bo", libSceAudioOutUnknown_Oqn65W_minus_w8bo_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_PNeVjMfwq1M_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("PNeVjMfwq1M", libSceAudioOutUnknown_PNeVjMfwq1M_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_PSg2qlLNCqM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("PSg2qlLNCqM", libSceAudioOutUnknown_PSg2qlLNCqM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_UAk5DtTuUMo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("UAk5DtTuUMo", libSceAudioOutUnknown_UAk5DtTuUMo_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_WKpJvbBdcbU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("WKpJvbBdcbU", libSceAudioOutUnknown_WKpJvbBdcbU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_WOfIge9NmBA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("WOfIge9NmBA", libSceAudioOutUnknown_WOfIge9NmBA_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_YSm2BXd3gfE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("YSm2BXd3gfE", libSceAudioOutUnknown_YSm2BXd3gfE_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_Zk1Cn7Z2tVs_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Zk1Cn7Z2tVs", libSceAudioOutUnknown_Zk1Cn7Z2tVs_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_bd5H255vnsk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("bd5H255vnsk", libSceAudioOutUnknown_bd5H255vnsk_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_f3xQNbru2m8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("f3xQNbru2m8", libSceAudioOutUnknown_f3xQNbru2m8_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_g33sQzMRRmQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("g33sQzMRRmQ", libSceAudioOutUnknown_g33sQzMRRmQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_gaUU6uC15vs_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("gaUU6uC15vs", libSceAudioOutUnknown_gaUU6uC15vs_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_jEcHKuQ4k8I_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("jEcHKuQ4k8I", libSceAudioOutUnknown_jEcHKuQ4k8I_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_lyHeaetMYXg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("lyHeaetMYXg", libSceAudioOutUnknown_lyHeaetMYXg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_r5LqvBxfG_plus_0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("r5LqvBxfG+0", libSceAudioOutUnknown_r5LqvBxfG_plus_0_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_rSyeebu6wWI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("rSyeebu6wWI", libSceAudioOutUnknown_rSyeebu6wWI_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_rzjbvXzvDtE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("rzjbvXzvDtE", libSceAudioOutUnknown_rzjbvXzvDtE_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_spvw78DsDzU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("spvw78DsDzU", libSceAudioOutUnknown_spvw78DsDzU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_tqTyWw6NgyU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("tqTyWw6NgyU", libSceAudioOutUnknown_tqTyWw6NgyU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_tvPlXmc4MHs_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("tvPlXmc4MHs", libSceAudioOutUnknown_tvPlXmc4MHs_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioOutUnknown_yt9g5kdJy1o_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("yt9g5kdJy1o", libSceAudioOutUnknown_yt9g5kdJy1o_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
#include "prx/libSceAudioOut/include/HostGain.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
void require(bool condition, const char* message) {
|
||||
if (!condition) throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
std::vector<std::int16_t> constantS16(std::size_t frames, unsigned channels, std::int16_t value) {
|
||||
return std::vector<std::int16_t>(frames * channels, value);
|
||||
}
|
||||
|
||||
void s16BypassAtUnity() {
|
||||
for (const unsigned channels : {1u, 2u, 8u}) {
|
||||
std::vector<std::int16_t> samples(256 * channels);
|
||||
for (std::size_t index = 0; index < samples.size(); ++index) samples[index] = static_cast<std::int16_t>(static_cast<int>(index * 7919u % 65536u) - 32768);
|
||||
const auto before = samples;
|
||||
HostGainRamp ramp;
|
||||
require(ramp.Bypass(HostGainRamp::Unity), "a ramp at unity with a unity target bypasses");
|
||||
ramp.Apply(samples.data(), 256, channels, HostGainRamp::Unity);
|
||||
require(std::memcmp(before.data(), samples.data(), samples.size() * sizeof(std::int16_t)) == 0, "unity leaves 16-bit samples bit-identical");
|
||||
require(ramp.Current() == HostGainRamp::Unity, "bypass keeps the gain at unity");
|
||||
}
|
||||
}
|
||||
|
||||
void s16FirstSampleOfRamp() {
|
||||
HostGainRamp ramp;
|
||||
require(ramp.Step() == 136, "a 480 frame ramp steps 136 per frame");
|
||||
auto samples = constantS16(1, 1, 10000);
|
||||
ramp.Apply(samples.data(), 1, 1, 32768);
|
||||
require(ramp.Current() == 65536 - 136, "the first frame moves one step");
|
||||
require(samples[0] == 9979, "the first frame is scaled by the first step");
|
||||
}
|
||||
|
||||
void s16RampReachesTargetExactly() {
|
||||
HostGainRamp ramp;
|
||||
auto samples = constantS16(2000, 1, 10000);
|
||||
ramp.Apply(samples.data(), 2000, 1, 32768);
|
||||
require(ramp.Current() == 32768, "the ramp lands exactly on the target");
|
||||
std::size_t firstAtTarget = 0;
|
||||
while (firstAtTarget < samples.size() && samples[firstAtTarget] != 5000) ++firstAtTarget;
|
||||
require(firstAtTarget == 240, "the ramp takes the 241 frames its step needs");
|
||||
for (std::size_t index = firstAtTarget; index < samples.size(); ++index) require(samples[index] == 5000, "samples stay at the target after the ramp");
|
||||
}
|
||||
|
||||
void s16RampHasNoDiscontinuity() {
|
||||
HostGainRamp ramp;
|
||||
auto samples = constantS16(2000, 1, 32000);
|
||||
ramp.Apply(samples.data(), 2000, 1, 0);
|
||||
int largest = 0;
|
||||
int previous = 32000;
|
||||
for (const auto sample : samples) {
|
||||
require(sample <= previous, "a ramp down never rises");
|
||||
largest = std::max(largest, previous - sample);
|
||||
previous = sample;
|
||||
}
|
||||
require(largest <= 67, "no step of a full-scale ramp exceeds its per-frame slope");
|
||||
require(samples.back() == 0, "the ramp ends in silence");
|
||||
}
|
||||
|
||||
void s16RampContinuesAcrossBuffers() {
|
||||
auto whole = constantS16(3000, 2, 20000);
|
||||
HostGainRamp wholeRamp;
|
||||
wholeRamp.Apply(whole.data(), 3000, 2, 16384);
|
||||
auto split = constantS16(3000, 2, 20000);
|
||||
HostGainRamp splitRamp;
|
||||
std::size_t done = 0;
|
||||
for (const std::size_t chunk : {1u, 7u, 100u, 333u, 1u, 900u, 1658u}) {
|
||||
splitRamp.Apply(split.data() + done * 2, chunk, 2, 16384);
|
||||
done += chunk;
|
||||
}
|
||||
require(done == 3000, "the chunks cover the buffer");
|
||||
require(std::memcmp(whole.data(), split.data(), whole.size() * sizeof(std::int16_t)) == 0, "a ramp split across buffers equals the same ramp in one buffer");
|
||||
require(wholeRamp.Current() == splitRamp.Current(), "both ramps end at the same gain");
|
||||
}
|
||||
|
||||
void s16SaturatesAboveUnity() {
|
||||
HostGainRamp ramp(1);
|
||||
auto samples = constantS16(4, 1, 30000);
|
||||
samples[1] = -30000;
|
||||
samples[2] = 8000;
|
||||
ramp.Apply(samples.data(), 4, 1, 4 * HostGainRamp::Unity);
|
||||
require(samples[0] == 32767, "a positive overshoot saturates at 32767");
|
||||
require(samples[1] == -32768, "a negative overshoot saturates at -32768");
|
||||
require(samples[2] == 32000, "a sample inside the range is scaled");
|
||||
}
|
||||
|
||||
void s16ChannelsShareTheFrameGain() {
|
||||
for (const unsigned channels : {1u, 2u, 8u}) {
|
||||
HostGainRamp ramp;
|
||||
auto samples = constantS16(600, channels, 12345);
|
||||
ramp.Apply(samples.data(), 600, channels, 0);
|
||||
for (std::size_t frame = 0; frame < 600; ++frame) {
|
||||
for (unsigned channel = 1; channel < channels; ++channel) require(samples[frame * channels + channel] == samples[frame * channels], "every channel of a frame gets the same gain");
|
||||
}
|
||||
require(samples[599 * channels] == 0, "the last frame is silent");
|
||||
}
|
||||
}
|
||||
|
||||
void s16SilentTargetSilencesAfterRamp() {
|
||||
HostGainRamp ramp(1);
|
||||
auto samples = constantS16(8, 2, -32768);
|
||||
ramp.Apply(samples.data(), 8, 2, 0);
|
||||
for (const auto sample : samples) require(sample == 0, "a zero gain writes zeros");
|
||||
require(!ramp.Bypass(0), "a silent target is never bypassed");
|
||||
auto again = constantS16(8, 2, 1000);
|
||||
ramp.Apply(again.data(), 8, 2, 0);
|
||||
for (const auto sample : again) require(sample == 0, "a settled silent gain stays silent");
|
||||
}
|
||||
|
||||
void s16ReturnToUnityBypassesAgain() {
|
||||
HostGainRamp ramp;
|
||||
auto samples = constantS16(2000, 2, 9000);
|
||||
ramp.Apply(samples.data(), 2000, 2, 0);
|
||||
auto back = constantS16(2000, 2, 9000);
|
||||
ramp.Apply(back.data(), 2000, 2, HostGainRamp::Unity);
|
||||
require(ramp.Current() == HostGainRamp::Unity, "the ramp returns to exactly unity");
|
||||
require(ramp.Bypass(HostGainRamp::Unity), "once back at unity the stream bypasses again");
|
||||
auto steady = constantS16(64, 2, 9000);
|
||||
const auto before = steady;
|
||||
ramp.Apply(steady.data(), 64, 2, HostGainRamp::Unity);
|
||||
require(steady == before, "samples after the return are bit-identical");
|
||||
}
|
||||
|
||||
void s16RoundsHalfUp() {
|
||||
HostGainRamp ramp(1);
|
||||
auto samples = constantS16(4, 1, 1);
|
||||
samples[1] = 3;
|
||||
samples[2] = -1;
|
||||
samples[3] = -3;
|
||||
ramp.Apply(samples.data(), 4, 1, 32768);
|
||||
require(samples[0] == 1 && samples[1] == 2, "a half rounds up for positive samples");
|
||||
require(samples[2] == 0 && samples[3] == -1, "a half rounds toward positive for negative samples");
|
||||
}
|
||||
|
||||
void s16RampUpLandsExactly() {
|
||||
HostGainRamp ramp;
|
||||
auto silence = constantS16(1000, 1, 0);
|
||||
ramp.Apply(silence.data(), 1000, 1, 0);
|
||||
require(ramp.Current() == 0, "the ramp reached silence");
|
||||
auto samples = constantS16(2000, 1, 10000);
|
||||
ramp.Apply(samples.data(), 2000, 1, HostGainRamp::Unity);
|
||||
require(ramp.Current() == HostGainRamp::Unity, "a ramp up lands exactly on unity");
|
||||
int previous = 0;
|
||||
int largest = 0;
|
||||
for (const auto sample : samples) {
|
||||
require(sample >= previous, "a ramp up never falls");
|
||||
largest = std::max(largest, sample - previous);
|
||||
previous = sample;
|
||||
}
|
||||
require(largest <= 22, "no step of a ramp up exceeds its per-frame slope");
|
||||
require(samples.back() == 10000, "samples return to the title's own values");
|
||||
}
|
||||
|
||||
std::vector<float> constantF32(std::size_t frames, unsigned channels, float value) {
|
||||
return std::vector<float>(frames * channels, value);
|
||||
}
|
||||
|
||||
void f32BypassAtUnity() {
|
||||
for (const unsigned channels : {1u, 2u, 8u}) {
|
||||
std::vector<float> samples(256 * channels);
|
||||
for (std::size_t index = 0; index < samples.size(); ++index) samples[index] = static_cast<float>(static_cast<int>(index % 2001) - 1000) / 777.0f;
|
||||
const auto before = samples;
|
||||
HostGainRamp ramp;
|
||||
ramp.Apply(samples.data(), 256, channels, HostGainRamp::Unity);
|
||||
require(std::memcmp(before.data(), samples.data(), samples.size() * sizeof(float)) == 0, "unity leaves float samples bit-identical");
|
||||
}
|
||||
}
|
||||
|
||||
void f32FirstSampleAndLanding() {
|
||||
HostGainRamp ramp;
|
||||
auto samples = constantF32(2000, 1, 1.0f);
|
||||
ramp.Apply(samples.data(), 2000, 1, 32768);
|
||||
require(samples[0] == static_cast<float>(65536 - 136) / 65536.0f, "the first float frame is scaled by the first step");
|
||||
require(samples[240] == 0.5f && samples[239] != 0.5f, "the float ramp lands on the target at the same frame as the 16-bit one");
|
||||
require(samples.back() == 0.5f, "float samples stay at the target after the ramp");
|
||||
}
|
||||
|
||||
void f32RampHasNoDiscontinuity() {
|
||||
HostGainRamp ramp;
|
||||
auto samples = constantF32(1000, 2, 1.0f);
|
||||
ramp.Apply(samples.data(), 1000, 2, 0);
|
||||
float previous = 1.0f;
|
||||
for (std::size_t frame = 0; frame < 1000; ++frame) {
|
||||
require(samples[frame * 2] == samples[frame * 2 + 1], "both channels get the same gain");
|
||||
require(previous - samples[frame * 2] <= 136.0f / 65536.0f + 1e-6f, "no float step exceeds the ramp slope");
|
||||
require(samples[frame * 2] <= previous, "a float ramp down never rises");
|
||||
previous = samples[frame * 2];
|
||||
}
|
||||
require(previous == 0.0f, "the float ramp ends in silence");
|
||||
}
|
||||
|
||||
void f32RampContinuesAcrossBuffers() {
|
||||
auto whole = constantF32(3000, 8, 0.75f);
|
||||
HostGainRamp wholeRamp;
|
||||
wholeRamp.Apply(whole.data(), 3000, 8, 16384);
|
||||
auto split = constantF32(3000, 8, 0.75f);
|
||||
HostGainRamp splitRamp;
|
||||
std::size_t done = 0;
|
||||
for (const std::size_t chunk : {5u, 1u, 480u, 481u, 2033u}) {
|
||||
splitRamp.Apply(split.data() + done * 8, chunk, 8, 16384);
|
||||
done += chunk;
|
||||
}
|
||||
require(done == 3000, "the float chunks cover the buffer");
|
||||
require(std::memcmp(whole.data(), split.data(), whole.size() * sizeof(float)) == 0, "a float ramp split across buffers equals the same ramp in one buffer");
|
||||
}
|
||||
|
||||
void f32DoesNotClamp() {
|
||||
HostGainRamp ramp(1);
|
||||
auto samples = constantF32(2, 1, 0.75f);
|
||||
ramp.Apply(samples.data(), 2, 1, 4 * HostGainRamp::Unity);
|
||||
require(samples[0] == 1.5f && samples[1] == 2.25f, "float samples above one are left for the device to clip");
|
||||
}
|
||||
|
||||
void filterPassesTheTitleBufferAtUnity() {
|
||||
std::vector<std::int16_t> title = constantS16(64, 2, 4321);
|
||||
std::vector<std::uint8_t> scratch;
|
||||
HostGainRamp ramp;
|
||||
const void* out = HostGainFilter(ramp, HostGainRamp::Unity, title.data(), false, 64, 2, scratch);
|
||||
require(out == title.data(), "at unity the filter returns the title's own pointer");
|
||||
require(scratch.empty(), "at unity the filter copies nothing");
|
||||
std::vector<float> titleFloat = constantF32(64, 8, 0.25f);
|
||||
out = HostGainFilter(ramp, HostGainRamp::Unity, titleFloat.data(), true, 64, 8, scratch);
|
||||
require(out == titleFloat.data() && scratch.empty(), "the same holds for float");
|
||||
}
|
||||
|
||||
void filterLeavesTheTitleBufferUntouched() {
|
||||
std::vector<std::int16_t> title = constantS16(64, 2, 4321);
|
||||
const auto before = title;
|
||||
std::vector<std::uint8_t> scratch;
|
||||
HostGainRamp ramp(1);
|
||||
const void* out = HostGainFilter(ramp, 0, title.data(), false, 64, 2, scratch);
|
||||
require(out == scratch.data(), "a changed gain returns the scratch copy");
|
||||
require(title == before, "the title's buffer is never written");
|
||||
const auto* result = static_cast<const std::int16_t*>(out);
|
||||
for (std::size_t index = 0; index < title.size(); ++index) require(result[index] == 0, "the copy is silent");
|
||||
}
|
||||
|
||||
void filterWorksInPlaceOnTheScratchBuffer() {
|
||||
std::vector<std::uint8_t> scratch(64 * 2 * sizeof(float));
|
||||
auto* floats = reinterpret_cast<float*>(scratch.data());
|
||||
for (std::size_t index = 0; index < 128; ++index) floats[index] = 1.0f;
|
||||
HostGainRamp ramp(1);
|
||||
const void* out = HostGainFilter(ramp, 0, scratch.data(), true, 64, 2, scratch);
|
||||
require(out == scratch.data(), "in place keeps the scratch pointer");
|
||||
for (std::size_t index = 0; index < 128; ++index) require(floats[index] == 0.0f, "in place applies the gain");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() try {
|
||||
s16BypassAtUnity();
|
||||
s16FirstSampleOfRamp();
|
||||
s16RampReachesTargetExactly();
|
||||
s16RampHasNoDiscontinuity();
|
||||
s16RampContinuesAcrossBuffers();
|
||||
s16SaturatesAboveUnity();
|
||||
s16ChannelsShareTheFrameGain();
|
||||
s16SilentTargetSilencesAfterRamp();
|
||||
s16ReturnToUnityBypassesAgain();
|
||||
s16RoundsHalfUp();
|
||||
s16RampUpLandsExactly();
|
||||
f32BypassAtUnity();
|
||||
f32FirstSampleAndLanding();
|
||||
f32RampHasNoDiscontinuity();
|
||||
f32RampContinuesAcrossBuffers();
|
||||
f32DoesNotClamp();
|
||||
filterPassesTheTitleBufferAtUnity();
|
||||
filterLeavesTheTitleBufferUntouched();
|
||||
filterWorksInPlaceOnTheScratchBuffer();
|
||||
std::puts("host gain tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "%s\n", error.what());
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
#include "prx/libScePad/include/HostVolume.hpp"
|
||||
#include "prx/libScePad/include/HostVolumeSettings.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
void require(bool condition, const char* message) {
|
||||
if (!condition) throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
void defaultState() {
|
||||
HostVolume state;
|
||||
require(state.Volume() == 100, "the volume starts at 100");
|
||||
require(!state.Muted(), "the host volume starts unmuted");
|
||||
}
|
||||
|
||||
void stepsDown() {
|
||||
HostVolume state;
|
||||
for (int expected = 95; expected >= 0; expected -= 5) {
|
||||
require(state.VolumeDown(), "a step down from above 0 changes the volume");
|
||||
require(state.Volume() == expected, "each step down removes 5");
|
||||
}
|
||||
require(state.Volume() == 0, "twenty steps reach 0");
|
||||
}
|
||||
|
||||
void stepsStopAtZero() {
|
||||
HostVolume state;
|
||||
for (int step = 0; step < 20; ++step) state.VolumeDown();
|
||||
require(!state.VolumeDown(), "a step down at 0 reports no change");
|
||||
require(state.Volume() == 0, "the volume never goes below 0");
|
||||
}
|
||||
|
||||
void stepsUp() {
|
||||
HostVolume state;
|
||||
for (int step = 0; step < 20; ++step) state.VolumeDown();
|
||||
for (int expected = 5; expected <= 100; expected += 5) {
|
||||
require(state.VolumeUp(), "a step up from below 100 changes the volume");
|
||||
require(state.Volume() == expected, "each step up adds 5");
|
||||
}
|
||||
}
|
||||
|
||||
void stepsStopAtMaximum() {
|
||||
HostVolume state;
|
||||
require(!state.VolumeUp(), "a step up at 100 reports no change");
|
||||
require(state.Volume() == 100, "the volume never goes above 100");
|
||||
}
|
||||
|
||||
void muteKeepsVolume() {
|
||||
HostVolume state;
|
||||
state.VolumeDown();
|
||||
state.VolumeDown();
|
||||
require(state.Volume() == 90, "two steps down give 90");
|
||||
require(state.ToggleMute(), "muting changes the state");
|
||||
require(state.Muted() && state.Volume() == 90, "muting leaves the volume alone");
|
||||
require(state.ToggleMute(), "unmuting changes the state");
|
||||
require(!state.Muted() && state.Volume() == 90, "unmuting restores the volume that was set");
|
||||
}
|
||||
|
||||
void muteAtZeroAndMaximum() {
|
||||
HostVolume state;
|
||||
state.ToggleMute();
|
||||
require(state.Volume() == 100, "muting at 100 keeps 100");
|
||||
state.ToggleMute();
|
||||
for (int step = 0; step < 20; ++step) state.VolumeDown();
|
||||
state.ToggleMute();
|
||||
require(state.Muted() && state.Volume() == 0, "muting at 0 keeps 0");
|
||||
state.ToggleMute();
|
||||
require(!state.Muted() && state.Volume() == 0, "unmuting at 0 leaves 0");
|
||||
}
|
||||
|
||||
void stepsEndMute() {
|
||||
HostVolume state;
|
||||
state.VolumeDown();
|
||||
state.ToggleMute();
|
||||
require(state.VolumeUp(), "a step up while muted changes the state");
|
||||
require(!state.Muted() && state.Volume() == 100, "a step up while muted unmutes and moves the volume");
|
||||
state.ToggleMute();
|
||||
require(state.VolumeDown(), "a step down while muted changes the state");
|
||||
require(!state.Muted() && state.Volume() == 95, "a step down while muted unmutes and moves the volume");
|
||||
}
|
||||
|
||||
void stepsAtLimitsStillEndMute() {
|
||||
HostVolume top;
|
||||
top.ToggleMute();
|
||||
require(top.VolumeUp(), "a step up at 100 while muted reports the unmute");
|
||||
require(!top.Muted() && top.Volume() == 100, "a step up at 100 while muted only unmutes");
|
||||
require(!top.VolumeUp(), "a second step up at 100 reports no change");
|
||||
HostVolume bottom;
|
||||
for (int step = 0; step < 20; ++step) bottom.VolumeDown();
|
||||
bottom.ToggleMute();
|
||||
require(bottom.VolumeDown(), "a step down at 0 while muted reports the unmute");
|
||||
require(!bottom.Muted() && bottom.Volume() == 0, "a step down at 0 while muted only unmutes");
|
||||
}
|
||||
|
||||
void setVolumeDirectly() {
|
||||
HostVolume state;
|
||||
require(state.SetVolume(35), "a new volume reports a change");
|
||||
require(state.Volume() == 35, "the volume takes the value set");
|
||||
require(!state.SetVolume(35), "the same volume reports no change");
|
||||
require(state.SetVolume(0) && state.Volume() == 0, "0 is accepted");
|
||||
require(state.SetVolume(100) && state.Volume() == 100, "100 is accepted");
|
||||
state.ToggleMute();
|
||||
state.SetVolume(40);
|
||||
require(state.Muted(), "setting the volume leaves the mute alone");
|
||||
}
|
||||
|
||||
void setVolumeRefusesOutOfRange() {
|
||||
HostVolume state;
|
||||
state.SetVolume(60);
|
||||
for (const int value : {-1, 101, 1000, -100}) {
|
||||
bool refused = false;
|
||||
try {
|
||||
state.SetVolume(value);
|
||||
} catch (const std::invalid_argument&) {
|
||||
refused = true;
|
||||
}
|
||||
require(refused, "a volume outside 0 to 100 is refused");
|
||||
require(state.Volume() == 60, "a refused volume leaves the state as it was");
|
||||
}
|
||||
}
|
||||
|
||||
void focusIgnoredByDefault() {
|
||||
HostVolume state;
|
||||
require(!state.MuteOnFocusLoss(), "muting on focus loss is off by default");
|
||||
require(!state.FocusChanged(false), "losing focus changes nothing with the option off");
|
||||
require(!state.FocusMuted(), "no focus mute with the option off");
|
||||
require(!state.FocusChanged(true), "gaining focus changes nothing with the option off");
|
||||
}
|
||||
|
||||
void focusLossMutesAndGainRestores() {
|
||||
HostVolume state;
|
||||
state.SetMuteOnFocusLoss(true);
|
||||
require(!state.FocusMuted(), "a focused window is not focus muted");
|
||||
require(state.FocusChanged(false), "losing focus reports a change");
|
||||
require(state.FocusMuted(), "a window without focus is focus muted");
|
||||
require(!state.FocusChanged(false), "losing focus twice reports no second change");
|
||||
require(state.FocusChanged(true), "gaining focus reports a change");
|
||||
require(!state.FocusMuted(), "gaining focus ends the focus mute");
|
||||
}
|
||||
|
||||
void focusMuteKeepsUserState() {
|
||||
HostVolume state;
|
||||
state.SetMuteOnFocusLoss(true);
|
||||
state.VolumeDown();
|
||||
state.ToggleMute();
|
||||
state.FocusChanged(false);
|
||||
state.FocusChanged(true);
|
||||
require(state.Muted() && state.Volume() == 95, "a focus round trip leaves the user's mute and volume");
|
||||
state.ToggleMute();
|
||||
state.FocusChanged(false);
|
||||
require(!state.Muted() && state.Volume() == 95, "the focus mute does not touch the muted flag");
|
||||
}
|
||||
|
||||
void focusOptionTogglesWhileUnfocused() {
|
||||
HostVolume state;
|
||||
state.FocusChanged(false);
|
||||
require(!state.FocusMuted(), "an unfocused window is not muted with the option off");
|
||||
require(state.SetMuteOnFocusLoss(true), "turning the option on while unfocused mutes");
|
||||
require(state.FocusMuted(), "the unfocused window is muted once the option is on");
|
||||
require(state.SetMuteOnFocusLoss(false), "turning the option off ends the focus mute");
|
||||
require(!state.FocusMuted(), "the focus mute is gone with the option off");
|
||||
}
|
||||
|
||||
void gainAtDefaultIsUnity() {
|
||||
HostVolume state;
|
||||
require(state.Gain() == HostVolume::UnityGain, "the default gain is exactly unity");
|
||||
require(HostVolume::UnityGain == 65536, "unity is 1.0 in 16.16 fixed point");
|
||||
}
|
||||
|
||||
void gainFollowsVolume() {
|
||||
HostVolume state;
|
||||
state.SetVolume(50);
|
||||
require(state.Gain() == 16384, "50 percent is a quarter of the amplitude");
|
||||
state.SetVolume(0);
|
||||
require(state.Gain() == 0, "0 is silence");
|
||||
std::uint32_t previous = 0;
|
||||
for (int volume = 1; volume <= 100; ++volume) {
|
||||
state.SetVolume(volume);
|
||||
require(state.Gain() > previous, "the gain grows with every volume");
|
||||
require(state.Gain() <= HostVolume::UnityGain, "the gain never exceeds unity");
|
||||
previous = state.Gain();
|
||||
}
|
||||
}
|
||||
|
||||
void gainIsZeroWhenSilent() {
|
||||
HostVolume state;
|
||||
state.ToggleMute();
|
||||
require(state.Gain() == 0 && state.Silent(), "a muted state has no gain");
|
||||
state.ToggleMute();
|
||||
require(state.Gain() == HostVolume::UnityGain && !state.Silent(), "unmuting restores the gain");
|
||||
state.SetMuteOnFocusLoss(true);
|
||||
state.FocusChanged(false);
|
||||
require(state.Gain() == 0 && state.Silent(), "a focus muted state has no gain");
|
||||
state.FocusChanged(true);
|
||||
require(state.Gain() == HostVolume::UnityGain, "gaining focus restores the gain");
|
||||
}
|
||||
|
||||
bool refusedWith(void (*parse)(), const char* name) {
|
||||
try {
|
||||
parse();
|
||||
} catch (const std::runtime_error& error) {
|
||||
return std::string(error.what()).find(name) != std::string::npos;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void flagParsing() {
|
||||
require(!ParseHostVolumeFlag("ANYPS5_MUTE_ON_FOCUS_LOSS", "0"), "0 turns the flag off");
|
||||
require(ParseHostVolumeFlag("ANYPS5_MUTE_ON_FOCUS_LOSS", "1"), "1 turns the flag on");
|
||||
require(refusedWith([] { ParseHostVolumeFlag("ANYPS5_MUTE_ON_FOCUS_LOSS", ""); }, "ANYPS5_MUTE_ON_FOCUS_LOSS"), "an empty flag is refused and named");
|
||||
require(refusedWith([] { ParseHostVolumeFlag("ANYPS5_MUTE_ON_FOCUS_LOSS", "yes"); }, "ANYPS5_MUTE_ON_FOCUS_LOSS"), "yes is refused and named");
|
||||
require(refusedWith([] { ParseHostVolumeFlag("ANYPS5_MUTE_ON_FOCUS_LOSS", "true"); }, "ANYPS5_MUTE_ON_FOCUS_LOSS"), "true is refused and named");
|
||||
require(refusedWith([] { ParseHostVolumeFlag("ANYPS5_MUTE_ON_FOCUS_LOSS", "2"); }, "ANYPS5_MUTE_ON_FOCUS_LOSS"), "2 is refused and named");
|
||||
require(refusedWith([] { ParseHostVolumeFlag("ANYPS5_MUTE_ON_FOCUS_LOSS", " 1"); }, "ANYPS5_MUTE_ON_FOCUS_LOSS"), "a padded 1 is refused and named");
|
||||
require(refusedWith([] { ParseHostVolumeFlag("ANYPS5_MUTE_ON_FOCUS_LOSS", "01"); }, "ANYPS5_MUTE_ON_FOCUS_LOSS"), "01 is refused and named");
|
||||
}
|
||||
|
||||
void levelParsing() {
|
||||
require(ParseHostVolumeLevel("ANYPS5_VOLUME", "0") == 0, "0 is a level");
|
||||
require(ParseHostVolumeLevel("ANYPS5_VOLUME", "100") == 100, "100 is a level");
|
||||
require(ParseHostVolumeLevel("ANYPS5_VOLUME", "37") == 37, "any whole number in range is a level");
|
||||
for (const char* bad : {"", "-1", "101", "50.5", "5 0", "abc", "+50", " 50", "50 ", "1e1", "99999999999999999999"}) {
|
||||
bool refused = false;
|
||||
try {
|
||||
ParseHostVolumeLevel("ANYPS5_VOLUME", bad);
|
||||
} catch (const std::runtime_error& error) {
|
||||
refused = std::string(error.what()).find("ANYPS5_VOLUME") != std::string::npos;
|
||||
}
|
||||
require(refused, "a level outside 0 to 100 or not a whole number is refused and named");
|
||||
}
|
||||
}
|
||||
|
||||
void messages() {
|
||||
HostVolume state;
|
||||
require(HostVolumeMessage(state) == "Host volume: 100%", "the default message gives the level");
|
||||
state.VolumeDown();
|
||||
require(HostVolumeMessage(state) == "Host volume: 95%", "a step shows the new level");
|
||||
state.ToggleMute();
|
||||
require(HostVolumeMessage(state) == "Host volume: muted (volume 95%)", "a mute shows the level it will return to");
|
||||
state.ToggleMute();
|
||||
state.SetMuteOnFocusLoss(true);
|
||||
state.FocusChanged(false);
|
||||
require(HostVolumeMessage(state) == "Host volume: muted while the window has no focus (volume 95%)", "a focus mute says why");
|
||||
state.ToggleMute();
|
||||
require(HostVolumeMessage(state) == "Host volume: muted (volume 95%)", "the user's mute takes precedence in the message");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() try {
|
||||
defaultState();
|
||||
stepsDown();
|
||||
stepsStopAtZero();
|
||||
stepsUp();
|
||||
stepsStopAtMaximum();
|
||||
muteKeepsVolume();
|
||||
muteAtZeroAndMaximum();
|
||||
stepsEndMute();
|
||||
stepsAtLimitsStillEndMute();
|
||||
setVolumeDirectly();
|
||||
setVolumeRefusesOutOfRange();
|
||||
focusIgnoredByDefault();
|
||||
focusLossMutesAndGainRestores();
|
||||
focusMuteKeepsUserState();
|
||||
focusOptionTogglesWhileUnfocused();
|
||||
gainAtDefaultIsUnity();
|
||||
gainFollowsVolume();
|
||||
gainIsZeroWhenSilent();
|
||||
flagParsing();
|
||||
levelParsing();
|
||||
messages();
|
||||
std::puts("host volume tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "%s\n", error.what());
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
#include "prx/libScePad/include/HostVolumeControl.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
|
||||
void require(bool condition, const char* message) {
|
||||
if (!condition) throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
void setEnvironment(const char* name, const char* value) {
|
||||
#ifdef _WIN32
|
||||
require(_putenv_s(name, value != nullptr ? value : "") == 0, "set the environment variable");
|
||||
#else
|
||||
if (value != nullptr) require(::setenv(name, value, 1) == 0, "set the environment variable");
|
||||
else require(::unsetenv(name) == 0, "unset the environment variable");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool refusesNaming(const char* volume, const char* flag, const char* name) {
|
||||
try {
|
||||
HostVolumeConfigure_nid_no_patch(volume, flag);
|
||||
} catch (const std::runtime_error& error) {
|
||||
return std::string(error.what()).find(name) != std::string::npos;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void defaultIsUnity() {
|
||||
HostVolumeConfigure_nid_no_patch(nullptr, nullptr);
|
||||
require(HostVolumeGain_nid_no_patch() == HostVolume::UnityGain, "the shared gain starts at exactly unity");
|
||||
}
|
||||
|
||||
void commandsPublishTheGain() {
|
||||
HostVolumeConfigure_nid_no_patch(nullptr, nullptr);
|
||||
HostVolume after;
|
||||
require(!HostVolumeApply_nid_no_patch(HostVolumeCommand::VolumeUp, &after), "a step up at 100 changes nothing");
|
||||
require(HostVolumeGain_nid_no_patch() == HostVolume::UnityGain, "a step that changes nothing keeps unity");
|
||||
require(HostVolumeApply_nid_no_patch(HostVolumeCommand::VolumeDown, &after), "a step down changes the volume");
|
||||
require(after.Volume() == 95 && HostVolumeGain_nid_no_patch() == after.Gain(), "the gain follows the volume");
|
||||
require(HostVolumeApply_nid_no_patch(HostVolumeCommand::ToggleMute, &after), "mute changes the state");
|
||||
require(after.Muted() && HostVolumeGain_nid_no_patch() == 0, "mute publishes a zero gain");
|
||||
require(HostVolumeApply_nid_no_patch(HostVolumeCommand::ToggleMute, nullptr), "unmute works without an out parameter");
|
||||
HostVolumeApply_nid_no_patch(HostVolumeCommand::VolumeUp, &after);
|
||||
require(HostVolumeGain_nid_no_patch() == HostVolume::UnityGain, "stepping back to 100 returns to exactly unity");
|
||||
}
|
||||
|
||||
void focusOnlyActsWhenEnabled() {
|
||||
HostVolumeConfigure_nid_no_patch(nullptr, nullptr);
|
||||
HostVolume after;
|
||||
require(!HostVolumeFocus_nid_no_patch(false, &after), "losing focus changes nothing by default");
|
||||
require(HostVolumeGain_nid_no_patch() == HostVolume::UnityGain, "the gain stays at unity without the option");
|
||||
HostVolumeFocus_nid_no_patch(true, nullptr);
|
||||
HostVolumeConfigure_nid_no_patch(nullptr, "1");
|
||||
require(HostVolumeGain_nid_no_patch() == HostVolume::UnityGain, "the option alone does not mute a focused window");
|
||||
require(HostVolumeFocus_nid_no_patch(false, &after), "losing focus with the option on changes the state");
|
||||
require(after.FocusMuted() && HostVolumeGain_nid_no_patch() == 0, "a window without focus is silent");
|
||||
require(HostVolumeFocus_nid_no_patch(true, &after), "gaining focus changes the state");
|
||||
require(!after.FocusMuted() && HostVolumeGain_nid_no_patch() == HostVolume::UnityGain, "gaining focus restores the gain");
|
||||
}
|
||||
|
||||
void configureTakesInitialValues() {
|
||||
HostVolumeConfigure_nid_no_patch("40", "0");
|
||||
HostVolume after;
|
||||
HostVolumeApply_nid_no_patch(HostVolumeCommand::VolumeUp, &after);
|
||||
require(after.Volume() == 45, "the initial volume is the one configured");
|
||||
require(!after.MuteOnFocusLoss(), "the flag 0 leaves the option off");
|
||||
HostVolumeConfigure_nid_no_patch("0", nullptr);
|
||||
require(HostVolumeGain_nid_no_patch() == 0, "an initial volume of 0 is silent");
|
||||
HostVolumeConfigure_nid_no_patch(nullptr, nullptr);
|
||||
require(HostVolumeGain_nid_no_patch() == HostVolume::UnityGain, "configuring without values returns to the default");
|
||||
}
|
||||
|
||||
void invalidValuesLeaveTheStateAlone() {
|
||||
HostVolumeConfigure_nid_no_patch("30", nullptr);
|
||||
const auto gain = HostVolumeGain_nid_no_patch();
|
||||
require(refusesNaming("101", nullptr, "ANYPS5_VOLUME"), "an out-of-range volume is refused and named");
|
||||
require(refusesNaming("loud", nullptr, "ANYPS5_VOLUME"), "a non-numeric volume is refused and named");
|
||||
require(refusesNaming(nullptr, "yes", "ANYPS5_MUTE_ON_FOCUS_LOSS"), "an invalid flag is refused and named");
|
||||
require(refusesNaming("50", "2", "ANYPS5_MUTE_ON_FOCUS_LOSS"), "an invalid flag next to a valid volume is refused and named");
|
||||
require(HostVolumeGain_nid_no_patch() == gain, "a refused configuration leaves the gain as it was");
|
||||
HostVolume after;
|
||||
HostVolumeApply_nid_no_patch(HostVolumeCommand::VolumeUp, &after);
|
||||
require(after.Volume() == 35, "a refused configuration leaves the volume as it was");
|
||||
HostVolumeConfigure_nid_no_patch(nullptr, nullptr);
|
||||
}
|
||||
|
||||
void environmentIsRead() {
|
||||
setEnvironment("ANYPS5_VOLUME", nullptr);
|
||||
setEnvironment("ANYPS5_MUTE_ON_FOCUS_LOSS", nullptr);
|
||||
HostVolumeConfigureFromEnvironment_nid_no_patch();
|
||||
require(HostVolumeGain_nid_no_patch() == HostVolume::UnityGain, "unset variables keep the default");
|
||||
HostVolume after;
|
||||
HostVolumeFocus_nid_no_patch(false, &after);
|
||||
require(!after.FocusMuted(), "an unset ANYPS5_MUTE_ON_FOCUS_LOSS leaves the option off");
|
||||
HostVolumeFocus_nid_no_patch(true, nullptr);
|
||||
setEnvironment("ANYPS5_VOLUME", "60");
|
||||
setEnvironment("ANYPS5_MUTE_ON_FOCUS_LOSS", "1");
|
||||
HostVolumeConfigureFromEnvironment_nid_no_patch();
|
||||
HostVolumeFocus_nid_no_patch(false, &after);
|
||||
require(after.FocusMuted() && after.Volume() == 60, "both variables are applied");
|
||||
setEnvironment("ANYPS5_MUTE_ON_FOCUS_LOSS", "maybe");
|
||||
bool refused = false;
|
||||
try {
|
||||
HostVolumeConfigureFromEnvironment_nid_no_patch();
|
||||
} catch (const std::runtime_error& error) {
|
||||
refused = std::string(error.what()).find("ANYPS5_MUTE_ON_FOCUS_LOSS") != std::string::npos;
|
||||
}
|
||||
require(refused, "an invalid variable from the environment is refused and named");
|
||||
setEnvironment("ANYPS5_VOLUME", nullptr);
|
||||
setEnvironment("ANYPS5_MUTE_ON_FOCUS_LOSS", nullptr);
|
||||
HostVolumeConfigureFromEnvironment_nid_no_patch();
|
||||
}
|
||||
|
||||
void readersSeeOnlyValidGains() {
|
||||
HostVolumeConfigure_nid_no_patch(nullptr, nullptr);
|
||||
std::atomic<bool> stop{false};
|
||||
std::atomic<bool> bad{false};
|
||||
std::thread reader([&] {
|
||||
while (!stop.load()) {
|
||||
const auto gain = HostVolumeGain_nid_no_patch();
|
||||
if (gain > HostVolume::UnityGain) bad.store(true);
|
||||
}
|
||||
});
|
||||
for (int round = 0; round < 20000; ++round) {
|
||||
HostVolumeApply_nid_no_patch(round % 3 == 0 ? HostVolumeCommand::ToggleMute : round % 3 == 1 ? HostVolumeCommand::VolumeDown : HostVolumeCommand::VolumeUp, nullptr);
|
||||
}
|
||||
stop.store(true);
|
||||
reader.join();
|
||||
require(!bad.load(), "a reader never sees a gain above unity while commands run");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() try {
|
||||
defaultIsUnity();
|
||||
commandsPublishTheGain();
|
||||
focusOnlyActsWhenEnabled();
|
||||
configureTakesInitialValues();
|
||||
invalidValuesLeaveTheStateAlone();
|
||||
environmentIsRead();
|
||||
readersSeeOnlyValidGains();
|
||||
std::puts("host volume state tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "%s\n", error.what());
|
||||
return 1;
|
||||
}
|
||||
@@ -224,6 +224,7 @@ std::int32_t APS5_VABI sceAudioPropagationSourceCalculateAudioPaths(AudioPropaga
|
||||
std::int32_t APS5_VABI sceAudioPropagationSourceSetAudioPaths(AudioPropagationHandle source, const void* entries, std::uint32_t count);
|
||||
std::int32_t APS5_VABI sceAudioPropagationSourceSetAudioPath(AudioPropagationHandle path, const AudioPropagation::AudioPath* data, float gain);
|
||||
std::int32_t APS5_VABI sceAudioPropagationSourceRender(AudioPropagationHandle system, AudioPropagation::RenderInfo* infos, std::uint32_t count);
|
||||
int APS5_VABI sceAudioPropagationSourceQueryAudioPaths();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
add_library(libSceAudioPropagation SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
add_library(libSceAudioPropagation SHARED EXCLUDE_FROM_ALL Export.cpp InventoryExports.cpp)
|
||||
target_include_directories(libSceAudioPropagation PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceAudioPropagation)
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "prx/libSceAudioPropagation/AudioPropagation.hpp"
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceAudioPropagationSourceQueryAudioPaths() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI libSceAudioPropagationUnknown_TrQMW7ARZXY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("TrQMW7ARZXY", libSceAudioPropagationUnknown_TrQMW7ARZXY_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioPropagationUnknown_ZSdiF_plus_pXrF8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("ZSdiF+pXrF8", libSceAudioPropagationUnknown_ZSdiF_plus_pXrF8_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioPropagationUnknown_fOTrQvqzABM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("fOTrQvqzABM", libSceAudioPropagationUnknown_fOTrQvqzABM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioPropagationUnknown_fhMkXxnE8aw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("fhMkXxnE8aw", libSceAudioPropagationUnknown_fhMkXxnE8aw_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioPropagationUnknown_laU0fM_minus_tTsc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("laU0fM-tTsc", libSceAudioPropagationUnknown_laU0fM_minus_tTsc_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioPropagationUnknown_mdH4mANi9GI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("mdH4mANi9GI", libSceAudioPropagationUnknown_mdH4mANi9GI_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAudioPropagationUnknown_o0gGIp1vd6A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("o0gGIp1vd6A", libSceAudioPropagationUnknown_o0gGIp1vd6A_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceAvcap2mvr/include/InventoryExports.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
@@ -8,3 +10,72 @@ extern "C" {
|
||||
APS5_DUMMY_FUN
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_AVuH0FujF30_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("AVuH0FujF30", libSceAvcap2mvrUnknown_AVuH0FujF30_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_JgAC1LkbWns_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("JgAC1LkbWns", libSceAvcap2mvrUnknown_JgAC1LkbWns_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_Kt2IOGEfaFc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Kt2IOGEfaFc", libSceAvcap2mvrUnknown_Kt2IOGEfaFc_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_Mq1MuGlr48g_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Mq1MuGlr48g", libSceAvcap2mvrUnknown_Mq1MuGlr48g_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_QSLdUawhEhg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("QSLdUawhEhg", libSceAvcap2mvrUnknown_QSLdUawhEhg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_R5tFB0tMbgY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("R5tFB0tMbgY", libSceAvcap2mvrUnknown_R5tFB0tMbgY_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_Tjmx_plus_DOF65c_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Tjmx+DOF65c", libSceAvcap2mvrUnknown_Tjmx_plus_DOF65c_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_ZMR_plus_Q0NYcmU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("ZMR+Q0NYcmU", libSceAvcap2mvrUnknown_ZMR_plus_Q0NYcmU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_nPlusHmt9NY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("nPlusHmt9NY", libSceAvcap2mvrUnknown_nPlusHmt9NY_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_s7aQGkLitBU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("s7aQGkLitBU", libSceAvcap2mvrUnknown_s7aQGkLitBU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_sM27f1nWpCc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("sM27f1nWpCc", libSceAvcap2mvrUnknown_sM27f1nWpCc_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_tq_minus_PG8QaNDM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("tq-PG8QaNDM", libSceAvcap2mvrUnknown_tq_minus_PG8QaNDM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_u4wtg4AegL8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("u4wtg4AegL8", libSceAvcap2mvrUnknown_u4wtg4AegL8_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_AVuH0FujF30_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_JgAC1LkbWns_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_Kt2IOGEfaFc_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_Mq1MuGlr48g_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_QSLdUawhEhg_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_R5tFB0tMbgY_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_Tjmx_plus_DOF65c_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_ZMR_plus_Q0NYcmU_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_nPlusHmt9NY_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_s7aQGkLitBU_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_sM27f1nWpCc_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_tq_minus_PG8QaNDM_nid_no_patch();
|
||||
int APS5_VABI libSceAvcap2mvrUnknown_u4wtg4AegL8_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
#pragma once
|
||||
#include "prx/libSceAvcap2mvr/include/InventoryExports.hpp"
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceBemp2sys/include/InventoryExports.hpp"
|
||||
#include "prx/libSceBemp2sys/include/Api.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -163,3 +165,17 @@ int APS5_VABI bemp2sys_tsfilter_sendmessage_nid_postfix(void) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceBemp2sysUnknown_1L1WwRMiys8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("1L1WwRMiys8", libSceBemp2sysUnknown_1L1WwRMiys8_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceBemp2sysUnknown_B1nK_plus_wb5rME_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("B1nK+wb5rME", libSceBemp2sysUnknown_B1nK_plus_wb5rME_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceBemp2sysUnknown_1L1WwRMiys8_nid_no_patch();
|
||||
int APS5_VABI libSceBemp2sysUnknown_B1nK_plus_wb5rME_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "prx/libSceBemp2sys/include/Api.hpp"
|
||||
#include "prx/libSceBemp2sys/include/InventoryExports.hpp"
|
||||
@@ -1,3 +1,6 @@
|
||||
#include "prx/libSceBgsStorage/include/LegacyExports.hpp"
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceBgsStorage/include/InventoryExports.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
@@ -8,3 +11,96 @@ extern "C" {
|
||||
APS5_DUMMY_FUN
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceBgsStorageUnknown_BauWWA9gkBc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("BauWWA9gkBc", libSceBgsStorageUnknown_BauWWA9gkBc_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceBgsStorageUnknown_JK67MBtUF5A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("JK67MBtUF5A", libSceBgsStorageUnknown_JK67MBtUF5A_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceBgsStorageUnknown_PQqTvPT8G2E_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("PQqTvPT8G2E", libSceBgsStorageUnknown_PQqTvPT8G2E_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceBgsStorageUnknown_kS74ICPn0MQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("kS74ICPn0MQ", libSceBgsStorageUnknown_kS74ICPn0MQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceBgsStorageUnknown_mTm6O2Zjiak_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("mTm6O2Zjiak", libSceBgsStorageUnknown_mTm6O2Zjiak_nid_no_patch);
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_2jhIwp44HLs_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("2jhIwp44HLs", bgsStorageLegacyUnknown_2jhIwp44HLs_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_40CYAu5xSh4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("40CYAu5xSh4", bgsStorageLegacyUnknown_40CYAu5xSh4_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_5GiiauJT87Q_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("5GiiauJT87Q", bgsStorageLegacyUnknown_5GiiauJT87Q_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_BD5wCFYcXKs_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("BD5wCFYcXKs", bgsStorageLegacyUnknown_BD5wCFYcXKs_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_C3LOXcpeDRk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("C3LOXcpeDRk", bgsStorageLegacyUnknown_C3LOXcpeDRk_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_FMDgC1Y8kGc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("FMDgC1Y8kGc", bgsStorageLegacyUnknown_FMDgC1Y8kGc_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_FMzg32vgtD8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("FMzg32vgtD8", bgsStorageLegacyUnknown_FMzg32vgtD8_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_L1lmQDSeYU8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("L1lmQDSeYU8", bgsStorageLegacyUnknown_L1lmQDSeYU8_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_PAXTtEXpfeo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("PAXTtEXpfeo", bgsStorageLegacyUnknown_PAXTtEXpfeo_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_hV1GHcoRNL0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("hV1GHcoRNL0", bgsStorageLegacyUnknown_hV1GHcoRNL0_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_j4C7FEFohO4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("j4C7FEFohO4", bgsStorageLegacyUnknown_j4C7FEFohO4_nid_no_patch);
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_ttm4oYz6IXs_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("ttm4oYz6IXs", bgsStorageLegacyUnknown_ttm4oYz6IXs_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceBgsStorageUnknown_BauWWA9gkBc_nid_no_patch();
|
||||
int APS5_VABI libSceBgsStorageUnknown_JK67MBtUF5A_nid_no_patch();
|
||||
int APS5_VABI libSceBgsStorageUnknown_PQqTvPT8G2E_nid_no_patch();
|
||||
int APS5_VABI libSceBgsStorageUnknown_kS74ICPn0MQ_nid_no_patch();
|
||||
int APS5_VABI libSceBgsStorageUnknown_mTm6O2Zjiak_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI bgsStorageLegacyUnknown_2jhIwp44HLs_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_40CYAu5xSh4_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_5GiiauJT87Q_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_BD5wCFYcXKs_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_C3LOXcpeDRk_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_FMDgC1Y8kGc_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_FMzg32vgtD8_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_L1lmQDSeYU8_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_PAXTtEXpfeo_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_hV1GHcoRNL0_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_j4C7FEFohO4_nid_no_patch();
|
||||
int APS5_VABI bgsStorageLegacyUnknown_ttm4oYz6IXs_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
#pragma once
|
||||
#include "prx/libSceBgsStorage/include/InventoryExports.hpp"
|
||||
#include "prx/libSceBgsStorage/include/LegacyExports.hpp"
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceCamera/include/InventoryExports.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
@@ -24,3 +25,22 @@ int APS5_VABI sceCameraIsVrCaptureEnable() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceCameraUnknown_AnqFx_minus_nAxZM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("AnqFx-nAxZM", libSceCameraUnknown_AnqFx_minus_nAxZM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCameraUnknown_azeU8qML4VM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("azeU8qML4VM", libSceCameraUnknown_azeU8qML4VM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCameraUnknown_kgRnfleNYNo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("kgRnfleNYNo", libSceCameraUnknown_kgRnfleNYNo_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -11,3 +11,9 @@ int APS5_VABI sceCameraSetForceDriverMode();
|
||||
int APS5_VABI sceCameraIsVrCaptureEnable();
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI libSceCameraUnknown_AnqFx_minus_nAxZM_nid_no_patch();
|
||||
int APS5_VABI libSceCameraUnknown_azeU8qML4VM_nid_no_patch();
|
||||
int APS5_VABI libSceCameraUnknown_kgRnfleNYNo_nid_no_patch();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "prx/libSceCdlgAdIdClient/include/Api.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
APS5_EXPORT("Lx1FeCVnfo8", sceCdlgAdIdClientUnknown00);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown00(void) {
|
||||
NotImplemented_nid_no_patch("Lx1FeCVnfo8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("IdatGKppXCA", sceCdlgAdIdClientUnknown01);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown01(void) {
|
||||
NotImplemented_nid_no_patch("IdatGKppXCA");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("YlO3Zs7q+20", sceCdlgAdIdClientUnknown02);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown02(void) {
|
||||
NotImplemented_nid_no_patch("YlO3Zs7q+20");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("cOw39NTIbU0", sceCdlgAdIdClientUnknown03);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown03(void) {
|
||||
NotImplemented_nid_no_patch("cOw39NTIbU0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("Z-mCvugj6Ro", sceCdlgAdIdClientUnknown04);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown04(void) {
|
||||
NotImplemented_nid_no_patch("Z-mCvugj6Ro");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("wZXR0qW+WLc", sceCdlgAdIdClientUnknown05);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown05(void) {
|
||||
NotImplemented_nid_no_patch("wZXR0qW+WLc");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("k6OlIkZWsec", sceCdlgAdIdClientUnknown06);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown06(void) {
|
||||
NotImplemented_nid_no_patch("k6OlIkZWsec");
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown00(void);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown01(void);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown02(void);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown03(void);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown04(void);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown05(void);
|
||||
int APS5_VABI sceCdlgAdIdClientUnknown06(void);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "prx/libSceCdlgAdIdClient/include/Api.hpp"
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "prx/libSceCffMgr/include/Api.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerIsOn(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerSetOn(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("0ihbCSHhEcA", sceCffMgrUnknown00);
|
||||
int APS5_VABI sceCffMgrUnknown00(void) {
|
||||
NotImplemented_nid_no_patch("0ihbCSHhEcA");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerIsWaitingReboot(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerGetVersion(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("zIlUE+nGqAc", sceCffMgrUnknown01);
|
||||
int APS5_VABI sceCffMgrUnknown01(void) {
|
||||
NotImplemented_nid_no_patch("zIlUE+nGqAc");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerEventOpen(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerEventClose(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("jIZSSBRMMlI", sceCffMgrUnknown02);
|
||||
int APS5_VABI sceCffMgrUnknown02(void) {
|
||||
NotImplemented_nid_no_patch("jIZSSBRMMlI");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("4iNzTMzx1iU", sceCffMgrUnknown03);
|
||||
int APS5_VABI sceCffMgrUnknown03(void) {
|
||||
NotImplemented_nid_no_patch("4iNzTMzx1iU");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("T8mAs5dG-4Q", sceCffMgrUnknown04);
|
||||
int APS5_VABI sceCffMgrUnknown04(void) {
|
||||
NotImplemented_nid_no_patch("T8mAs5dG-4Q");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("fbOF9VQ0NFs", sceCffMgrUnknown05);
|
||||
int APS5_VABI sceCffMgrUnknown05(void) {
|
||||
NotImplemented_nid_no_patch("fbOF9VQ0NFs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("nJwIWgJx8vw", sceCffMgrUnknown06);
|
||||
int APS5_VABI sceCffMgrUnknown06(void) {
|
||||
NotImplemented_nid_no_patch("nJwIWgJx8vw");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerDebugInit(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerIsOn(void);
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerSetOn(void);
|
||||
int APS5_VABI sceCffMgrUnknown00(void);
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerIsWaitingReboot(void);
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerGetVersion(void);
|
||||
int APS5_VABI sceCffMgrUnknown01(void);
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerEventOpen(void);
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerEventClose(void);
|
||||
int APS5_VABI sceCffMgrUnknown02(void);
|
||||
int APS5_VABI sceCffMgrUnknown03(void);
|
||||
int APS5_VABI sceCffMgrUnknown04(void);
|
||||
int APS5_VABI sceCffMgrUnknown05(void);
|
||||
int APS5_VABI sceCffMgrUnknown06(void);
|
||||
int APS5_VABI sceConsoleFeatureFlagManagerDebugInit(void);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "prx/libSceCffMgr/include/Api.hpp"
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_8q7icGBWIrA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("8q7icGBWIrA", libSceCommonDialogUnknown_8q7icGBWIrA_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_D_minus_V35OhFeIM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("D-V35OhFeIM", libSceCommonDialogUnknown_D_minus_V35OhFeIM_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_QXFsLON5QWw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("QXFsLON5QWw", libSceCommonDialogUnknown_QXFsLON5QWw_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_SDpCfY9uB0g_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("SDpCfY9uB0g", libSceCommonDialogUnknown_SDpCfY9uB0g_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_Zaa6fhiKQDE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Zaa6fhiKQDE", libSceCommonDialogUnknown_Zaa6fhiKQDE_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_aUS4PgJye98_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("aUS4PgJye98", libSceCommonDialogUnknown_aUS4PgJye98_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_afLdI6i0lQw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("afLdI6i0lQw", libSceCommonDialogUnknown_afLdI6i0lQw_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_mVRnPerBcK0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("mVRnPerBcK0", libSceCommonDialogUnknown_mVRnPerBcK0_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_p9TTq4bLdFU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("p9TTq4bLdFU", libSceCommonDialogUnknown_p9TTq4bLdFU_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_q3_minus_8WWCG2N0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("q3-8WWCG2N0", libSceCommonDialogUnknown_q3_minus_8WWCG2N0_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_txNJzxX6yrA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("txNJzxX6yrA", libSceCommonDialogUnknown_txNJzxX6yrA_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceCommonDialogUnknown_yxjgDvqUbGQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("yxjgDvqUbGQ", libSceCommonDialogUnknown_yxjgDvqUbGQ_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
add_library(libSceCommonDialog SHARED EXCLUDE_FROM_ALL Export.cpp InventoryExports.cpp)
|
||||
add_library(libSceCommonDialog SHARED EXCLUDE_FROM_ALL Export.cpp InventoryExports.cpp AdditionalExports.cpp)
|
||||
target_include_directories(libSceCommonDialog PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceCommonDialog)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceContentSearch/include/InventoryExports.hpp"
|
||||
#include "prx/libSceContentSearch/include/Api.hpp"
|
||||
#include <cstdint>
|
||||
@@ -207,3 +208,17 @@ int APS5_VABI sceContentSearchSearchApplication() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceContentSearchUnknown_Np8cEpyDFRE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("Np8cEpyDFRE", libSceContentSearchUnknown_Np8cEpyDFRE_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceContentSearchUnknown_X9e_plus_hZfue0U_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("X9e+hZfue0U", libSceContentSearchUnknown_X9e_plus_hZfue0U_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -9,4 +9,7 @@ int APS5_VABI sceContentSearchDisableAvContentCreatedEvent();
|
||||
int APS5_VABI sceContentSearchEnableAvContentCreatedEvent();
|
||||
int APS5_VABI sceContentSearchGetContentIdByAvContentCreatedEvent();
|
||||
|
||||
int APS5_VABI libSceContentSearchUnknown_Np8cEpyDFRE_nid_no_patch();
|
||||
int APS5_VABI libSceContentSearchUnknown_X9e_plus_hZfue0U_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "prx/libc/include/general/ExportMacros.hpp"
|
||||
#include "prx/libSceDiscMap/include/InventoryExports.hpp"
|
||||
#include "prx/libSceDiscMap/include/Api.hpp"
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
@@ -36,3 +38,17 @@ int APS5_VABI sceDiscMapGetPackageSize(std::int64_t fflags, int* ret1, int* ret2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceDiscMapUnknown_5_plus_vOlukvkfg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("5+vOlukvkfg", libSceDiscMapUnknown_5_plus_vOlukvkfg_nid_no_patch);
|
||||
|
||||
int APS5_VABI libSceDiscMapUnknown_fJgP_plus_wqifno_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("fJgP+wqifno", libSceDiscMapUnknown_fJgP_plus_wqifno_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI libSceDiscMapUnknown_5_plus_vOlukvkfg_nid_no_patch();
|
||||
int APS5_VABI libSceDiscMapUnknown_fJgP_plus_wqifno_nid_no_patch();
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "prx/libSceDiscMap/include/Api.hpp"
|
||||
#include "prx/libSceDiscMap/include/InventoryExports.hpp"
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "prx/libSceFlexContent/include/Api.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceFlexContentInitialize(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceFlexContentTerminate(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("7n4PI+iTKws", sceFlexContentUnknown00);
|
||||
int APS5_VABI sceFlexContentUnknown00(void) {
|
||||
NotImplemented_nid_no_patch("7n4PI+iTKws");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("bgXJD9PYROo", sceFlexContentUnknown01);
|
||||
int APS5_VABI sceFlexContentUnknown01(void) {
|
||||
NotImplemented_nid_no_patch("bgXJD9PYROo");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceFlexContentMount(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("EP5ByjgbB2Y", sceFlexContentUnknown02);
|
||||
int APS5_VABI sceFlexContentUnknown02(void) {
|
||||
NotImplemented_nid_no_patch("EP5ByjgbB2Y");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceFlexContentGetDownloadProgress(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceFlexContentDelete(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceFlexContentGetLatestVersion(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceFlexContentGetInstalledVersion(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("TNwR02XaltA", sceFlexContentUnknown03);
|
||||
int APS5_VABI sceFlexContentUnknown03(void) {
|
||||
NotImplemented_nid_no_patch("TNwR02XaltA");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("EQWWghng4OI", sceFlexContentUnknown04);
|
||||
int APS5_VABI sceFlexContentUnknown04(void) {
|
||||
NotImplemented_nid_no_patch("EQWWghng4OI");
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceFlexContentInitialize(void);
|
||||
int APS5_VABI sceFlexContentTerminate(void);
|
||||
int APS5_VABI sceFlexContentUnknown00(void);
|
||||
int APS5_VABI sceFlexContentUnknown01(void);
|
||||
int APS5_VABI sceFlexContentMount(void);
|
||||
int APS5_VABI sceFlexContentUnknown02(void);
|
||||
int APS5_VABI sceFlexContentGetDownloadProgress(void);
|
||||
int APS5_VABI sceFlexContentDelete(void);
|
||||
int APS5_VABI sceFlexContentGetLatestVersion(void);
|
||||
int APS5_VABI sceFlexContentGetInstalledVersion(void);
|
||||
int APS5_VABI sceFlexContentUnknown03(void);
|
||||
int APS5_VABI sceFlexContentUnknown04(void);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "prx/libSceFlexContent/include/Api.hpp"
|
||||
Loaded 100 of 617 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user