Compare commits

..

5 Commits

Author SHA1 Message Date
boykopovar c4134a95e2 Use repository root as CMake source directory (#153)
* feat(project): add root cmakelists for ide auto-detect

* cmake: use repository root as source directory

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-03 00:34:21 +02:00
nmzik fb5ecec455 renderer: ignore stale stencil state for depth-only targets 2026-08-02 14:14:32 +02:00
nmzik 650d9c91a1 libNet: add missing abi 2026-08-02 13:49:07 +02:00
nmzik fc8d2a3b83 guest_gpu: remove memory-unmap submission deadlock + remove legacy agc buffering 2026-08-02 13:26:29 +02:00
nmzik 59b8fad341 graphics: support 3D color render targets 2026-08-02 09:38:57 +02:00
19 changed files with 525 additions and 478 deletions
+3 -3
View File
@@ -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
View File
@@ -3,4 +3,5 @@
.idea/
build/
_Build/vscode-clang/
_Build/
_Build/
cmake-build-debug/
+1 -1
View File
@@ -1,5 +1,5 @@
{
"cmake.sourceDirectory": "${workspaceFolder}/src",
"cmake.sourceDirectory": "${workspaceFolder}",
"cmake.buildDirectory": "${workspaceFolder}/_Build/vscode-clang",
"cmake.generator": "Ninja",
"cmake.environment": {
+112 -110
View File
@@ -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 .)
+4 -4
View File
@@ -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"
+1 -1
View File
@@ -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
)
+5 -62
View File
@@ -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
-17
View File
@@ -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
View File
@@ -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
View File
@@ -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 =
-18
View File
@@ -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 ||
+4 -4
View File
@@ -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}
-199
View File
@@ -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);
+5
View File
@@ -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);
+273 -12
View File
@@ -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, &copy);
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();