mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c4134a95e2 | |||
| fb5ecec455 | |||
| 650d9c91a1 | |||
| fc8d2a3b83 | |||
| 59b8fad341 |
@@ -73,7 +73,7 @@ jobs:
|
||||
- name: Configure
|
||||
shell: cmd
|
||||
run: |
|
||||
cmake -S src -B _Build/windows ^
|
||||
cmake -S . -B _Build/windows ^
|
||||
-G Ninja ^
|
||||
-DCMAKE_BUILD_TYPE=Release ^
|
||||
-DCMAKE_C_COMPILER=clang-cl ^
|
||||
@@ -147,7 +147,7 @@ jobs:
|
||||
- name: Configure
|
||||
shell: bash
|
||||
run: |
|
||||
cmake -S src -B _Build/macos \
|
||||
cmake -S . -B _Build/macos \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
|
||||
@@ -270,7 +270,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p _Build
|
||||
cmake -S src -B _Build/linux \
|
||||
cmake -S . -B _Build/linux \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
|
||||
+2
-1
@@ -3,4 +3,5 @@
|
||||
.idea/
|
||||
build/
|
||||
_Build/vscode-clang/
|
||||
_Build/
|
||||
_Build/
|
||||
cmake-build-debug/
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"cmake.sourceDirectory": "${workspaceFolder}/src",
|
||||
"cmake.sourceDirectory": "${workspaceFolder}",
|
||||
"cmake.buildDirectory": "${workspaceFolder}/_Build/vscode-clang",
|
||||
"cmake.generator": "Ninja",
|
||||
"cmake.environment": {
|
||||
|
||||
+112
-110
@@ -6,6 +6,10 @@ endif()
|
||||
|
||||
project(Kyty)
|
||||
|
||||
set(KYTY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
set(KYTY_TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests")
|
||||
set(KYTY_THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty")
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES ".*Linux")
|
||||
set(LINUX TRUE)
|
||||
endif()
|
||||
@@ -19,13 +23,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
|
||||
|
||||
include(utils.cmake)
|
||||
include("${KYTY_SOURCE_DIR}/utils.cmake")
|
||||
include(CTest)
|
||||
|
||||
option(KYTY_ENABLE_CLANG_TIDY "Run clang-tidy checks during builds" OFF)
|
||||
|
||||
set(KYTY_THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty")
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
include(TestBigEndian)
|
||||
@@ -97,36 +99,36 @@ endif()
|
||||
|
||||
project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.2.2)
|
||||
|
||||
include_directories(
|
||||
include_directories(
|
||||
${KYTY_THIRD_PARTY_DIR}/gtest/include
|
||||
${KYTY_THIRD_PARTY_DIR}/gtest
|
||||
${KYTY_THIRD_PARTY_DIR}/fmt/include
|
||||
${KYTY_THIRD_PARTY_DIR}/magic_enum/include/magic_enum
|
||||
${PROJECT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${KYTY_SOURCE_DIR}
|
||||
)
|
||||
|
||||
set(KYTY_VERSION "${PROJECT_VERSION}")
|
||||
|
||||
configure_file(
|
||||
${PROJECT_SOURCE_DIR}/cmake_config.h.in
|
||||
${KYTY_SOURCE_DIR}/cmake_config.h.in
|
||||
${PROJECT_BINARY_DIR}/cmake_config.h
|
||||
)
|
||||
|
||||
find_package(Git)
|
||||
|
||||
|
||||
add_custom_target( KytyGitVersion
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D INPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/kytyGitVersion.h.in
|
||||
-D OUTPUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/kytyGitVersion.h
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D INPUT_FILE=${KYTY_SOURCE_DIR}/kytyGitVersion.h.in
|
||||
-D OUTPUT_FILE=${PROJECT_BINARY_DIR}/kytyGitVersion.h
|
||||
-D GIT_EXECUTABLE=${GIT_EXECUTABLE}
|
||||
-D GIT_WORKING_DIRECTORY=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/generate_version.cmake
|
||||
-P ${KYTY_SOURCE_DIR}/generate_version.cmake
|
||||
COMMENT "Generate kytyGitVersion.h"
|
||||
)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0.0)
|
||||
list(APPEND KYTY_IWYU
|
||||
list(APPEND KYTY_IWYU
|
||||
kyty_emulator
|
||||
common
|
||||
#launcher
|
||||
@@ -139,55 +141,55 @@ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0.0)
|
||||
endif()
|
||||
|
||||
option(KYTY_BUILD_LAUNCHER "Build Qt launcher" ON)
|
||||
|
||||
config_compiler_and_linker()
|
||||
|
||||
|
||||
config_compiler_and_linker()
|
||||
|
||||
add_subdirectory("${KYTY_THIRD_PARTY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/3rdparty")
|
||||
add_subdirectory(common)
|
||||
add_subdirectory("${KYTY_SOURCE_DIR}/common" "${CMAKE_CURRENT_BINARY_DIR}/common")
|
||||
|
||||
file(GLOB kyty_emulator_src CONFIGURE_DEPENDS
|
||||
libs/*.cpp
|
||||
libs/*.h
|
||||
graphics/*.cpp
|
||||
graphics/*.h
|
||||
graphics/guest_gpu/*.cpp
|
||||
graphics/guest_gpu/*.h
|
||||
graphics/guest_gpu/command_processor/*.cpp
|
||||
graphics/guest_gpu/command_processor/*.h
|
||||
graphics/host_gpu/*.cpp
|
||||
graphics/host_gpu/*.h
|
||||
graphics/host_gpu/renderer/*.cpp
|
||||
graphics/host_gpu/renderer/*.h
|
||||
graphics/host_gpu/renderer/cache/*.cpp
|
||||
graphics/host_gpu/renderer/cache/*.h
|
||||
graphics/host_gpu/renderer/image/*.cpp
|
||||
graphics/host_gpu/renderer/image/*.h
|
||||
graphics/host_gpu/renderer/pipeline/*.cpp
|
||||
graphics/host_gpu/renderer/pipeline/*.h
|
||||
graphics/shader/*.cpp
|
||||
graphics/shader/*.h
|
||||
graphics/shader/recompiler/*.cpp
|
||||
graphics/shader/recompiler/*.h
|
||||
graphics/shader/recompiler/cfg/*.cpp
|
||||
graphics/shader/recompiler/cfg/*.h
|
||||
graphics/shader/recompiler/decompiler/*.cpp
|
||||
graphics/shader/recompiler/decompiler/*.h
|
||||
graphics/shader/recompiler/emitter/*.cpp
|
||||
graphics/shader/recompiler/emitter/*.h
|
||||
graphics/shader/recompiler/ir/*.cpp
|
||||
graphics/shader/recompiler/ir/*.h
|
||||
graphics/presentation/*.cpp
|
||||
graphics/presentation/*.h
|
||||
graphics/presentation/window/*.cpp
|
||||
graphics/presentation/window/*.h
|
||||
kernel/*.cpp
|
||||
kernel/*.h
|
||||
loader/*.cpp
|
||||
loader/*.h
|
||||
"${KYTY_SOURCE_DIR}/libs/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/libs/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/guest_gpu/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/guest_gpu/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/guest_gpu/command_processor/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/guest_gpu/command_processor/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/cache/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/cache/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/image/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/image/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/pipeline/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/pipeline/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/cfg/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/cfg/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/decompiler/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/decompiler/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/emitter/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/emitter/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/presentation/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/presentation/*.h"
|
||||
"${KYTY_SOURCE_DIR}/graphics/presentation/window/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/presentation/window/*.h"
|
||||
"${KYTY_SOURCE_DIR}/kernel/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/kernel/*.h"
|
||||
"${KYTY_SOURCE_DIR}/loader/*.cpp"
|
||||
"${KYTY_SOURCE_DIR}/loader/*.h"
|
||||
)
|
||||
|
||||
find_program(KYTY_GLSLANG_VALIDATOR glslangValidator REQUIRED)
|
||||
set(gpu_tiler_shader_dir "${CMAKE_CURRENT_SOURCE_DIR}/graphics/host_gpu/shaders")
|
||||
set(gpu_tiler_shader_dir "${KYTY_SOURCE_DIR}/graphics/host_gpu/shaders")
|
||||
set(gpu_tiler_generated_dir "${PROJECT_BINARY_DIR}/gpu_tiler_shaders")
|
||||
set(gpu_tiler_shader_names
|
||||
standard256
|
||||
@@ -215,7 +217,7 @@ foreach(shader_name IN LISTS gpu_tiler_shader_names)
|
||||
COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.0 -Os
|
||||
"-I${gpu_tiler_shader_dir}" -o "${shader_spv}" "${shader_source}"
|
||||
COMMAND ${CMAKE_COMMAND} -DINPUT=${shader_spv} -DOUTPUT=${shader_header}
|
||||
-DSYMBOL=${shader_symbol} -P "${CMAKE_CURRENT_SOURCE_DIR}/embed_spirv.cmake"
|
||||
-DSYMBOL=${shader_symbol} -P "${KYTY_SOURCE_DIR}/embed_spirv.cmake"
|
||||
DEPENDS "${shader_source}" ${gpu_tiler_shader_includes}
|
||||
VERBATIM
|
||||
)
|
||||
@@ -239,7 +241,7 @@ foreach(shader_source IN LISTS gpu_blit_shader_sources)
|
||||
COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.0 -Os
|
||||
"-I${gpu_tiler_shader_dir}" -o "${shader_spv}" "${shader_source}"
|
||||
COMMAND ${CMAKE_COMMAND} -DINPUT=${shader_spv} -DOUTPUT=${shader_header}
|
||||
-DSYMBOL=${shader_symbol} -P "${CMAKE_CURRENT_SOURCE_DIR}/embed_spirv.cmake"
|
||||
-DSYMBOL=${shader_symbol} -P "${KYTY_SOURCE_DIR}/embed_spirv.cmake"
|
||||
DEPENDS "${shader_source}"
|
||||
VERBATIM
|
||||
)
|
||||
@@ -248,8 +250,8 @@ endforeach()
|
||||
list(APPEND kyty_emulator_src ${gpu_blit_shader_headers})
|
||||
|
||||
list(APPEND kyty_emulator_src
|
||||
emulator.h
|
||||
emulator.cpp
|
||||
"${KYTY_SOURCE_DIR}/emulator.h"
|
||||
"${KYTY_SOURCE_DIR}/emulator.cpp"
|
||||
)
|
||||
list(REMOVE_DUPLICATES kyty_emulator_src)
|
||||
|
||||
@@ -280,7 +282,7 @@ if(LINUX)
|
||||
endif()
|
||||
|
||||
set(inc_headers
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${KYTY_SOURCE_DIR}
|
||||
${KYTY_THIRD_PARTY_DIR}/SDL2/include
|
||||
${KYTY_THIRD_PARTY_DIR}/VulkanMemoryAllocator/include
|
||||
${KYTY_THIRD_PARTY_DIR}/SPIRV-Tools/include
|
||||
@@ -292,13 +294,13 @@ set(inc_headers
|
||||
|
||||
if (KYTY_CLANG_CL)
|
||||
list(APPEND kyty_emulator_link_libraries winpthread)
|
||||
list(APPEND inc_headers
|
||||
list(APPEND inc_headers
|
||||
${KYTY_THIRD_PARTY_DIR}/winpthread/include
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND check_headers
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${KYTY_SOURCE_DIR}
|
||||
)
|
||||
|
||||
function(add_kyty_full_emulator_test target source)
|
||||
@@ -320,108 +322,108 @@ endfunction()
|
||||
function(configure_macos_guest_address_space target)
|
||||
if(APPLE AND (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64" OR
|
||||
(NOT CMAKE_OSX_ARCHITECTURES AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$")))
|
||||
target_sources(${target} PRIVATE kernel/macosGuestAddressSpace.cpp)
|
||||
target_sources(${target} PRIVATE "${KYTY_SOURCE_DIR}/kernel/macosGuestAddressSpace.cpp")
|
||||
target_compile_definitions(${target} PRIVATE KYTY_LINKED_GUEST_ADDRESS_SPACE=1)
|
||||
target_link_options(${target} PRIVATE
|
||||
-Wl,-ld_classic,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x40000,-segaddr,SYSTEM_MANAGED,0x40000,-segaddr,SYSTEM_RESERVED,0x7ffffc000,-segaddr,USER_AREA,0x7000000000,-image_base,0x700000000000)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
add_kyty_full_emulator_test(shader_cfg_tests ../tests/shaderCfgTests.cpp)
|
||||
add_kyty_full_emulator_test(shader_cfg_tests "${KYTY_TESTS_DIR}/shaderCfgTests.cpp")
|
||||
|
||||
add_executable(scalar_provenance_tests EXCLUDE_FROM_ALL
|
||||
../tests/ScalarProvenanceTests.cpp
|
||||
graphics/host_gpu/hostMemory.cpp
|
||||
graphics/shader/recompiler/ir/ReadLaneElimination.cpp
|
||||
graphics/shader/recompiler/ir/ScalarProvenance.cpp
|
||||
graphics/shader/recompiler/ir/SrtWalker.cpp
|
||||
"${KYTY_TESTS_DIR}/ScalarProvenanceTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ReadLaneElimination.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ScalarProvenance.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/SrtWalker.cpp"
|
||||
)
|
||||
target_link_libraries(scalar_provenance_tests fmt::fmt)
|
||||
target_include_directories(scalar_provenance_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(page_manager_tests EXCLUDE_FROM_ALL
|
||||
../tests/PageManagerTests.cpp
|
||||
graphics/host_gpu/pageManager.cpp
|
||||
"${KYTY_TESTS_DIR}/PageManagerTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/pageManager.cpp"
|
||||
)
|
||||
target_include_directories(page_manager_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(bit_array_tests EXCLUDE_FROM_ALL
|
||||
../tests/BitArrayTests.cpp
|
||||
"${KYTY_TESTS_DIR}/BitArrayTests.cpp"
|
||||
)
|
||||
target_include_directories(bit_array_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(memory_tracker_tests EXCLUDE_FROM_ALL
|
||||
../tests/MemoryTrackerTests.cpp
|
||||
graphics/host_gpu/pageManager.cpp
|
||||
graphics/host_gpu/memoryTracker.cpp
|
||||
"${KYTY_TESTS_DIR}/MemoryTrackerTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/pageManager.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/memoryTracker.cpp"
|
||||
)
|
||||
target_link_libraries(memory_tracker_tests fmt::fmt common)
|
||||
target_include_directories(memory_tracker_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(shader_vertex_metadata_tests EXCLUDE_FROM_ALL
|
||||
../tests/ShaderVertexMetadataTests.cpp
|
||||
graphics/host_gpu/hostMemory.cpp
|
||||
graphics/shader/shaderVertexMetadata.cpp
|
||||
"${KYTY_TESTS_DIR}/ShaderVertexMetadataTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/shaderVertexMetadata.cpp"
|
||||
)
|
||||
target_include_directories(shader_vertex_metadata_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(shader_stage_runtime_tests EXCLUDE_FROM_ALL
|
||||
../tests/ShaderStageRuntimeTests.cpp
|
||||
graphics/guest_gpu/gpu_format.cpp
|
||||
graphics/host_gpu/hostMemory.cpp
|
||||
graphics/shader/shaderStageRuntime.cpp
|
||||
graphics/shader/recompiler/ir/ResourceMaterialization.cpp
|
||||
graphics/shader/recompiler/ir/ScalarProvenance.cpp
|
||||
graphics/shader/recompiler/ir/SrtWalker.cpp
|
||||
"${KYTY_TESTS_DIR}/ShaderStageRuntimeTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/guest_gpu/gpu_format.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/shaderStageRuntime.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ResourceMaterialization.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ScalarProvenance.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/SrtWalker.cpp"
|
||||
)
|
||||
target_link_libraries(shader_stage_runtime_tests fmt::fmt)
|
||||
target_include_directories(shader_stage_runtime_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(resource_tracking_tests EXCLUDE_FROM_ALL
|
||||
../tests/ResourceTrackingTests.cpp
|
||||
graphics/guest_gpu/gpu_format.cpp
|
||||
graphics/host_gpu/hostMemory.cpp
|
||||
graphics/shader/recompiler/ir/ScalarProvenance.cpp
|
||||
graphics/shader/recompiler/ir/SrtWalker.cpp
|
||||
graphics/shader/recompiler/ir/SrtPatcher.cpp
|
||||
graphics/shader/recompiler/ir/ResourceTracking.cpp
|
||||
graphics/shader/recompiler/ir/ResourceMaterialization.cpp
|
||||
graphics/shader/recompiler/ir/ShaderInfoCollection.cpp
|
||||
graphics/shader/recompiler/ir/BindingLayout.cpp
|
||||
"${KYTY_TESTS_DIR}/ResourceTrackingTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/guest_gpu/gpu_format.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ScalarProvenance.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/SrtWalker.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/SrtPatcher.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ResourceTracking.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ResourceMaterialization.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ShaderInfoCollection.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/BindingLayout.cpp"
|
||||
)
|
||||
target_link_libraries(resource_tracking_tests fmt::fmt)
|
||||
target_include_directories(resource_tracking_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(resource_mutex_tests EXCLUDE_FROM_ALL
|
||||
../tests/ResourceMutexTests.cpp
|
||||
graphics/host_gpu/renderer/cache/resourceMutex.cpp
|
||||
"${KYTY_TESTS_DIR}/ResourceMutexTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/cache/resourceMutex.cpp"
|
||||
)
|
||||
target_link_libraries(resource_mutex_tests common)
|
||||
target_include_directories(resource_mutex_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(audio_out2_port_tests EXCLUDE_FROM_ALL
|
||||
../tests/AudioOut2PortTests.cpp
|
||||
libs/libAudio2.cpp
|
||||
loader/timer.cpp
|
||||
"${KYTY_TESTS_DIR}/AudioOut2PortTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/libs/libAudio2.cpp"
|
||||
"${KYTY_SOURCE_DIR}/loader/timer.cpp"
|
||||
)
|
||||
target_link_libraries(audio_out2_port_tests common fmt::fmt)
|
||||
target_include_directories(audio_out2_port_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(event_queue_lifetime_tests EXCLUDE_FROM_ALL
|
||||
../tests/EventQueueLifetimeTests.cpp
|
||||
kernel/eventQueue.cpp
|
||||
loader/timer.cpp
|
||||
"${KYTY_TESTS_DIR}/EventQueueLifetimeTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/kernel/eventQueue.cpp"
|
||||
"${KYTY_SOURCE_DIR}/loader/timer.cpp"
|
||||
)
|
||||
target_link_libraries(event_queue_lifetime_tests common fmt::fmt)
|
||||
target_include_directories(event_queue_lifetime_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(image_page_table_tests EXCLUDE_FROM_ALL
|
||||
../tests/ImagePageTableTests.cpp
|
||||
"${KYTY_TESTS_DIR}/ImagePageTableTests.cpp"
|
||||
)
|
||||
target_link_libraries(image_page_table_tests common fmt::fmt)
|
||||
target_include_directories(image_page_table_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_kyty_full_emulator_test(shader_recompiler_compute_tests ../tests/ShaderRecompilerComputeTests.cpp)
|
||||
add_kyty_full_emulator_test(shader_recompiler_compute_tests "${KYTY_TESTS_DIR}/ShaderRecompilerComputeTests.cpp")
|
||||
|
||||
set(gpu_test_generated_dir "${PROJECT_BINARY_DIR}/gpu_test_shaders")
|
||||
set(gpu_test_ms_depth_source
|
||||
@@ -437,14 +439,14 @@ add_custom_command(
|
||||
-o "${gpu_test_ms_depth_spv}" "${gpu_test_ms_depth_source}"
|
||||
COMMAND ${CMAKE_COMMAND} -DINPUT=${gpu_test_ms_depth_spv}
|
||||
-DOUTPUT=${gpu_test_ms_depth_header} -DSYMBOL=GPU_TEST_MS_DEPTH_SPV
|
||||
-P "${CMAKE_CURRENT_SOURCE_DIR}/embed_spirv.cmake"
|
||||
-P "${KYTY_SOURCE_DIR}/embed_spirv.cmake"
|
||||
DEPENDS "${gpu_test_ms_depth_source}"
|
||||
VERBATIM
|
||||
)
|
||||
target_sources(shader_recompiler_compute_tests PRIVATE
|
||||
"${gpu_test_ms_depth_header}")
|
||||
|
||||
add_kyty_full_emulator_test(virtual_memory_allocation_tests ../tests/VirtualMemoryAllocationTests.cpp)
|
||||
add_kyty_full_emulator_test(virtual_memory_allocation_tests "${KYTY_TESTS_DIR}/VirtualMemoryAllocationTests.cpp")
|
||||
target_compile_definitions(virtual_memory_allocation_tests PRIVATE
|
||||
KYTY_VIRTUAL_MEMORY_ALLOCATION_TESTS=1)
|
||||
|
||||
@@ -520,7 +522,7 @@ if(BUILD_TESTING)
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(kyty_emulator main.cpp ${kyty_emulator_src})
|
||||
add_executable(kyty_emulator "${KYTY_SOURCE_DIR}/main.cpp" ${kyty_emulator_src})
|
||||
configure_macos_guest_address_space(kyty_emulator)
|
||||
|
||||
target_link_libraries(kyty_emulator ${kyty_emulator_link_libraries})
|
||||
@@ -570,14 +572,14 @@ if(APPLE)
|
||||
# reverts to the hardened defaults and aborts when it first executes written code).
|
||||
add_custom_command(TARGET kyty_emulator POST_BUILD
|
||||
COMMAND codesign -s - --force --options runtime
|
||||
--entitlements "${CMAKE_CURRENT_SOURCE_DIR}/macos_jit.entitlements"
|
||||
--entitlements "${KYTY_SOURCE_DIR}/macos_jit.entitlements"
|
||||
$<TARGET_FILE:kyty_emulator>
|
||||
COMMENT "Codesign kyty_emulator with JIT entitlements (macOS)")
|
||||
endif()
|
||||
|
||||
install(TARGETS kyty_emulator DESTINATION .)
|
||||
if(KYTY_BUILD_LAUNCHER)
|
||||
add_subdirectory(launcher)
|
||||
add_subdirectory("${KYTY_SOURCE_DIR}/launcher" "${CMAKE_CURRENT_BINARY_DIR}/launcher")
|
||||
endif()
|
||||
if(KYTY_CLANG_CL)
|
||||
install(FILES "${KYTY_THIRD_PARTY_DIR}/winpthread/bin/libwinpthread-1.dll" DESTINATION .)
|
||||
@@ -141,7 +141,7 @@ git submodule update --init --recursive
|
||||
Configure the project. Replace the Qt path with the version installed on your system:
|
||||
|
||||
```powershell
|
||||
cmake -S src -B _Build/windows -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_PREFIX_PATH="C:/Qt/6.x.x/msvc2022_64"
|
||||
cmake -S . -B _Build/windows -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_PREFIX_PATH="C:/Qt/6.x.x/msvc2022_64"
|
||||
```
|
||||
|
||||
Build the launcher and stage a runnable installation:
|
||||
@@ -174,7 +174,7 @@ Qt 6 (Concurrent, Network, Widgets) is also required — either the distribution
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
|
||||
cmake -S src -B _Build/linux -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
cmake -S . -B _Build/linux -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DCMAKE_PREFIX_PATH="$Qt6_DIR"
|
||||
|
||||
@@ -188,7 +188,7 @@ The install step copies the Qt libraries and plugins next to the binaries, so
|
||||
As on Windows, the MSVC compiler is not used; Clang is required. `cl.exe` is rejected at configure
|
||||
time.
|
||||
|
||||
Note that the CMake source root is `src`, not the repository root.
|
||||
The CMake source root is the repository root.
|
||||
|
||||
### Building on macOS
|
||||
|
||||
@@ -207,7 +207,7 @@ Requirements:
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
|
||||
cmake -S src -B _Build/macos -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
cmake -S . -B _Build/macos -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DCMAKE_PREFIX_PATH="$Qt6_DIR"
|
||||
|
||||
@@ -13,7 +13,7 @@ endif()
|
||||
add_library(common STATIC ${common_src} ${common_headers})
|
||||
|
||||
target_include_directories(common
|
||||
PUBLIC ${PROJECT_SOURCE_DIR}
|
||||
PUBLIC ${KYTY_SOURCE_DIR}
|
||||
PRIVATE
|
||||
${KYTY_THIRD_PARTY_DIR}/cpuinfo/include
|
||||
)
|
||||
|
||||
@@ -32,11 +32,10 @@
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
static thread_local CommandProcessor* g_current_processor = nullptr;
|
||||
static thread_local Pm4Execution* g_current_execution = nullptr;
|
||||
static thread_local uint32_t g_submission_pause_depth = 0;
|
||||
static thread_local bool g_gpu_mutex_owned = false;
|
||||
static thread_local bool g_gpu_thread = false;
|
||||
static thread_local CommandProcessor* g_current_processor = nullptr;
|
||||
static thread_local Pm4Execution* g_current_execution = nullptr;
|
||||
static thread_local bool g_gpu_mutex_owned = false;
|
||||
static thread_local bool g_gpu_thread = false;
|
||||
|
||||
class GpuMutexLock final {
|
||||
public:
|
||||
@@ -98,8 +97,6 @@ public:
|
||||
bool trigger_agc_interrupt_on_done);
|
||||
void SubmitFlipPreparation(uint64_t request_id);
|
||||
void Done();
|
||||
void PauseSubmissions();
|
||||
void ResumeSubmissions();
|
||||
void Shutdown();
|
||||
[[nodiscard]] bool IsStopping();
|
||||
void SendCommand(Common::UniqueFunction<void>&& command);
|
||||
@@ -407,7 +404,7 @@ void CommandProcessor::WriteData(uint32_t* dst, const uint32_t* src, uint32_t dw
|
||||
uint32_t write_control) {
|
||||
const uint32_t dst_sel = ((write_control >> 30u) & 0x1u) | ((write_control >> 7u) & 0x1eu);
|
||||
const uint32_t cache_policy = (write_control >> 25u) & 0x3u;
|
||||
const uint32_t increment = (write_control >> 16u) & 0x1u;
|
||||
const uint32_t increment = (write_control >> 16u) & 0x1u;
|
||||
const uint32_t write_confirm = (write_control >> 20u) & 0x1u;
|
||||
|
||||
switch (dst_sel) {
|
||||
@@ -696,26 +693,6 @@ bool GpuState::Process(Submission& submission) {
|
||||
return complete;
|
||||
}
|
||||
|
||||
void GpuState::PauseSubmissions() {
|
||||
if (g_gpu_mutex_owned) {
|
||||
EXIT("GPU submissions are already paused by this thread\n");
|
||||
}
|
||||
g_gpu_mutex_owned = true;
|
||||
m_submission_mutex.Lock();
|
||||
if (!IsGpuThread()) {
|
||||
WaitLocked();
|
||||
}
|
||||
m_renderer.GetCommandScheduler().DrainPriorityOperations();
|
||||
}
|
||||
|
||||
void GpuState::ResumeSubmissions() {
|
||||
if (!g_gpu_mutex_owned) {
|
||||
EXIT("GPU submissions resumed without an active pause\n");
|
||||
}
|
||||
m_submission_mutex.Unlock();
|
||||
g_gpu_mutex_owned = false;
|
||||
}
|
||||
|
||||
Pm4ProcessResult CommandProcessor::Process(Pm4Execution& execution, uint32_t* buffer,
|
||||
uint32_t size_dw) {
|
||||
KYTY_PROFILER_BLOCK("CommandProcessor::Process");
|
||||
@@ -1693,32 +1670,6 @@ int Gpu::GetFrameNum() const {
|
||||
return m_state->GetFrameNum();
|
||||
}
|
||||
|
||||
void Gpu::PauseSubmissions() {
|
||||
m_state->PauseSubmissions();
|
||||
}
|
||||
|
||||
void Gpu::ResumeSubmissions() {
|
||||
m_state->ResumeSubmissions();
|
||||
}
|
||||
|
||||
Gpu::SubmissionLock::SubmissionLock(Gpu& gpu): m_gpu(gpu) {
|
||||
if (g_current_processor != nullptr || g_submission_pause_depth == UINT32_MAX) {
|
||||
EXIT("cannot acquire GPU submission lock in the current state\n");
|
||||
}
|
||||
if (g_submission_pause_depth++ == 0) {
|
||||
m_gpu.PauseSubmissions();
|
||||
}
|
||||
}
|
||||
|
||||
Gpu::SubmissionLock::~SubmissionLock() {
|
||||
if (g_submission_pause_depth == 0) {
|
||||
EXIT("GPU submission lock released without ownership\n");
|
||||
}
|
||||
if (--g_submission_pause_depth == 0) {
|
||||
m_gpu.ResumeSubmissions();
|
||||
}
|
||||
}
|
||||
|
||||
bool Gpu::IsCommandProcessorThread() noexcept {
|
||||
return g_current_processor != nullptr;
|
||||
}
|
||||
@@ -1727,12 +1678,4 @@ CommandProcessor* Gpu::CurrentCommandProcessor() noexcept {
|
||||
return g_current_processor;
|
||||
}
|
||||
|
||||
bool Gpu::SubmissionLockHeld() noexcept {
|
||||
return g_submission_pause_depth != 0;
|
||||
}
|
||||
|
||||
bool Gpu::MutexHeld() noexcept {
|
||||
return g_gpu_mutex_owned;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -35,25 +35,8 @@ public:
|
||||
|
||||
[[nodiscard]] static bool IsCommandProcessorThread() noexcept;
|
||||
[[nodiscard]] static CommandProcessor* CurrentCommandProcessor() noexcept;
|
||||
[[nodiscard]] static bool SubmissionLockHeld() noexcept;
|
||||
[[nodiscard]] static bool MutexHeld() noexcept;
|
||||
|
||||
class SubmissionLock final {
|
||||
public:
|
||||
explicit SubmissionLock(Gpu& gpu);
|
||||
~SubmissionLock();
|
||||
KYTY_CLASS_NO_COPY(SubmissionLock);
|
||||
|
||||
private:
|
||||
Gpu& m_gpu;
|
||||
};
|
||||
|
||||
private:
|
||||
friend class SubmissionLock;
|
||||
|
||||
void PauseSubmissions();
|
||||
void ResumeSubmissions();
|
||||
|
||||
std::unique_ptr<GpuState> m_state;
|
||||
};
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
+17
-5
@@ -7,7 +7,8 @@
|
||||
namespace Libs::Graphics {
|
||||
|
||||
GpuResourceManager::GpuResourceManager(GraphicContext& graphics, CommandScheduler& scheduler)
|
||||
: m_buffer_cache(graphics, scheduler, m_page_manager, m_texture_cache, m_resource_mutex),
|
||||
: m_scheduler(scheduler),
|
||||
m_buffer_cache(graphics, scheduler, m_page_manager, m_texture_cache, m_resource_mutex),
|
||||
m_texture_cache(graphics, scheduler, m_page_manager, m_buffer_cache, m_resource_mutex) {}
|
||||
|
||||
GpuResourceManager::~GpuResourceManager() = default;
|
||||
@@ -101,7 +102,22 @@ void GpuResourceManager::MapMemory(uint64_t vaddr, uint64_t size) {
|
||||
}
|
||||
|
||||
void GpuResourceManager::UnmapMemory(uint64_t vaddr, uint64_t size) {
|
||||
if (CommandScheduler::InDeferredOperation()) {
|
||||
EXIT("unsupported memory unmap from an asynchronous GPU completion, "
|
||||
"addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
|
||||
vaddr, size);
|
||||
}
|
||||
if (m_resource_mutex.IsOwnedByCurrentThread()) {
|
||||
EXIT("unsupported memory unmap from a pre-owned resource transaction, "
|
||||
"addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
|
||||
vaddr, size);
|
||||
}
|
||||
const auto unmap = [this, vaddr, size] {
|
||||
if (m_scheduler.Active()) {
|
||||
const auto tick = m_scheduler.CurrentTick();
|
||||
m_scheduler.FinishCurrent();
|
||||
m_scheduler.WaitPriorityOperations(tick);
|
||||
}
|
||||
m_buffer_cache.UnmapMemory(vaddr, size);
|
||||
m_texture_cache.UnmapMemory(vaddr, size);
|
||||
m_page_manager.OnGpuUnmap(vaddr, size);
|
||||
@@ -109,13 +125,9 @@ void GpuResourceManager::UnmapMemory(uint64_t vaddr, uint64_t size) {
|
||||
m_mapped_ranges.Subtract(vaddr, size);
|
||||
};
|
||||
if (m_gpu == nullptr) {
|
||||
if (m_resource_mutex.IsOwnedByCurrentThread()) {
|
||||
EXIT("cannot synchronously unmap from a resource transaction\n");
|
||||
}
|
||||
unmap();
|
||||
return;
|
||||
}
|
||||
Gpu::SubmissionLock submissions(*m_gpu);
|
||||
m_gpu->SendCommandSync(unmap);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
private:
|
||||
PageManager m_page_manager;
|
||||
ResourceMutex m_resource_mutex;
|
||||
CommandScheduler& m_scheduler;
|
||||
BufferCache m_buffer_cache;
|
||||
TextureCache m_texture_cache;
|
||||
mutable std::shared_mutex m_mapped_ranges_mutex;
|
||||
|
||||
+12
-6
@@ -867,22 +867,28 @@ TextureCache::BuildColorTransfer(const Image& image, BindingType binding,
|
||||
case BindingType::Texture: break;
|
||||
case BindingType::Storage: owner = "StorageTextureCache"; break;
|
||||
case BindingType::RenderTarget:
|
||||
if (info.resources.layers == 0 || info.data.size % info.resources.layers != 0 ||
|
||||
info.samples != 1 || image.backing.samples != 1) {
|
||||
EXIT("TextureCache: invalid color-attachment upload\n");
|
||||
}
|
||||
format = ImageOps::RenderTargetTransferFormat(info.bytes_per_block);
|
||||
allow_depth_tile = false;
|
||||
plan.swap_bgra16 = info.bgra16;
|
||||
owner = "RenderTarget";
|
||||
break;
|
||||
case BindingType::VideoOut:
|
||||
if (info.resources.layers == 0 || info.data.size % info.resources.layers != 0 ||
|
||||
info.samples != 1 || image.backing.samples != 1 ||
|
||||
(binding == BindingType::VideoOut &&
|
||||
info.metadata.compression != VideoOutCompression::Uncompressed)) {
|
||||
info.metadata.compression != VideoOutCompression::Uncompressed) {
|
||||
EXIT("TextureCache: invalid color-attachment upload\n");
|
||||
}
|
||||
format = binding == BindingType::RenderTarget
|
||||
? ImageOps::RenderTargetTransferFormat(info.bytes_per_block)
|
||||
: info.guest_format;
|
||||
format = info.guest_format;
|
||||
layers = info.resources.layers;
|
||||
volume = false;
|
||||
layered = layers > 1;
|
||||
allow_depth_tile = false;
|
||||
plan.swap_bgra16 = info.bgra16;
|
||||
owner = binding == BindingType::RenderTarget ? "RenderTarget" : "VideoOut";
|
||||
owner = "VideoOut";
|
||||
break;
|
||||
case BindingType::DepthTarget: return plan;
|
||||
}
|
||||
|
||||
@@ -119,7 +119,18 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
uint32_t pitch = 0;
|
||||
uint64_t size = 0;
|
||||
bool tile = false;
|
||||
const bool standard64 =
|
||||
const bool volume = rt.attrib3.dimension == 2;
|
||||
if (rt.attrib3.dimension != 1 && !volume) {
|
||||
EXIT("unsupported render-target dimension: %u\n", rt.attrib3.dimension);
|
||||
}
|
||||
if (!volume && rt.attrib3.depth != 0) {
|
||||
EXIT("2D render target has nonzero depth: %u\n", rt.attrib3.depth);
|
||||
}
|
||||
if (volume && samples != 1) {
|
||||
EXIT("multisampled 3D render targets are unsupported\n");
|
||||
}
|
||||
const uint32_t depth = volume ? rt.attrib3.depth + 1u : 1u;
|
||||
const bool standard64 =
|
||||
rt.attrib3.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB);
|
||||
|
||||
switch (rt.attrib3.tile_mode) {
|
||||
@@ -145,6 +156,7 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
if (bytes_per_element == 0) {
|
||||
EXIT("render-target format has no valid element size\n");
|
||||
}
|
||||
const auto transfer_format = ImageOps::RenderTargetTransferFormat(bytes_per_element);
|
||||
if (standard64 &&
|
||||
(rt.attrib3.dimension != 1 || rt.attrib3.depth != 0 || levels != 1 ||
|
||||
rt.view.current_mip_level != 0 || view.base_layer != 0 || view.image_layers != 1 ||
|
||||
@@ -165,10 +177,14 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
if (rt.pitch.pitch_div8_minus1 != 0) {
|
||||
pitch = (rt.pitch.pitch_div8_minus1 + 1u) << 3u;
|
||||
} else if (tile) {
|
||||
pitch = standard64
|
||||
? TileGetTexturePitch(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float),
|
||||
width, levels, rt.attrib3.tile_mode)
|
||||
: TileGetRenderTargetPitch(width, bytes_per_element, rt.attrib.num_fragments);
|
||||
if (volume) {
|
||||
pitch = TileGetTexturePitch(transfer_format, width, levels, rt.attrib3.tile_mode);
|
||||
} else if (standard64) {
|
||||
pitch = TileGetTexturePitch(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float),
|
||||
width, levels, rt.attrib3.tile_mode);
|
||||
} else {
|
||||
pitch = TileGetRenderTargetPitch(width, bytes_per_element, rt.attrib.num_fragments);
|
||||
}
|
||||
if (pitch == 0) {
|
||||
EXIT("unsupported render-target pitch: width=%u bytes=%u\n", width, bytes_per_element);
|
||||
}
|
||||
@@ -176,9 +192,19 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
pitch = width;
|
||||
}
|
||||
|
||||
TileSizeOffset mip_sizes[16] {};
|
||||
TilePaddedSize mip_padded[16] {};
|
||||
if (tile) {
|
||||
TileSizeOffset mip_sizes[16] {};
|
||||
TilePaddedSize mip_padded[16] {};
|
||||
TileVolumeLayout volume_layout {};
|
||||
uint64_t backing_size = 0;
|
||||
if (volume) {
|
||||
if (!tile || !TileGetTextureVolumeLayout(transfer_format, width, height, depth, levels,
|
||||
rt.attrib3.tile_mode, volume_layout)) {
|
||||
EXIT("unsupported 3D render-target layout: %ux%ux%u levels=%u tile=%u\n", width, height,
|
||||
depth, levels, rt.attrib3.tile_mode);
|
||||
}
|
||||
size = volume_layout.block_slice_size;
|
||||
backing_size = volume_layout.total_size;
|
||||
} else if (tile) {
|
||||
TileSizeAlign layout {};
|
||||
bool valid_layout = false;
|
||||
if (standard64) {
|
||||
@@ -203,12 +229,6 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
mip_sizes[0] = {static_cast<uint32_t>(size), 0, 0, 0, 0, 0};
|
||||
mip_padded[0] = {pitch, height};
|
||||
}
|
||||
if (rt.slice.slice_div64_minus1 != 0 &&
|
||||
(static_cast<uint64_t>(rt.slice.slice_div64_minus1) + 1u) * 64u != size) {
|
||||
EXIT("render-target slice span mismatch: encoded=0x%016" PRIx64 " derived=0x%016" PRIx64
|
||||
"\n",
|
||||
(static_cast<uint64_t>(rt.slice.slice_div64_minus1) + 1u) * 64u, size);
|
||||
}
|
||||
} else {
|
||||
size = static_cast<uint64_t>(pitch) * height * bytes_per_element * samples;
|
||||
if (size > UINT32_MAX) {
|
||||
@@ -217,40 +237,66 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
mip_sizes[0] = {static_cast<uint32_t>(size), 0, 0, 0, 0, 0};
|
||||
mip_padded[0] = {pitch, height};
|
||||
}
|
||||
if (size == 0 || size > UINT64_MAX / view.image_layers) {
|
||||
if (rt.slice.slice_div64_minus1 != 0 &&
|
||||
(static_cast<uint64_t>(rt.slice.slice_div64_minus1) + 1u) * 64u != size) {
|
||||
EXIT("render-target slice span mismatch: encoded=0x%016" PRIx64 " derived=0x%016" PRIx64
|
||||
"\n",
|
||||
(static_cast<uint64_t>(rt.slice.slice_div64_minus1) + 1u) * 64u, size);
|
||||
}
|
||||
if (size == 0 || (!volume && size > UINT64_MAX / view.image_layers)) {
|
||||
EXIT("render-target memory footprint is invalid\n");
|
||||
}
|
||||
const auto backing_size = size * view.image_layers;
|
||||
if (!volume) {
|
||||
backing_size = size * view.image_layers;
|
||||
}
|
||||
if (backing_size == 0) {
|
||||
EXIT("render-target backing is empty\n");
|
||||
}
|
||||
if (backing_size > TRACKER_ADDRESS_SIZE - rt.base.addr) {
|
||||
EXIT("render-target backing range is invalid\n");
|
||||
}
|
||||
|
||||
const vk::Extent2D view_extent = {std::max(width >> rt.view.current_mip_level, 1u),
|
||||
std::max(height >> rt.view.current_mip_level, 1u)};
|
||||
const uint32_t view_depth = std::max(depth >> rt.view.current_mip_level, 1u);
|
||||
if (volume &&
|
||||
(view.base_layer >= view_depth || view.layer_count > view_depth - view.base_layer)) {
|
||||
EXIT("3D render-target view exceeds mip depth: base=%u count=%u depth=%u mip=%u\n",
|
||||
view.base_layer, view.layer_count, view_depth, rt.view.current_mip_level);
|
||||
}
|
||||
|
||||
auto decision_log_id = g_render_color_log_count.fetch_add(1);
|
||||
if (decision_log_id < 128) {
|
||||
LOGF("RenderColorTarget: slot=%" PRIu32 " addr=0x%010" PRIx64 " size=0x%016" PRIx64
|
||||
" extent=%ux%u view_mip=%u view_extent=%ux%u levels=%u pitch=%u"
|
||||
" extent=%ux%ux%u view_mip=%u view_extent=%ux%u levels=%u pitch=%u"
|
||||
" fmt=0x%08" PRIx32 " nfmt=0x%08" PRIx32 " order=0x%08" PRIx32 " samples=%u tile=%s\n",
|
||||
rt_slot, rt.base.addr, backing_size, width, height, rt.view.current_mip_level,
|
||||
rt_slot, rt.base.addr, backing_size, width, height, depth, rt.view.current_mip_level,
|
||||
view_extent.width, view_extent.height, levels, pitch, rt.info.format,
|
||||
rt.info.channel_type, rt.info.channel_order, samples, tile ? "tiled" : "linear");
|
||||
}
|
||||
|
||||
TextureCache::ImageDesc desc {};
|
||||
desc.type = TextureCache::BindingType::RenderTarget;
|
||||
desc.info.data = {rt.base.addr, backing_size};
|
||||
desc.info.pixel_format = target_format.format;
|
||||
desc.info.guest_format = ImageOps::RenderTargetTransferFormat(bytes_per_element);
|
||||
desc.info.type = Prospero::ImageType::kColor2D;
|
||||
desc.info.extent = {width, height, 1};
|
||||
desc.info.resources = {levels, view.image_layers};
|
||||
desc.info.pitch = pitch;
|
||||
desc.type = TextureCache::BindingType::RenderTarget;
|
||||
desc.info.data = {rt.base.addr, backing_size};
|
||||
desc.info.pixel_format = target_format.format;
|
||||
desc.info.guest_format = transfer_format;
|
||||
desc.info.type = volume ? Prospero::ImageType::kColor3D : Prospero::ImageType::kColor2D;
|
||||
desc.info.extent = {width, height, depth};
|
||||
desc.info.resources = {levels, volume ? 1u : view.image_layers};
|
||||
desc.info.pitch = pitch;
|
||||
desc.info.bytes_per_block = bytes_per_element;
|
||||
desc.info.samples = samples;
|
||||
desc.info.tile_mode = rt.attrib3.tile_mode;
|
||||
for (uint32_t level = 0; level < levels; level++) {
|
||||
if (volume) {
|
||||
desc.info.mip_layout[level] = {
|
||||
volume_layout.level_offsets[level],
|
||||
volume_layout.level_sizes[level],
|
||||
volume_layout.level_widths[level],
|
||||
volume_layout.level_heights[level],
|
||||
};
|
||||
continue;
|
||||
}
|
||||
const auto level_offset =
|
||||
mip_sizes[level].src_size != 0 ? mip_sizes[level].src_offset : mip_sizes[level].offset;
|
||||
const auto level_size =
|
||||
|
||||
@@ -359,30 +359,12 @@ static void RtCheck(const HW::RenderTarget& rt) {
|
||||
logged = true;
|
||||
}
|
||||
}
|
||||
if (rt.attrib3.depth != 0x00000000) {
|
||||
static bool logged = false;
|
||||
if (!logged) {
|
||||
LOGF("RenderTarget: temporary: ignoring PS5 color target depth_minus1=0x%08" PRIx32
|
||||
"\n",
|
||||
rt.attrib3.depth);
|
||||
logged = true;
|
||||
}
|
||||
}
|
||||
if (!RenderIsColorTileMode(rt.attrib3.tile_mode)) {
|
||||
EXIT("unknown PS5 render-target tile mode: 0x%08" PRIx32 "\n", rt.attrib3.tile_mode);
|
||||
}
|
||||
if (!RenderIsColorDimension(rt.attrib3.dimension)) {
|
||||
EXIT("unknown PS5 render-target dimension: 0x%08" PRIx32 "\n", rt.attrib3.dimension);
|
||||
}
|
||||
if (rt.attrib3.dimension != 0x00000001) {
|
||||
static bool logged = false;
|
||||
if (!logged) {
|
||||
LOGF("RenderTarget: temporary: using 2D fallback for PS5 color "
|
||||
"dimension=0x%08" PRIx32 "\n",
|
||||
rt.attrib3.dimension);
|
||||
logged = true;
|
||||
}
|
||||
}
|
||||
if (!rt.attrib3.cmask_pipe_aligned) {
|
||||
static bool logged = false;
|
||||
if (!logged) {
|
||||
|
||||
@@ -96,9 +96,11 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
|
||||
const auto& dc = hw.GetDepthControl();
|
||||
const auto& sc = hw.GetStencilControl();
|
||||
const auto& sm = hw.GetStencilMask();
|
||||
const bool depth_active =
|
||||
const bool has_stencil =
|
||||
z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid);
|
||||
const bool depth_active =
|
||||
dc.z_enable || dc.z_write_enable || dc.depth_bounds_enable || rc.depth_clear_enable;
|
||||
const bool stencil_active = dc.stencil_enable || rc.stencil_clear_enable;
|
||||
const bool stencil_active = has_stencil && (dc.stencil_enable || rc.stencil_clear_enable);
|
||||
if (!depth_active && !stencil_active) {
|
||||
return;
|
||||
}
|
||||
@@ -139,8 +141,6 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
|
||||
}
|
||||
return;
|
||||
}
|
||||
const bool has_stencil =
|
||||
z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid);
|
||||
const bool has_htile = z.z_info.htile_acceleration;
|
||||
const auto samples = render_sample_count(z.z_info.num_samples);
|
||||
if (samples == 0) {
|
||||
@@ -156,8 +156,8 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
|
||||
DepthFatal("invalid depth view: base=%u last=%u", z.depth_view.slice_start,
|
||||
z.depth_view.slice_max);
|
||||
}
|
||||
if ((stencil_active && !has_stencil) || rc.resummarize_enable || rc.copy_centroid ||
|
||||
rc.copy_sample != 0 || z.z_info.expclear_enabled || z.stencil_info.expclear_enabled ||
|
||||
if (rc.resummarize_enable || rc.copy_centroid || rc.copy_sample != 0 ||
|
||||
z.z_info.expclear_enabled || z.stencil_info.expclear_enabled ||
|
||||
z.z_info.partially_resident || z.stencil_info.partially_resident ||
|
||||
z.z_info.max_mip_level != 0 || z.depth_view.current_mip_level != 0 ||
|
||||
z.depth_info.addr5_swizzle_mask != 0 || z.depth_info.array_mode != 0 ||
|
||||
@@ -279,10 +279,10 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
|
||||
r.depth_min_bounds = hw.GetDepthBoundsMin();
|
||||
r.depth_max_bounds = hw.GetDepthBoundsMax();
|
||||
|
||||
r.stencil_clear_enable = rc.stencil_clear_enable;
|
||||
r.stencil_clear_enable = has_stencil && rc.stencil_clear_enable;
|
||||
r.stencil_clear_value = hw.GetStencilClearValue();
|
||||
r.stencil_test_enable = dc.stencil_enable;
|
||||
if (dc.stencil_enable) {
|
||||
r.stencil_test_enable = has_stencil && dc.stencil_enable;
|
||||
if (r.stencil_test_enable) {
|
||||
if (dc.stencilfunc > static_cast<uint8_t>(vk::CompareOp::eAlways) ||
|
||||
(dc.backface_enable &&
|
||||
dc.stencilfunc_bf > static_cast<uint8_t>(vk::CompareOp::eAlways)) ||
|
||||
|
||||
@@ -105,6 +105,10 @@ Image::Barriers Image::GetBarriers(vk::ImageLayout destinat
|
||||
std::optional<ImageSubresourceRange> range) {
|
||||
auto& state = backing.state;
|
||||
auto& subresource_states = backing.subresource_states;
|
||||
if (range && info.IsVolume()) {
|
||||
range->base_layer = 0;
|
||||
range->layer_count = 1;
|
||||
}
|
||||
|
||||
const bool partial =
|
||||
range && (range->base_level != 0 || range->level_count != info.resources.levels ||
|
||||
|
||||
@@ -141,14 +141,14 @@ elseif(LINUX)
|
||||
endif()
|
||||
|
||||
|
||||
set(tidy_dirs "${CMAKE_SOURCE_DIR}/launcher/include")
|
||||
set(iwyu_maps "${CMAKE_SOURCE_DIR}/launcher/utils/qt6_16.imp")
|
||||
set(tidy_dirs "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
set(iwyu_maps "${CMAKE_CURRENT_SOURCE_DIR}/utils/qt6_16.imp")
|
||||
|
||||
get_property(inc_headers TARGET launcher PROPERTY INCLUDE_DIRECTORIES)
|
||||
|
||||
list(APPEND inc_headers
|
||||
${CMAKE_SOURCE_DIR}/launcher
|
||||
${CMAKE_BINARY_DIR}/launcher/launcher_autogen/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/launcher_autogen/include
|
||||
${Qt6Widgets_INCLUDE_DIRS}
|
||||
${Qt6Core_INCLUDE_DIRS}
|
||||
${Qt6Gui_INCLUDE_DIRS}
|
||||
|
||||
@@ -221,57 +221,6 @@ static RegisterDefaults* get_internal_register_defaults(uint32_t ver) {
|
||||
return get_register_defaults(g_agc_internal_reg_defaults_by_version[index], &storage[index]);
|
||||
}
|
||||
|
||||
struct PendingGraphicsSegment {
|
||||
uint32_t* start = nullptr;
|
||||
uint32_t* end = nullptr;
|
||||
uint32_t* range_end = nullptr;
|
||||
};
|
||||
|
||||
static std::mutex g_pending_graphics_segment_mutex;
|
||||
static PendingGraphicsSegment g_pending_graphics_segment;
|
||||
|
||||
static void track_pending_graphics_segment_after_submit(uint32_t* dcb, uint32_t size_in_dwords) {
|
||||
if (dcb == nullptr || size_in_dwords == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* segment_start = dcb + size_in_dwords;
|
||||
auto* range_end = segment_start + 0xfffffu;
|
||||
|
||||
std::lock_guard lock(g_pending_graphics_segment_mutex);
|
||||
g_pending_graphics_segment.start = segment_start;
|
||||
g_pending_graphics_segment.end = segment_start;
|
||||
g_pending_graphics_segment.range_end = range_end;
|
||||
}
|
||||
|
||||
static void track_pending_graphics_allocation(uint32_t* cmd, uint32_t size_dw) {
|
||||
if (cmd == nullptr || size_dw == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard lock(g_pending_graphics_segment_mutex);
|
||||
auto* range_start = g_pending_graphics_segment.start;
|
||||
auto* range_end = g_pending_graphics_segment.range_end;
|
||||
if (range_start == nullptr || range_end == nullptr || cmd < range_start || cmd >= range_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* cmd_end = cmd + size_dw;
|
||||
if (cmd > g_pending_graphics_segment.end) {
|
||||
static std::atomic<uint32_t> log_count {0};
|
||||
if (log_count.fetch_add(1) < 64) {
|
||||
LOGF("\t pending graphics segment: ignoring non-contiguous allocation cmd = "
|
||||
"0x%016" PRIx64 ", tracked_end = 0x%016" PRIx64 "\n",
|
||||
reinterpret_cast<uint64_t>(cmd),
|
||||
reinterpret_cast<uint64_t>(g_pending_graphics_segment.end));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cmd_end > g_pending_graphics_segment.end && cmd_end <= range_end) {
|
||||
g_pending_graphics_segment.end = cmd_end;
|
||||
}
|
||||
}
|
||||
|
||||
struct CommandBuffer {
|
||||
using Callback = KYTY_SYSV_ABI bool (*)(CommandBuffer*, uint32_t, void*);
|
||||
|
||||
@@ -370,7 +319,6 @@ struct CommandBuffer {
|
||||
}
|
||||
auto* ret_ptr = cursor_up;
|
||||
cursor_up += size_dw;
|
||||
track_pending_graphics_allocation(ret_ptr, size_dw);
|
||||
return ret_ptr;
|
||||
}
|
||||
};
|
||||
@@ -1918,7 +1866,6 @@ uint32_t* KYTY_SYSV_ABI GraphicsCbReleaseMem(CommandBuffer* buf, uint8_t action,
|
||||
cmd[5] = static_cast<uint32_t>(packet_data & 0xffffffffu);
|
||||
cmd[6] = static_cast<uint32_t>((packet_data >> 32u) & 0xffffffffu);
|
||||
cmd[7] = interrupt_ctx_id & 0x07ffffffu;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -3815,150 +3762,6 @@ static void submit_dcb(uint32_t* dcb, uint32_t size_in_dwords) {
|
||||
EXIT_IF(g_renderer == nullptr);
|
||||
g_renderer->GetGpu().Submit(dcb, size_in_dwords, nullptr, 0,
|
||||
!dcb_has_queued_interrupt(dcb, size_in_dwords));
|
||||
Gen5::track_pending_graphics_segment_after_submit(dcb, size_in_dwords);
|
||||
}
|
||||
|
||||
static std::vector<uint64_t> collect_acb_wait_addresses(const uint32_t* acb,
|
||||
uint32_t size_in_dwords) {
|
||||
std::vector<uint64_t> addresses;
|
||||
|
||||
for (uint32_t offset = 0; offset < size_in_dwords;) {
|
||||
auto cmd_id = acb[offset];
|
||||
auto len = KYTY_PM4_LEN(cmd_id);
|
||||
if (len == 0 || len > size_in_dwords - offset) {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
auto op = (cmd_id >> 8u) & 0xffu;
|
||||
if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd_id) == Pm4::R_WAIT_MEM_32 && len >= 7) {
|
||||
auto address = static_cast<uint64_t>(acb[offset + 1]) |
|
||||
(static_cast<uint64_t>(acb[offset + 2]) << 32u);
|
||||
if (address != 0) {
|
||||
addresses.push_back(address);
|
||||
}
|
||||
} else if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd_id) == Pm4::R_WAIT_MEM_64 && len >= 9) {
|
||||
auto address = static_cast<uint64_t>(acb[offset + 1]) |
|
||||
(static_cast<uint64_t>(acb[offset + 2]) << 32u);
|
||||
if (address != 0) {
|
||||
addresses.push_back(address);
|
||||
}
|
||||
}
|
||||
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
static bool acb_waits_for_address(const std::vector<uint64_t>& wait_addresses,
|
||||
uint64_t release_address) {
|
||||
for (auto address: wait_addresses) {
|
||||
if (address == release_address) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void flush_pending_graphics_segment_before_acb(const uint32_t* acb,
|
||||
uint32_t acb_size_in_dwords) {
|
||||
uint32_t* dcb = nullptr;
|
||||
uint32_t size_in_dwords = 0;
|
||||
auto wait_addresses = collect_acb_wait_addresses(acb, acb_size_in_dwords);
|
||||
|
||||
{
|
||||
std::lock_guard lock(Gen5::g_pending_graphics_segment_mutex);
|
||||
if (!wait_addresses.empty() && Gen5::g_pending_graphics_segment.start != nullptr) {
|
||||
auto* scan = Gen5::g_pending_graphics_segment.start;
|
||||
auto* matched_end = Gen5::g_pending_graphics_segment.start;
|
||||
while (scan < Gen5::g_pending_graphics_segment.end) {
|
||||
auto cmd_id = *scan;
|
||||
if (cmd_id == 0x80000000u) {
|
||||
scan++;
|
||||
continue;
|
||||
}
|
||||
if ((cmd_id & 0xC0000000u) != 0xC0000000u) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto len = KYTY_PM4_LEN(cmd_id);
|
||||
if (len == 0 ||
|
||||
len > static_cast<uint32_t>(Gen5::g_pending_graphics_segment.end - scan)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (((cmd_id >> 8u) & 0xffu) == Pm4::IT_NOP &&
|
||||
KYTY_PM4_R(cmd_id) == Pm4::R_RELEASE_MEM && len >= 7) {
|
||||
auto release_addr =
|
||||
static_cast<uint64_t>(scan[3]) | (static_cast<uint64_t>(scan[4]) << 32u);
|
||||
if (acb_waits_for_address(wait_addresses, release_addr)) {
|
||||
matched_end = scan + len;
|
||||
}
|
||||
}
|
||||
|
||||
scan += len;
|
||||
}
|
||||
|
||||
if (matched_end > Gen5::g_pending_graphics_segment.start) {
|
||||
Gen5::g_pending_graphics_segment.end = matched_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (Gen5::g_pending_graphics_segment.start != nullptr &&
|
||||
Gen5::g_pending_graphics_segment.end > Gen5::g_pending_graphics_segment.start) {
|
||||
auto* scan = Gen5::g_pending_graphics_segment.start;
|
||||
auto* valid_end = Gen5::g_pending_graphics_segment.start;
|
||||
while (scan < Gen5::g_pending_graphics_segment.end) {
|
||||
auto cmd_id = *scan;
|
||||
if (cmd_id == 0x80000000u) {
|
||||
scan++;
|
||||
valid_end = scan;
|
||||
continue;
|
||||
}
|
||||
if ((cmd_id & 0xC0000000u) != 0xC0000000u) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto len = KYTY_PM4_LEN(cmd_id);
|
||||
if (len == 0 ||
|
||||
len > static_cast<uint32_t>(Gen5::g_pending_graphics_segment.end - scan)) {
|
||||
break;
|
||||
}
|
||||
|
||||
scan += len;
|
||||
valid_end = scan;
|
||||
}
|
||||
|
||||
if (valid_end < Gen5::g_pending_graphics_segment.end) {
|
||||
static std::atomic<uint32_t> log_count {0};
|
||||
if (log_count.fetch_add(1) < 64) {
|
||||
LOGF("\t trimming pending graphics segment: addr = 0x%016" PRIx64
|
||||
", old_dw = 0x%08" PRIx32 ", new_dw = 0x%08" PRIx32 "\n",
|
||||
reinterpret_cast<uint64_t>(Gen5::g_pending_graphics_segment.start),
|
||||
static_cast<uint32_t>(Gen5::g_pending_graphics_segment.end -
|
||||
Gen5::g_pending_graphics_segment.start),
|
||||
static_cast<uint32_t>(valid_end - Gen5::g_pending_graphics_segment.start));
|
||||
}
|
||||
Gen5::g_pending_graphics_segment.end = valid_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (Gen5::g_pending_graphics_segment.start == nullptr ||
|
||||
Gen5::g_pending_graphics_segment.end <= Gen5::g_pending_graphics_segment.start) {
|
||||
return;
|
||||
}
|
||||
|
||||
dcb = Gen5::g_pending_graphics_segment.start;
|
||||
size_in_dwords = static_cast<uint32_t>(Gen5::g_pending_graphics_segment.end -
|
||||
Gen5::g_pending_graphics_segment.start);
|
||||
}
|
||||
|
||||
LOGF("\t flushing pending graphics segment before ACB: addr = 0x%016" PRIx64
|
||||
", dw_num = 0x%08" PRIx32 "\n",
|
||||
reinterpret_cast<uint64_t>(dcb), size_in_dwords);
|
||||
|
||||
submit_dcb(dcb, size_in_dwords);
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitDcb(const Packet* packet) {
|
||||
@@ -4074,8 +3877,6 @@ static void submit_acb(uint32_t queue, uint32_t* acb, uint32_t size_in_dwords) {
|
||||
LOGF("\t acb[%u] = 0x%08" PRIx32 "\n", i, acb[i]);
|
||||
}
|
||||
|
||||
flush_pending_graphics_segment_before_acb(acb, size_in_dwords);
|
||||
|
||||
GraphicsDbgDumpDcb("a", size_in_dwords, acb);
|
||||
|
||||
const bool trigger_interrupt_on_done = !dcb_has_queued_interrupt(acb, size_in_dwords);
|
||||
|
||||
@@ -97,6 +97,10 @@ int KYTY_SYSV_ABI NetShutdown(int s, int how) {
|
||||
return FinishSocketCall(Net::Shutdown(s, how));
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI NetGetsockname(int s, void* addr, uint32_t* addrlen) {
|
||||
return FinishSocketCall(Net::Getsockname(s, addr, addrlen));
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI NetPoolCreate(const char* name, int size, int flags) {
|
||||
return NET_CALL(Net::NetPoolCreate(name, size, flags));
|
||||
}
|
||||
@@ -196,6 +200,7 @@ LIB_DEFINE(InitNet_1_Net) {
|
||||
LIB_FUNC("v6M4txecCuo", LibNet::NetEtherNtostr);
|
||||
LIB_FUNC("6Oc0bLsIYe0", LibNet::NetGetMacAddress);
|
||||
LIB_FUNC("hLuXdjHnhiI", LibNet::NetGetSockInfo);
|
||||
LIB_FUNC("hoOAofhhRvE", LibNet::NetGetsockname);
|
||||
LIB_FUNC("SF47kB2MNTo", LibNet::NetEpollCreate);
|
||||
LIB_FUNC("ZVw46bsasAk", LibNet::NetEpollControl);
|
||||
LIB_FUNC("drjIbDbA7UQ", LibNet::NetEpollWait);
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <chrono>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
@@ -248,6 +249,12 @@ struct RenderExecutorTestAccess {
|
||||
executor.ResolveRenderDepthTarget(submit_id, buffer, depth);
|
||||
}
|
||||
|
||||
static void ResolveRenderColorTarget(RenderExecutor& executor, uint64_t submit_id,
|
||||
RenderCommandBuffer& buffer, RenderColorInfo& color,
|
||||
uint32_t slot) {
|
||||
executor.ResolveRenderColorTarget(submit_id, buffer, color, 0, slot);
|
||||
}
|
||||
|
||||
static void BindRenderTarget(RenderExecutor& executor, ImageId id) {
|
||||
executor.BindRenderTarget(id);
|
||||
}
|
||||
@@ -1444,22 +1451,91 @@ public:
|
||||
uint32_t ordered_suffix = 0;
|
||||
std::jthread ordered([&] {
|
||||
ordered_started.release();
|
||||
Gpu::SubmissionLock submissions(gpu);
|
||||
gpu.SendCommandSync([&] {
|
||||
ordered_suffix = suffix;
|
||||
ordered_finished = true;
|
||||
});
|
||||
gpu.Done();
|
||||
ordered_suffix = suffix;
|
||||
ordered_finished = true;
|
||||
});
|
||||
ordered_started.acquire();
|
||||
gpu.SendCommandSync([&] {
|
||||
Require("GpuCommandLane", "ordered barrier", !ordered_finished.load(),
|
||||
"ordered host command overtook a queued submission");
|
||||
Require("GpuCommandLane", "submit done barrier", !ordered_finished.load(),
|
||||
"submit done returned before a queued submission");
|
||||
label = 1;
|
||||
});
|
||||
ordered.join();
|
||||
Require("GpuCommandLane", "ordered completion",
|
||||
prefix == 11 && suffix == 22 && ordered_suffix == 22 && ordered_finished.load(),
|
||||
"submission barrier did not drain prior PM4 work");
|
||||
"submit done did not drain prior PM4 work");
|
||||
|
||||
auto& resources = context.GetGpuResources();
|
||||
constexpr uint64_t empty_unmap_base = 0x0000000200400000ull;
|
||||
constexpr uint64_t empty_unmap_size = 0x4000;
|
||||
resources.MapMemory(empty_unmap_base, empty_unmap_size);
|
||||
label = 0;
|
||||
prefix = 0;
|
||||
suffix = 0;
|
||||
gpu.Submit(commands.data(), static_cast<uint32_t>(commands.size()), nullptr, 0);
|
||||
|
||||
std::binary_semaphore unmap_complete {0};
|
||||
std::jthread unmap_thread([&] {
|
||||
resources.UnmapMemory(empty_unmap_base, empty_unmap_size);
|
||||
unmap_complete.release();
|
||||
});
|
||||
const bool unmap_returned = unmap_complete.try_acquire_for(std::chrono::seconds(2));
|
||||
gpu.SendCommandSync([&] { label = 1; });
|
||||
if (!unmap_returned) {
|
||||
unmap_complete.acquire();
|
||||
}
|
||||
unmap_thread.join();
|
||||
gpu.Done();
|
||||
Require("GpuCommandLane", "unmap queue progress",
|
||||
unmap_returned && !resources.IsMapped(empty_unmap_base, empty_unmap_size) &&
|
||||
prefix == 11 && suffix == 22,
|
||||
"an unrelated unmap waited for a blocked PM4 submission");
|
||||
|
||||
auto& scheduler = context.GetCommandScheduler();
|
||||
std::atomic<bool> normal_completed {false};
|
||||
gpu.SendCommandSync(
|
||||
[&] { scheduler.DeferOperation([&] { normal_completed = true; }); });
|
||||
resources.MapMemory(empty_unmap_base, empty_unmap_size);
|
||||
resources.UnmapMemory(empty_unmap_base, empty_unmap_size);
|
||||
Require("GpuCommandLane", "unmap native completion",
|
||||
normal_completed.load() &&
|
||||
!resources.IsMapped(empty_unmap_base, empty_unmap_size),
|
||||
"unmap returned before an earlier native guest-memory callback");
|
||||
|
||||
std::binary_semaphore priority_entered {0};
|
||||
std::binary_semaphore release_priority {0};
|
||||
gpu.SendCommandSync([&] {
|
||||
scheduler.DeferPriorityOperation([&] {
|
||||
priority_entered.release();
|
||||
release_priority.acquire();
|
||||
});
|
||||
scheduler.Flush();
|
||||
});
|
||||
priority_entered.acquire();
|
||||
resources.MapMemory(empty_unmap_base, empty_unmap_size);
|
||||
|
||||
std::binary_semaphore priority_unmap_entered {0};
|
||||
std::binary_semaphore priority_unmap_complete {0};
|
||||
std::jthread priority_unmap_thread([&] {
|
||||
gpu.SendCommandSync([&] {
|
||||
priority_unmap_entered.release();
|
||||
resources.UnmapMemory(empty_unmap_base, empty_unmap_size);
|
||||
});
|
||||
priority_unmap_complete.release();
|
||||
});
|
||||
priority_unmap_entered.acquire();
|
||||
const bool unmap_overtook_priority =
|
||||
priority_unmap_complete.try_acquire_for(std::chrono::seconds(1));
|
||||
release_priority.release();
|
||||
if (!unmap_overtook_priority) {
|
||||
priority_unmap_complete.acquire();
|
||||
}
|
||||
priority_unmap_thread.join();
|
||||
Require("GpuCommandLane", "unmap priority ordering",
|
||||
!unmap_overtook_priority &&
|
||||
!resources.IsMapped(empty_unmap_base, empty_unmap_size),
|
||||
"unmap returned before an earlier guest-memory callback");
|
||||
|
||||
constexpr uintptr_t fault_base = 0x0000000200500000ull;
|
||||
constexpr uint64_t fault_size = 0x10000;
|
||||
@@ -1477,7 +1553,6 @@ public:
|
||||
Require("GpuCommandLane", "processor fault allocation",
|
||||
fault_memory == reinterpret_cast<void*>(fault_base),
|
||||
"fixed processor-fault allocation failed");
|
||||
auto& resources = context.GetGpuResources();
|
||||
resources.MapMemory(fault_base, fault_size);
|
||||
|
||||
constexpr uint64_t immediate_dst = fault_base + 0x1000;
|
||||
@@ -1524,9 +1599,7 @@ public:
|
||||
Require("GpuCommandLane", "DMA_DATA packet assembly", dma_cursor == dma_commands.size(),
|
||||
"DMA_DATA GDS packet stream has the wrong size");
|
||||
gpu.Submit(dma_commands.data(), static_cast<uint32_t>(dma_commands.size()), nullptr, 0);
|
||||
{
|
||||
Gpu::SubmissionLock submissions(gpu);
|
||||
}
|
||||
gpu.Done();
|
||||
constexpr uint32_t clean_fill_value = 0xdecafbad;
|
||||
gpu.SendCommandSyncWithProcessor([&](CommandProcessor&) {
|
||||
auto& buffer_cache = resources.GetBufferCache();
|
||||
@@ -4751,6 +4824,155 @@ public:
|
||||
std::printf("[gpu] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckRenderExecutorColorVolumeDiscovery() {
|
||||
constexpr const char* name = "RenderExecutorColorVolumeDiscovery";
|
||||
constexpr uintptr_t base = 0x0000000203e00000ull;
|
||||
constexpr uint64_t allocation_size = 0x200000;
|
||||
constexpr uint64_t allocation_alignment = 0x10000;
|
||||
EnsureRuntimeContext();
|
||||
|
||||
int64_t direct_offset = -1;
|
||||
Require(name, "direct allocation",
|
||||
Libs::LibKernel::Memory::KernelAllocateDirectMemory(
|
||||
0, Libs::LibKernel::Memory::KernelGetDirectMemorySize(), allocation_size,
|
||||
allocation_alignment, 0, &direct_offset) == 0,
|
||||
"color-volume direct-memory allocation failed");
|
||||
void* mapped = reinterpret_cast<void*>(base);
|
||||
Require(name, "direct mapping",
|
||||
Libs::LibKernel::Memory::KernelMapDirectMemory(&mapped, allocation_size, 0x3, 0x10,
|
||||
direct_offset,
|
||||
allocation_alignment) == 0 &&
|
||||
mapped == reinterpret_cast<void*>(base),
|
||||
"color-volume fixed mapping failed");
|
||||
std::memset(mapped, 0, allocation_size);
|
||||
constexpr uint64_t slice_size = 0x10000;
|
||||
std::memset(static_cast<uint8_t*>(mapped) + 31 * slice_size, 0x5a, slice_size);
|
||||
|
||||
{
|
||||
RenderContext context(m_runtime_context);
|
||||
auto& scheduler = context.GetCommandScheduler();
|
||||
HW::Context registers {};
|
||||
HW::UserConfig user_config {};
|
||||
HW::Shader shaders {};
|
||||
registers.SetColorBase(0, {.addr = base});
|
||||
registers.SetColorInfo(
|
||||
0, {.format = Prospero::GpuEnumValue(Prospero::ChannelLayout::k10_10_10_2),
|
||||
.channel_type = Prospero::GpuEnumValue(Prospero::ChannelType::kUNorm),
|
||||
.channel_order = Prospero::GpuEnumValue(Prospero::ChannelOrder::kStandard)});
|
||||
registers.SetColorAttrib2(0, {.height = 31, .width = 31});
|
||||
registers.SetColorAttrib3(
|
||||
0, {.depth = 31,
|
||||
.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget),
|
||||
.dimension = 2,
|
||||
.cmask_pipe_aligned = true,
|
||||
.dcc_pipe_aligned = true});
|
||||
registers.SetRenderTargetMask(0x0f);
|
||||
scheduler.Begin(registers, user_config, shaders);
|
||||
|
||||
auto& resources = context.GetGpuResources();
|
||||
auto& texture_cache = resources.GetTextureCache();
|
||||
auto& executor = context.GetRenderExecutor();
|
||||
resources.MapMemory(base, allocation_size);
|
||||
|
||||
RenderColorInfo color {};
|
||||
RenderExecutorTestAccess::ResolveRenderColorTarget(executor, 1, scheduler.Current(),
|
||||
color, 0);
|
||||
const auto attachment = texture_cache.FindRenderTarget(color.image_id, color.desc);
|
||||
const auto& image = texture_cache.GetImage(color.image_id);
|
||||
Require(name, "captured 3D target",
|
||||
color.image_id && attachment != nullptr &&
|
||||
color.desc.info.type == Prospero::ImageType::kColor3D &&
|
||||
color.desc.info.extent == vk::Extent3D {32, 32, 32} &&
|
||||
color.desc.info.resources == ImageSubresources {1, 1} &&
|
||||
color.desc.info.pitch == 128 &&
|
||||
color.desc.info.data.size == allocation_size &&
|
||||
color.desc.info.mip_layout[0].size == 0x10000 &&
|
||||
color.desc.view_info.type == vk::ImageViewType::e2D &&
|
||||
color.desc.view_info.layer_count == 1 &&
|
||||
image.backing.image_type == vk::ImageType::e3D &&
|
||||
static_cast<bool>(image.backing.flags &
|
||||
vk::ImageCreateFlagBits::e2DArrayCompatible) &&
|
||||
image.usage.render_target && image.IsGpuModified(),
|
||||
"dimension=2/depth=31 did not create the SDK-defined 32x32x32 "
|
||||
"backing and 2D "
|
||||
"attachment slice");
|
||||
|
||||
RenderExecutorTestAccess::ResetBindings(executor);
|
||||
registers.SetColorView(
|
||||
0, {.base_array_slice_index = 7, .last_array_slice_index = 7});
|
||||
RenderColorInfo sliced_color {};
|
||||
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
||||
executor, 2, scheduler.Current(), sliced_color, 0);
|
||||
RenderDepthInfo no_depth {};
|
||||
const auto sliced_rendering = RenderExecutorTestAccess::AcquireRenderTargets(
|
||||
executor, scheduler.Current(), &sliced_color, 1, no_depth);
|
||||
Require(name, "3D slice transition",
|
||||
sliced_color.image_id == color.image_id && sliced_color.image_view != nullptr &&
|
||||
sliced_color.desc.view_info.base_layer == 7 &&
|
||||
sliced_rendering.num_color_attachments == 1 && sliced_rendering.num_layers == 1,
|
||||
"a nonzero 3D attachment slice was treated as a Vulkan array layer");
|
||||
|
||||
auto storage_desc = color.desc;
|
||||
storage_desc.type = BindingType::Storage;
|
||||
storage_desc.info.guest_format =
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm);
|
||||
storage_desc.view_info.type = vk::ImageViewType::e3D;
|
||||
storage_desc.view_info.usage = vk::ImageUsageFlagBits::eStorage;
|
||||
const auto storage_id = texture_cache.FindImage(storage_desc);
|
||||
const auto storage_view = texture_cache.FindTexture(storage_id, storage_desc);
|
||||
const auto& shared_image = texture_cache.GetImage(storage_id);
|
||||
Require(name, "storage alias reuse",
|
||||
storage_id == color.image_id && storage_view != nullptr &&
|
||||
shared_image.IsGpuModified() && shared_image.usage.render_target,
|
||||
"the matching 3D storage binding did not reuse the live "
|
||||
"render-target image");
|
||||
|
||||
Require(name, "volume readback queue",
|
||||
TextureCacheTestAccess::TryDownload(texture_cache, storage_id),
|
||||
"the 3D render target could not be queued for guest-layout readback");
|
||||
auto mirror = resources.GetBufferCache().ObtainBuffer(
|
||||
scheduler.Current(), base, allocation_size, false, true, true);
|
||||
Require(name, "volume mirror",
|
||||
mirror.buffer != nullptr && mirror.owner != nullptr,
|
||||
"the 3D render-target readback has no BufferCache owner");
|
||||
scheduler.Current().RetainResourceUntilFence(mirror.owner);
|
||||
auto slice_probe =
|
||||
CreateHostBuffer(name, 4, vk::BufferUsageFlagBits::eTransferDst, {0});
|
||||
const vk::BufferCopy copy {mirror.offset + 31 * slice_size, 0, 4};
|
||||
scheduler.Current().Handle().copyBuffer(mirror.buffer, slice_probe.buffer, 1, ©);
|
||||
vk::BufferMemoryBarrier barrier {};
|
||||
barrier.sType = vk::StructureType::eBufferMemoryBarrier;
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eHostRead;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.buffer = slice_probe.buffer;
|
||||
barrier.size = slice_probe.size;
|
||||
scheduler.Current().Handle().pipelineBarrier(
|
||||
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eHost, {}, 0, nullptr,
|
||||
1, &barrier, 0, nullptr);
|
||||
scheduler.Finish();
|
||||
scheduler.DrainPriorityOperations();
|
||||
Require(name, "volume Z transfer",
|
||||
ReadBuffer(name, slice_probe, 1) == std::vector<u32> {0x5a5a5a5a},
|
||||
"render-target upload/readback lost the final Z slice");
|
||||
DestroyBuffer(&slice_probe);
|
||||
|
||||
RenderExecutorTestAccess::ResetBindings(executor);
|
||||
resources.UnmapMemory(base, allocation_size);
|
||||
scheduler.Finish();
|
||||
}
|
||||
|
||||
Require(name, "unmap direct backing",
|
||||
Libs::LibKernel::Memory::KernelMunmap(base, allocation_size) == 0,
|
||||
"color-volume direct mapping release failed");
|
||||
Require(
|
||||
name, "release direct backing",
|
||||
Libs::LibKernel::Memory::KernelReleaseDirectMemory(direct_offset, allocation_size) == 0,
|
||||
"color-volume direct-memory allocation release failed");
|
||||
std::printf("[gpu] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckRenderExecutorStencilBindingDiscovery() {
|
||||
constexpr const char* name = "RenderExecutorStencilBindingDiscovery";
|
||||
constexpr uintptr_t base = 0x0000000203600000ull;
|
||||
@@ -5298,6 +5520,43 @@ public:
|
||||
"state at the final acquisition boundary");
|
||||
RenderExecutorTestAccess::ResetBindings(executor);
|
||||
|
||||
constexpr uint64_t depth_only_address = base + 0x140000;
|
||||
HW::DepthRenderTarget depth_only_target {};
|
||||
depth_only_target.z_info.format =
|
||||
Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F);
|
||||
depth_only_target.z_info.z_compare_base = Prospero::ZCompareBase::kZMax;
|
||||
depth_only_target.stencil_info.htile_stencil_disabled = true;
|
||||
depth_only_target.z_read_base_addr = depth_only_address;
|
||||
depth_only_target.z_write_base_addr = depth_only_address;
|
||||
depth_only_target.size = {63, 63, true};
|
||||
registers.SetDepthRenderTarget(depth_only_target);
|
||||
HW::DepthControl depth_only_control {};
|
||||
depth_only_control.stencil_enable = true;
|
||||
depth_only_control.z_enable = true;
|
||||
depth_only_control.z_write_enable = true;
|
||||
depth_only_control.zfunc = static_cast<uint8_t>(vk::CompareOp::eAlways);
|
||||
registers.SetDepthControl(depth_only_control);
|
||||
HW::RenderControl depth_only_render_control {};
|
||||
depth_only_render_control.depth_clear_enable = true;
|
||||
depth_only_render_control.stencil_clear_enable = true;
|
||||
registers.SetRenderControl(depth_only_render_control);
|
||||
RenderDepthInfo depth_only {};
|
||||
RenderExecutorTestAccess::ResolveRenderDepthTarget(executor, 1, scheduler.Current(),
|
||||
depth_only);
|
||||
Require(
|
||||
name, "depth-only target with stale stencil state",
|
||||
depth_only.image_id && depth_only.format == vk::Format::eD32Sfloat &&
|
||||
depth_only.depth_test_enable && depth_only.depth_write_enable &&
|
||||
depth_only.depth_clear_enable && !depth_only.stencil_test_enable &&
|
||||
!depth_only.stencil_clear_enable && depth_only.stencil_buffer_vaddr == 0 &&
|
||||
depth_only.stencil_buffer_size == 0 && depth_only.desc.info.stencil.Empty() &&
|
||||
depth_only.depth_buffer_size != 0 &&
|
||||
depth_only_address + depth_only.depth_buffer_size <= base + allocation_size &&
|
||||
depth_only.vaddr_num == 1 &&
|
||||
depth_only.AttachmentWriteAspects() == vk::ImageAspectFlagBits::eDepth,
|
||||
"raw stencil test or clear state leaked into a depth-only attachment");
|
||||
RenderExecutorTestAccess::ResetBindings(executor);
|
||||
|
||||
auto video_subresource = make_target_desc(base + 0x20000, target_mip_size, {1, 1, 1});
|
||||
video_subresource.type = BindingType::VideoOut;
|
||||
video_subresource.info.pixel_format = vk::Format::eR8G8B8A8Srgb;
|
||||
@@ -17075,6 +17334,7 @@ int main(int argc, char** argv) {
|
||||
CheckDepthAttachmentWrites();
|
||||
CheckDynamicRenderingState();
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckRenderExecutorColorVolumeDiscovery();
|
||||
vulkan.CheckRenderExecutorStencilBindingDiscovery();
|
||||
vulkan.CheckUnifiedTextureCacheFlow();
|
||||
vulkan.CheckBgra16Readback();
|
||||
@@ -17215,6 +17475,7 @@ int main(int argc, char** argv) {
|
||||
vulkan.CheckCommandPoolGrowth();
|
||||
vulkan.CheckGpuTilerCpuParity();
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
vulkan.CheckRenderExecutorColorVolumeDiscovery();
|
||||
vulkan.CheckRenderExecutorStencilBindingDiscovery();
|
||||
vulkan.CheckUnifiedTextureCacheFlow();
|
||||
vulkan.CheckBgra16Readback();
|
||||
|
||||
Reference in New Issue
Block a user