mirror of
https://github.com/sal063/AC6_recomp
synced 2026-06-11 05:08:55 -04:00
feat: wire AC6 native graphics runtime and bootstrap configure path
Run the native renderer every frame from AC6 present timing hooks with a visible runtime status overlay so migration progress is observable in-game. Also add a tracked CMake bootstrap include and migration mapping docs so fresh clones can configure before generated glue exists. Made-with: Cursor
This commit is contained in:
+7
-1
@@ -9,11 +9,17 @@ project(ac6recomp LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include(generated/rexglue.cmake)
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/generated/rexglue.cmake")
|
||||
include(generated/rexglue.cmake)
|
||||
else()
|
||||
include(cmake/rexglue_bootstrap.cmake)
|
||||
endif()
|
||||
|
||||
# Sources
|
||||
set(AC6RECOMP_SOURCES
|
||||
src/main.cpp
|
||||
src/d3d_hooks.cpp
|
||||
src/render_hooks.cpp
|
||||
src/ac6_native_graphics.cpp
|
||||
src/ac6_native_graphics_overlay.cpp
|
||||
src/ac6_native_renderer/ac6_render_frontend.cpp
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# Bootstrap ReXGlue integration for fresh clones where generated/rexglue.cmake
|
||||
# is not present yet.
|
||||
#
|
||||
# This file is intentionally tracked in git so first-time configure works on
|
||||
# all platforms before running codegen.
|
||||
|
||||
# SDK version
|
||||
# Set REXSDK_VERSION to pin a specific SDK version.
|
||||
# Otherwise, the version bundled with this bootstrap is used.
|
||||
set(REXSDK_VERSION "" CACHE STRING "Override SDK version (leave empty for default)")
|
||||
|
||||
# Find SDK
|
||||
set(REXSDK_DIR "" CACHE PATH "Path to rexglue-sdk source tree")
|
||||
if(REXSDK_DIR)
|
||||
add_subdirectory("${REXSDK_DIR}" rexglue-sdk)
|
||||
else()
|
||||
if(REXSDK_VERSION)
|
||||
find_package(rexglue ${REXSDK_VERSION} EXACT QUIET CONFIG)
|
||||
else()
|
||||
find_package(rexglue 0.7.4 QUIET CONFIG)
|
||||
endif()
|
||||
if(NOT rexglue_FOUND)
|
||||
message(FATAL_ERROR
|
||||
"ReXGlue SDK not found. Either:\n"
|
||||
" - Set REXSDK_DIR to the rexglue-sdk source tree (e.g. thirdparty/rexglue-sdk)\n"
|
||||
" - Install the SDK package and ensure it is on CMAKE_PREFIX_PATH")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Include generated code if codegen has been run.
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/generated/sources.cmake")
|
||||
include(generated/sources.cmake)
|
||||
endif()
|
||||
|
||||
# Configure a rexglue target with SDK libraries and platform settings.
|
||||
# Call after add_executable() in your CMakeLists.txt.
|
||||
# Usage: rexglue_setup_target(<target>)
|
||||
macro(rexglue_setup_target target_name)
|
||||
target_sources(${target_name} PRIVATE ${GENERATED_SOURCES})
|
||||
target_include_directories(${target_name} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/generated
|
||||
)
|
||||
target_link_libraries(${target_name} PRIVATE
|
||||
rex::core
|
||||
rex::system
|
||||
rex::kernel
|
||||
rex::graphics
|
||||
rex::ui
|
||||
)
|
||||
rexglue_configure_target(${target_name})
|
||||
endmacro()
|
||||
|
||||
# Codegen target - run:
|
||||
# cmake --build . --target ac6recomp_codegen
|
||||
add_custom_target(ac6recomp_codegen
|
||||
COMMAND $<TARGET_FILE:rex::rexglue> codegen ${CMAKE_CURRENT_SOURCE_DIR}/ac6recomp_config.toml
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generating recompiled code for ac6recomp"
|
||||
VERBATIM
|
||||
)
|
||||
@@ -0,0 +1,131 @@
|
||||
# AC6 Native Graphics Config Migration Matrix
|
||||
|
||||
Date: 2026-04-17
|
||||
Scope: `AC6 recomp` graphics configuration migration
|
||||
Status: initial actionable matrix (to be extended as new graphics keys are discovered)
|
||||
|
||||
Related planning docs:
|
||||
|
||||
- `AC6_NATIVE_GRAPHICS_MIGRATION_STRATEGY_2026-04-17.md`
|
||||
- `AC6_NATIVE_GRAPHICS_API_DEPRECATION_TIMELINE.md`
|
||||
- `AC6_NATIVE_GRAPHICS_EXECUTION_PLAN_2026-04-17.md`
|
||||
|
||||
## Purpose
|
||||
|
||||
This document converts deprecation policy into concrete key-by-key actions. It defines:
|
||||
|
||||
- what legacy graphics keys do today
|
||||
- whether each key is kept, renamed, made dev-only, or removed
|
||||
- when enforcement happens (`M2` through `M6`)
|
||||
- what migration behavior and CI checks are required
|
||||
|
||||
## Enforcement Legend
|
||||
|
||||
- `keep`: remains valid in production native renderer
|
||||
- `rename`: replaced by native key; legacy alias can exist temporarily
|
||||
- `dev-only`: blocked in production builds; permitted in developer builds
|
||||
- `remove`: deleted from AC6 production path after milestone gate
|
||||
|
||||
## Key Migration Matrix
|
||||
|
||||
| Legacy key | Current meaning | Native replacement / behavior | Action | Enforcement milestone | User migration note | CI / linter rule |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| `vsync` | controls vertical sync pacing in emulation-era GPU path | `native.present.vsync` | rename | M4 | migrate to native present setting; same semantic intent | error on legacy key in production config after M4 |
|
||||
| `guest_vblank_sync_to_refresh` | keeps guest vblank cadence tied to guest refresh | `compat.timing.guest_vblank_sync_to_refresh` | dev-only | M2 | keep only for timing investigations | fail production build if enabled |
|
||||
| `swap_post_effect` | applies post effect at emulated swap stage (`none`, `fxaa`, `fxaa_extreme`) | `native.postfx.swap_effect` | rename | M4 | same options initially, later unified into post-FX stack config | warn on legacy key in M3, error in M4 |
|
||||
| `resolution` | emulation-era output resolution selector | `native.output.resolution` | rename | M4 | migrate value directly | auto-fix mapping in config migration tool |
|
||||
| `resolution_scale` | global emulation resolution scale | `native.render.scale` | rename | M3 | use native scale with subsystem routing support | error if both keys present |
|
||||
| `draw_resolution_scale_x` | emulation draw-scale X | `native.render.scale_x` | rename | M3 | migrate only if non-default | warning if legacy key present in M3+ |
|
||||
| `draw_resolution_scale_y` | emulation draw-scale Y | `native.render.scale_y` | rename | M3 | migrate only if non-default | warning if legacy key present in M3+ |
|
||||
| `draw_resolution_scaled_texture_offsets` | emulation compensation for scaled texture offsets | native render graph handles coordinate transforms explicitly | remove | M5 | no user replacement; behavior internalized | error if key present after M5 |
|
||||
| `resolve_resolution_scale_fill_half_pixel_offset` | half-pixel handling during emulated resolve scale fill | handled by native resolve pass shaders | remove | M5 | no replacement needed | error on key after M5 |
|
||||
| `readback_resolve` | CPU readback mode for render-to-texture resolve | `compat.readback.resolve_mode` (dev-only) | dev-only | M2 | use only during parity/debug bring-up | fail production build if not default |
|
||||
| `readback_resolve_half_pixel_offset` | resolve readback sampling offset tweak | `compat.readback.resolve_half_pixel_offset` (dev-only) | dev-only | M2 | debug-only parity aid | fail production build if enabled |
|
||||
| `readback_memexport` | CPU readback for shader memexport coherency | `compat.readback.memexport` (dev-only) | dev-only | M2 | needed only while legacy bridge remains | fail production build if enabled |
|
||||
| `readback_memexport_fast` | fast memexport readback mode | `compat.readback.memexport_fast` (dev-only) | dev-only | M2 | debug/perf experiment only | fail production build if enabled |
|
||||
| `vulkan_readback_resolve` | Vulkan legacy alias for readback resolve | none (legacy alias removed) | remove | M3 | migrate to shared compat key if needed in dev builds | reject key always in production |
|
||||
| `vulkan_readback_memexport` | Vulkan legacy alias for memexport readback | none (legacy alias removed) | remove | M3 | migrate to shared compat key if needed in dev builds | reject key always in production |
|
||||
| `d3d12_readback_resolve` | D3D12 legacy alias for readback resolve | none (legacy alias removed) | remove | M3 | migrate to shared compat key if needed in dev builds | reject key always in production |
|
||||
| `d3d12_readback_memexport` | D3D12 legacy alias for memexport readback | none (legacy alias removed) | remove | M3 | migrate to shared compat key if needed in dev builds | reject key always in production |
|
||||
| `async_shader_compilation` | async runtime shader/pipeline compilation in emulation path | `native.shader.runtime_async_compile` (dev-only fallback) | dev-only | M2 | native path uses offline compiled shaders; runtime path debug-only | fail production config if runtime compile enabled |
|
||||
| `dump_shaders` | dumps runtime translated shaders | `native.debug.dump_shaders` (dev-only) | dev-only | M2 | for migration diagnostics only | block in production config |
|
||||
| `dxbc_switch` | legacy DXBC translator switch | none | remove | M5 | no replacement; offline shader pipeline supersedes | error on key after M5 |
|
||||
| `dxbc_source_map` | legacy translator source map output | none | remove | M5 | no replacement; use offline reflection artifacts | error on key after M5 |
|
||||
| `vfetch_index_rounding_bias` | Xenos translator behavior knob | none | remove | M5 | no replacement on native path | error on key after M5 |
|
||||
| `texture_cache_memory_limit_render_to_texture` | emulated texture cache memory cap for RTT | `native.streaming.texture_budget_mb` | rename | M4 | migrate to native residency budget | warning when legacy key used |
|
||||
| `texture_cache_memory_limit_soft` | soft emulated texture cache limit | `native.streaming.texture_budget_soft_mb` | rename | M4 | migrate value with documented unit conversion | linter auto-fix if units are valid |
|
||||
| `texture_cache_memory_limit_hard` | hard emulated texture cache limit | `native.streaming.texture_budget_hard_mb` | rename | M4 | migrate value with documented unit conversion | linter auto-fix if units are valid |
|
||||
| `texture_cache_memory_limit_soft_lifetime` | cache residency lifetime heuristic | native streamer residency policy tables | remove | M5 | no user replacement | error on key after M5 |
|
||||
| `gpu_3d_to_2d_texture` | emulated texture workaround | `compat.texture.legacy_3d_to_2d` | dev-only | M3 | only for parity triage | fail production if enabled |
|
||||
| `gpu_allow_invalid_fetch_constants` | tolerate invalid fetch constants | `compat.validation.allow_invalid_fetch_constants` | dev-only | M2 | debug-only escape hatch | fail production if true |
|
||||
| `non_seamless_cube_map` | compatibility toggle for cube map sampling | `native.sampling.non_seamless_cube_map` | keep | M4 | kept as hardware compatibility option | ensure default distribution value documented |
|
||||
| `anisotropic_override` | forced anisotropic filtering level | `native.quality.anisotropy_override` | rename | M4 | migrate directly; same value range | validate range in config linter |
|
||||
| `occlusion_query_enable` | enable host occlusion query handling | `native.query.occlusion.enable` | rename | M4 | migrate directly | error if both old and new keys set |
|
||||
| `query_occlusion_fake_sample_count` | fake sample count for emulated queries | `compat.query.fake_sample_count` | dev-only | M3 | debugging only; not for production | fail production if non-default |
|
||||
| `depth_float24_round` | depth precision workaround | `compat.depth.float24_round` | dev-only | M3 | only use for parity troubleshooting | fail production if true |
|
||||
| `depth_float24_convert_in_pixel_shader` | depth conversion workaround | `compat.depth.float24_ps_convert` | dev-only | M3 | debug-only parity aid | fail production if true |
|
||||
| `depth_transfer_not_equal_test` | depth transfer compare workaround | `compat.depth.transfer_not_equal_test` | dev-only | M3 | debug-only parity aid | fail production if non-default |
|
||||
| `native_stencil_value_output` | stencil output behavior toggle | `native.depth_stencil.stencil_output` | keep | M4 | stays as backend compatibility toggle | validate supported backend combinations |
|
||||
| `native_stencil_value_output_d3d12_intel` | Intel-specific stencil behavior toggle | `native.depth_stencil.d3d12_intel_stencil_output` | keep | M4 | keep platform-specific escape hatch | limit to Windows+D3D12 in linter |
|
||||
| `gamma_render_target_as_unorm16` | gamma RT format behavior | `native.render_target.gamma_unorm16` | keep | M4 | retained as quality/compat setting | ensure default value parity-tested |
|
||||
| `native_2x_msaa` | native 2x MSAA toggle | `native.quality.msaa_2x` | rename | M4 | migrate directly | warn if legacy key used after M4 |
|
||||
| `snorm16_render_target_full_range` | emulated RT format behavior toggle | `compat.render_target.snorm16_full_range` | dev-only | M3 | parity bring-up only | fail production if enabled |
|
||||
| `mrt_edram_used_range_clamp_to_min` | EDRAM-era MRT behavior workaround | none | remove | M5 | no replacement in native render graph | error on key after M5 |
|
||||
| `direct_host_resolve` | direct host resolve path toggle | none (native resolve passes are authoritative) | remove | M5 | no replacement | error on key after M5 |
|
||||
| `execute_unclipped_draw_vs_on_cpu` | CPU fallback for draw processing | none | remove | M5 | no replacement on native path | error on key after M5 |
|
||||
| `execute_unclipped_draw_vs_on_cpu_for_psi_render_backend` | backend-specific CPU fallback | none | remove | M5 | no replacement on native path | error on key after M5 |
|
||||
| `execute_unclipped_draw_vs_on_cpu_with_scissor` | CPU fallback variant | none | remove | M5 | no replacement on native path | error on key after M5 |
|
||||
| `force_convert_line_loops_to_strips` | primitive conversion workaround | `compat.primitive.line_loop_to_strip` | dev-only | M3 | debug-only compatibility fallback | fail production if enabled |
|
||||
| `force_convert_quad_lists_to_triangle_lists` | primitive conversion workaround | `compat.primitive.quad_to_tri` | dev-only | M3 | debug-only compatibility fallback | fail production if enabled |
|
||||
| `force_convert_triangle_fans_to_lists` | primitive conversion workaround | `compat.primitive.fan_to_list` | dev-only | M3 | debug-only compatibility fallback | fail production if enabled |
|
||||
| `primitive_processor_cache_min_indices` | primitive cache threshold | `native.frontend.primitive_cache_min_indices` | rename | M4 | migrate directly after native frontend cutover | range-check in linter |
|
||||
| `trace_gpu_prefix` | trace output prefix for GPU traces | `native.debug.trace_prefix` (dev-only) | dev-only | M2 | diagnostics only | fail production if non-empty |
|
||||
| `trace_gpu_stream` | stream GPU trace continuously | `native.debug.trace_stream` (dev-only) | dev-only | M2 | diagnostics only | fail production if true |
|
||||
| `gpu_debug_markers` | GPU markers for tools like PIX/RenderDoc | `native.debug.gpu_markers` | keep | M4 | supported for dev and optionally production troubleshooting | allow but default off in release config |
|
||||
| `vulkan_sparse_shared_memory` | Vulkan shared-memory emulation mode | none | remove | M5 | no native replacement | error on key after M5 |
|
||||
| `vulkan_submit_on_primary_buffer_end` | Vulkan emulation submit timing behavior | `native.vulkan.submit_policy` | rename | M4 | migrate to native queue submit policy | warn then error after M4 |
|
||||
| `vulkan_dynamic_rendering` | Vulkan dynamic rendering toggle | `native.vulkan.dynamic_rendering` | keep | M4 | retained as backend capability switch | validate backend support |
|
||||
| `vulkan_async_skip_incomplete_frames` | Vulkan frame skip behavior | `native.vulkan.allow_incomplete_frame_skip` | rename | M4 | retain as backend tuning option | validate only on Vulkan backend |
|
||||
| `vulkan_pipeline_creation_threads` | Vulkan runtime pipeline thread count | `native.vulkan.pipeline_threads` | rename | M4 | used for native pipeline library management | range validation |
|
||||
| `vulkan_tessellation_wireframe` | Vulkan tessellation wireframe debug mode | `native.debug.vulkan.tess_wireframe` | dev-only | M2 | debug-only mode | fail production if true |
|
||||
| `vulkan_force_expand_point_sprites_in_vs` | Vulkan compatibility workaround | `compat.vulkan.expand_point_sprites_in_vs` | dev-only | M3 | parity fallback only | fail production if true |
|
||||
| `vulkan_force_expand_rectangle_lists_in_vs` | Vulkan compatibility workaround | `compat.vulkan.expand_rect_lists_in_vs` | dev-only | M3 | parity fallback only | fail production if true |
|
||||
| `vulkan_force_convert_quad_lists_to_triangle_lists` | Vulkan primitive conversion workaround | `compat.vulkan.quad_to_tri` | dev-only | M3 | parity fallback only | fail production if true |
|
||||
| `render_target_path_vulkan` | Vulkan render target debug dump path | `native.debug.vulkan.render_target_path` (dev-only) | dev-only | M2 | debug output only | fail production if non-empty |
|
||||
| `d3d12_bindless` | D3D12 bindless toggle | `native.d3d12.bindless` | keep | M4 | retained as backend feature flag | validate support on hardware tier |
|
||||
| `d3d12_submit_on_primary_buffer_end` | D3D12 emulation submit timing behavior | `native.d3d12.submit_policy` | rename | M4 | migrate to native queue submit policy | warn then error after M4 |
|
||||
| `d3d12_dxbc_disasm` | DXBC disassembly diagnostics | `native.debug.d3d12.dxbc_disasm` (dev-only) | dev-only | M2 | diagnostics only | fail production if true |
|
||||
| `d3d12_dxbc_disasm_dxilconv` | DXIL conversion disassembly diagnostics | `native.debug.d3d12.dxbc_disasm_dxilconv` (dev-only) | dev-only | M2 | diagnostics only | fail production if true |
|
||||
| `d3d12_pipeline_creation_threads` | D3D12 runtime pipeline thread count | `native.d3d12.pipeline_threads` | rename | M4 | migrate directly | range validation |
|
||||
| `d3d12_tessellation_wireframe` | D3D12 tessellation wireframe debug mode | `native.debug.d3d12.tess_wireframe` | dev-only | M2 | diagnostics only | fail production if true |
|
||||
| `d3d12_tiled_shared_memory` | D3D12 tiled shared-memory emulation toggle | none | remove | M5 | no replacement | error on key after M5 |
|
||||
| `render_target_path_d3d12` | D3D12 render target debug dump path | `native.debug.d3d12.render_target_path` (dev-only) | dev-only | M2 | diagnostics only | fail production if non-empty |
|
||||
|
||||
## Mechanical Migration Rules
|
||||
|
||||
1. Apply all `rename` mappings first.
|
||||
2. If both legacy and native key are present, native key wins and linter emits warning in `M2-M3`, error in `M4+`.
|
||||
3. `dev-only` keys:
|
||||
- allowed in local and CI debug/dev profiles
|
||||
- blocked in production distribution artifacts immediately at the listed milestone
|
||||
4. `remove` keys:
|
||||
- warning one milestone before removal
|
||||
- hard error at removal milestone and later
|
||||
|
||||
## Required Tooling
|
||||
|
||||
- Config migration script:
|
||||
- input: existing user/developer config
|
||||
- output: rewritten config with `rename` rules applied and deprecation report
|
||||
- Config linter modes:
|
||||
- `warn` mode for pre-enforcement milestones
|
||||
- `enforce` mode for release pipelines
|
||||
- CI checks:
|
||||
- fail if default shipping config contains `dev-only` or `remove` keys past enforcement milestone
|
||||
- fail if unknown graphics keys are present
|
||||
|
||||
## Open Items
|
||||
|
||||
- confirm final native key namespace before M3 freeze (`native.*` versus split subsystem namespaces)
|
||||
- define unit conversion policy for memory-budget key migrations where old/new units differ
|
||||
- attach examples for common user migration paths (`performance`, `debug`, `capture`) in README updates
|
||||
@@ -0,0 +1,71 @@
|
||||
# AC6 Native Graphics Render API Removal Map
|
||||
|
||||
Date: 2026-04-17
|
||||
Scope: AC6 render-path symbols, interfaces, and build linkage
|
||||
|
||||
Purpose: convert the migration strategy and audit into a concrete, file-referenced retirement map for legacy PM4/Xenos render interfaces.
|
||||
|
||||
Related docs:
|
||||
|
||||
- `AC6_NATIVE_GRAPHICS_EMULATION_AUDIT_2026-04-17.md`
|
||||
- `AC6_NATIVE_GRAPHICS_EXECUTION_PLAN_2026-04-17.md`
|
||||
- `AC6_NATIVE_GRAPHICS_API_DEPRECATION_TIMELINE.md`
|
||||
- `AC6_NATIVE_GRAPHICS_CONFIG_MIGRATION_MATRIX.md`
|
||||
|
||||
## Map Rules
|
||||
|
||||
- This map is AC6-scope only; non-graphics kernel compatibility exports may remain.
|
||||
- `M3` means hybrid migration and routing controls.
|
||||
- `M4` means native present authority.
|
||||
- `M5` means render linkage removal from AC6 targets.
|
||||
- Every `remove` entry must have a native replacement and validation artifact before deletion.
|
||||
|
||||
## Removal Matrix
|
||||
|
||||
| Legacy API / symbol / module | Current references (primary files) | Native replacement | Action | Target milestone | Compatibility-shim notes | Required validation artifact |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| `rex::graphics::GraphicsSystem` as render owner | `thirdparty/rexglue-sdk/include/rex/graphics/graphics_system.h`, `thirdparty/rexglue-sdk/src/graphics/graphics_system.cpp` | `ac6_native_renderer` ownership split across `RenderDevice`, `RenderGraph`, `FrameScheduler` | remove from AC6 render route | M5 | retain minimal interrupt/timing bridge only | boot + frame submission logs showing AC6 render no longer instantiates legacy graphics owner for production |
|
||||
| `rex::graphics::CommandProcessor` PM4 execution core | `thirdparty/rexglue-sdk/include/rex/graphics/command_processor.h`, `thirdparty/rexglue-sdk/src/graphics/command_processor.cpp` | native render graph compilation and submission from `Ac6RenderFrontend` | remove | M5 | no PM4 parsing in production route | link report proving `command_processor*` objects excluded from AC6 shipping target |
|
||||
| PM4 packet path including `PM4_XE_SWAP` | `thirdparty/rexglue-sdk/src/graphics/packet_disassembler.cpp`, `thirdparty/rexglue-sdk/src/graphics/command_processor.cpp` | native frame boundary and present path | remove | M5 | temporary parity hooks allowed pre-M5 only | CI check proving no production frame depends on PM4 swap synthesis |
|
||||
| `VdSwap_entry` PM4 swap synthesis behavior | `thirdparty/rexglue-sdk/src/kernel/xboxkrnl/xboxkrnl_video.cpp` | `VdSwap` as native frame boundary only | narrow then remove PM4 synthesis | M4->M5 | keep interrupt contract if required by title timing | contract doc + canary telemetry confirming native present authority |
|
||||
| D3D12 emulation command processor (`D3D12CommandProcessor`) | `thirdparty/rexglue-sdk/include/rex/graphics/d3d12/command_processor.h`, `thirdparty/rexglue-sdk/src/graphics/d3d12/command_processor.cpp` | `ac6_native_renderer/backends/d3d12_*` | remove from AC6 link | M5 | none for render; backend native module remains | object-link exclusion report for emulation D3D12 command processor |
|
||||
| Vulkan emulation command processor (`VulkanCommandProcessor`) | `thirdparty/rexglue-sdk/include/rex/graphics/vulkan/command_processor.h`, `thirdparty/rexglue-sdk/src/graphics/vulkan/command_processor.cpp` | `ac6_native_renderer/backends/vulkan_*` | remove from AC6 link | M5 | none for render; backend native module remains | object-link exclusion report for emulation Vulkan command processor |
|
||||
| Emulated shared-memory render model | `thirdparty/rexglue-sdk/src/graphics/shared_memory.cpp`, `thirdparty/rexglue-sdk/src/graphics/d3d12/shared_memory.cpp`, `thirdparty/rexglue-sdk/src/graphics/vulkan/shared_memory.cpp` | host-native resource allocator + transient/upload arenas | remove | M5 | none | memory validation showing native allocator path only |
|
||||
| Texture cache + untiling runtime conversion | `thirdparty/rexglue-sdk/src/graphics/pipeline/texture/cache.cpp`, `thirdparty/rexglue-sdk/src/graphics/pipeline/texture/conversion.cpp`, backend texture caches | cooked texture packages + streaming manager | remove | M5 | dynamic texture bridge allowed during M3-M4 only | parity and perf reports showing no hot-path guest untiling |
|
||||
| Render-target cache and EDRAM emulation | `thirdparty/rexglue-sdk/src/graphics/pipeline/render_target/cache.cpp`, backend render target caches | explicit native render graph attachments/history buffers | remove | M5 | none for production render route | pass graph captures showing native attachment ownership |
|
||||
| Runtime shader translation (`dxbc`/`spirv` translators) | `thirdparty/rexglue-sdk/src/graphics/pipeline/shader/translator.cpp`, `dxbc_translator*.cpp`, `spirv_translator*.cpp` | authored HLSL + offline DXIL/SPIR-V/MSL pipeline | remove | M5 | dev-only diagnostics may remain out of production path | CI shader manifest proving no runtime translation on native path |
|
||||
| Xenos register/render state ownership | `thirdparty/rexglue-sdk/src/graphics/registers.cpp`, `register_file.cpp`, `xenos.cpp` | native render/material descriptors | remove from render-authoritative path | M5 | limited compatibility reads may remain outside render | code-level ownership audit showing no render pass built from Xenos register file |
|
||||
| Emulation trace writer / PM4-centric diagnostics | `thirdparty/rexglue-sdk/src/graphics/trace_writer.cpp` and trace protocol stack | native capture + pass timeline dumps + backend markers | dev-only then remove from production | M6 | keep dev capture tooling if isolated from shipping path | production package scan with no PM4/Xenos trace dependencies |
|
||||
|
||||
## Keep And Adapt (Not Removed)
|
||||
|
||||
| Component | Primary files | Native migration disposition |
|
||||
| --- | --- | --- |
|
||||
| presenter / window / provider | `thirdparty/rexglue-sdk/src/native/ui/presenter.cpp`, `thirdparty/rexglue-sdk/src/native/ui/d3d12/d3d12_presenter.cpp`, provider and window modules | keep and adapt to consume native final-color output |
|
||||
| runtime graphics injection seam | `thirdparty/rexglue-sdk/src/native/ui/rex_app.cpp`, `thirdparty/rexglue-sdk/src/system/runtime.cpp`, `thirdparty/rexglue-sdk/include/rex/system/interfaces/graphics.h` | keep and expand for native renderer lifecycle, telemetry, and kill switches |
|
||||
| AC6-local migration bridge and diagnostics | `src/ac6_native_graphics.cpp`, `src/ac6_native_graphics_overlay.cpp`, `src/ac6_native_renderer/*` | keep during migration; progressively reduce legacy bridge responsibilities |
|
||||
|
||||
## Build/CI Retirement Checks
|
||||
|
||||
At minimum, AC6 Phase 5 completion must include:
|
||||
|
||||
1. link artifact proof that AC6 shipping target excludes:
|
||||
- `command_processor` objects
|
||||
- shader translator objects
|
||||
- shared-memory render resources
|
||||
- guest-state texture and render-target caches
|
||||
2. config linter enforcement from `AC6_NATIVE_GRAPHICS_CONFIG_MIGRATION_MATRIX.md` for removed/dev-only legacy keys
|
||||
3. parity, perf, and memory gates green on benchmark matrix after legacy linkage removal
|
||||
|
||||
## Sequencing Notes
|
||||
|
||||
- `M3`: route subsystems via native/legacy toggles while parity hardens
|
||||
- `M4`: transfer present authority; `VdSwap` reduced to boundary semantics
|
||||
- `M5`: remove legacy render linkage from AC6 production
|
||||
- `M6`: clean dead flags and PM4/Xenos-only diagnostic dependencies from production deliverables
|
||||
|
||||
## Open Items
|
||||
|
||||
- confirm final AC6 shipping target(s) that CI link-exclusion checks run against
|
||||
- add exact object/library names once build graph emits deterministic link manifests
|
||||
- tie each matrix row to issue IDs in the migration epic tracker
|
||||
+142
-1
@@ -1 +1,142 @@
|
||||
|
||||
#include "ac6_native_graphics.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <string_view>
|
||||
|
||||
#include <rex/cvar.h>
|
||||
#include <rex/logging.h>
|
||||
|
||||
#include "ac6_native_renderer/native_renderer.h"
|
||||
#include "d3d_hooks.h"
|
||||
|
||||
REXCVAR_DEFINE_BOOL(ac6_native_graphics_enabled, true, "AC6/NativeGraphics",
|
||||
"Enable AC6 native renderer frame-plan execution from captured D3D state");
|
||||
REXCVAR_DEFINE_BOOL(ac6_native_graphics_require_capture, true, "AC6/NativeGraphics",
|
||||
"Force render-capture on while native graphics execution is enabled");
|
||||
REXCVAR_DEFINE_STRING(ac6_native_graphics_backend, "auto", "AC6/NativeGraphics",
|
||||
"Preferred native backend: auto, d3d12, vulkan, metal")
|
||||
.allowed({"auto", "d3d12", "vulkan", "metal"});
|
||||
REXCVAR_DEFINE_STRING(ac6_native_graphics_feature_level, "scene_submission", "AC6/NativeGraphics",
|
||||
"Native renderer feature level: bootstrap, scene_submission, parity_validation, shipping")
|
||||
.allowed({"bootstrap", "scene_submission", "parity_validation", "shipping"});
|
||||
REXCVAR_DEFINE_INT32(ac6_native_graphics_frames_in_flight, 2, "AC6/NativeGraphics",
|
||||
"Native renderer max frames in flight")
|
||||
.range(1, 4);
|
||||
|
||||
namespace ac6::graphics {
|
||||
namespace {
|
||||
|
||||
std::mutex g_native_graphics_mutex;
|
||||
ac6::renderer::NativeRenderer g_native_renderer;
|
||||
NativeGraphicsRuntimeStatus g_runtime_status{};
|
||||
|
||||
ac6::renderer::BackendType ParseBackend(std::string_view value) {
|
||||
if (value == "d3d12") {
|
||||
return ac6::renderer::BackendType::kD3D12;
|
||||
}
|
||||
if (value == "vulkan") {
|
||||
return ac6::renderer::BackendType::kVulkan;
|
||||
}
|
||||
if (value == "metal") {
|
||||
return ac6::renderer::BackendType::kMetal;
|
||||
}
|
||||
return ac6::renderer::BackendType::kUnknown;
|
||||
}
|
||||
|
||||
ac6::renderer::FeatureLevel ParseFeatureLevel(std::string_view value) {
|
||||
if (value == "bootstrap") {
|
||||
return ac6::renderer::FeatureLevel::kBootstrap;
|
||||
}
|
||||
if (value == "parity_validation") {
|
||||
return ac6::renderer::FeatureLevel::kParityValidation;
|
||||
}
|
||||
if (value == "shipping") {
|
||||
return ac6::renderer::FeatureLevel::kShipping;
|
||||
}
|
||||
return ac6::renderer::FeatureLevel::kSceneSubmission;
|
||||
}
|
||||
|
||||
ac6::renderer::NativeRendererConfig BuildRendererConfig() {
|
||||
ac6::renderer::NativeRendererConfig config;
|
||||
config.preferred_backend = ParseBackend(REXCVAR_GET(ac6_native_graphics_backend));
|
||||
config.feature_level = ParseFeatureLevel(REXCVAR_GET(ac6_native_graphics_feature_level));
|
||||
config.max_frames_in_flight = static_cast<uint32_t>(REXCVAR_GET(ac6_native_graphics_frames_in_flight));
|
||||
config.enable_debug_markers = true;
|
||||
config.enable_validation = true;
|
||||
return config;
|
||||
}
|
||||
|
||||
bool EnsureInitialized() {
|
||||
if (g_runtime_status.initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
++g_runtime_status.init_attempts;
|
||||
const ac6::renderer::NativeRendererConfig config = BuildRendererConfig();
|
||||
if (!g_native_renderer.Initialize(config)) {
|
||||
g_runtime_status.had_init_failure = true;
|
||||
REXLOG_ERROR("AC6 native graphics failed to initialize backend={}",
|
||||
ac6::renderer::ToString(ac6::renderer::ResolveBackend(config.preferred_backend)));
|
||||
return false;
|
||||
}
|
||||
|
||||
g_runtime_status.initialized = true;
|
||||
g_runtime_status.had_init_failure = false;
|
||||
++g_runtime_status.init_successes;
|
||||
g_runtime_status.feature_level = config.feature_level;
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateStatusFromRendererUnlocked() {
|
||||
g_runtime_status.renderer_stats = g_native_renderer.GetStats();
|
||||
g_runtime_status.active_backend = g_runtime_status.renderer_stats.active_backend;
|
||||
g_runtime_status.frame_plan = g_native_renderer.frame_plan();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void OnFrameBoundary() {
|
||||
std::scoped_lock<std::mutex> lock(g_native_graphics_mutex);
|
||||
|
||||
g_runtime_status.enabled = REXCVAR_GET(ac6_native_graphics_enabled);
|
||||
if (!g_runtime_status.enabled) {
|
||||
if (g_runtime_status.initialized) {
|
||||
g_native_renderer.Shutdown();
|
||||
g_runtime_status.initialized = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (REXCVAR_GET(ac6_native_graphics_require_capture) && !REXCVAR_GET(ac6_render_capture)) {
|
||||
REXCVAR_SET(ac6_render_capture, true);
|
||||
}
|
||||
|
||||
if (!EnsureInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ac6::d3d::FrameCaptureSnapshot frame_capture = ac6::d3d::GetFrameCapture();
|
||||
g_runtime_status.capture_summary = ac6::d3d::GetFrameCaptureSummary();
|
||||
|
||||
g_native_renderer.BeginFrame();
|
||||
g_native_renderer.BuildCapturedFrame(frame_capture);
|
||||
++g_runtime_status.frames_built;
|
||||
UpdateStatusFromRendererUnlocked();
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
std::scoped_lock<std::mutex> lock(g_native_graphics_mutex);
|
||||
if (!g_runtime_status.initialized) {
|
||||
return;
|
||||
}
|
||||
g_native_renderer.Shutdown();
|
||||
g_runtime_status.initialized = false;
|
||||
}
|
||||
|
||||
NativeGraphicsRuntimeStatus GetRuntimeStatus() {
|
||||
std::scoped_lock<std::mutex> lock(g_native_graphics_mutex);
|
||||
return g_runtime_status;
|
||||
}
|
||||
|
||||
} // namespace ac6::graphics
|
||||
|
||||
|
||||
@@ -1 +1,32 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "ac6_native_renderer/frame_plan.h"
|
||||
#include "ac6_native_renderer/types.h"
|
||||
#include "d3d_state.h"
|
||||
|
||||
namespace ac6::graphics {
|
||||
|
||||
struct NativeGraphicsRuntimeStatus {
|
||||
bool enabled = false;
|
||||
bool initialized = false;
|
||||
bool had_init_failure = false;
|
||||
uint64_t init_attempts = 0;
|
||||
uint64_t init_successes = 0;
|
||||
uint64_t frames_built = 0;
|
||||
|
||||
ac6::renderer::BackendType active_backend = ac6::renderer::BackendType::kUnknown;
|
||||
ac6::renderer::FeatureLevel feature_level = ac6::renderer::FeatureLevel::kBootstrap;
|
||||
ac6::renderer::NativeRendererStats renderer_stats{};
|
||||
ac6::d3d::FrameCaptureSummary capture_summary{};
|
||||
ac6::renderer::NativeFramePlan frame_plan{};
|
||||
};
|
||||
|
||||
void OnFrameBoundary();
|
||||
void Shutdown();
|
||||
|
||||
NativeGraphicsRuntimeStatus GetRuntimeStatus();
|
||||
|
||||
} // namespace ac6::graphics
|
||||
|
||||
|
||||
@@ -1 +1,57 @@
|
||||
|
||||
#include "ac6_native_graphics_overlay.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "ac6_native_graphics.h"
|
||||
|
||||
namespace ac6::graphics {
|
||||
|
||||
NativeGraphicsStatusDialog::NativeGraphicsStatusDialog(rex::ui::ImGuiDrawer* imgui_drawer)
|
||||
: ImGuiDialog(imgui_drawer) {}
|
||||
|
||||
NativeGraphicsStatusDialog::~NativeGraphicsStatusDialog() = default;
|
||||
|
||||
void NativeGraphicsStatusDialog::OnDraw(ImGuiIO& io) {
|
||||
(void)io;
|
||||
if (!visible_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ImGui::Begin("AC6 Native Graphics##status", &visible_, ImGuiWindowFlags_NoCollapse)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
const NativeGraphicsRuntimeStatus status = GetRuntimeStatus();
|
||||
ImGui::Text("enabled: %s", status.enabled ? "true" : "false");
|
||||
ImGui::Text("initialized: %s", status.initialized ? "true" : "false");
|
||||
ImGui::Text("init failures seen: %s", status.had_init_failure ? "true" : "false");
|
||||
ImGui::Text("init attempts/successes: %llu / %llu",
|
||||
static_cast<unsigned long long>(status.init_attempts),
|
||||
static_cast<unsigned long long>(status.init_successes));
|
||||
ImGui::Text("frames built: %llu", static_cast<unsigned long long>(status.frames_built));
|
||||
ImGui::Separator();
|
||||
ImGui::Text("backend: %s", ac6::renderer::ToString(status.active_backend).data());
|
||||
ImGui::Text("feature level: %s", ac6::renderer::ToString(status.feature_level).data());
|
||||
ImGui::Text("renderer frames: %llu",
|
||||
static_cast<unsigned long long>(status.renderer_stats.frame_count));
|
||||
ImGui::Text("render passes built: %llu",
|
||||
static_cast<unsigned long long>(status.renderer_stats.built_pass_count));
|
||||
ImGui::Separator();
|
||||
ImGui::Text("capture frame: %llu",
|
||||
static_cast<unsigned long long>(status.capture_summary.frame_index));
|
||||
ImGui::Text("capture draws/clears/resolves: %u / %u / %u",
|
||||
status.capture_summary.draw_count, status.capture_summary.clear_count,
|
||||
status.capture_summary.resolve_count);
|
||||
ImGui::Text("planned output: %ux%u", status.frame_plan.output_width,
|
||||
status.frame_plan.output_height);
|
||||
ImGui::Text("stages scene/post/ui: %s / %s / %s",
|
||||
status.frame_plan.has_scene_stage ? "yes" : "no",
|
||||
status.frame_plan.has_post_process_stage ? "yes" : "no",
|
||||
status.frame_plan.has_ui_stage ? "yes" : "no");
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} // namespace ac6::graphics
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ class NativeGraphicsStatusDialog final : public rex::ui::ImGuiDialog {
|
||||
explicit NativeGraphicsStatusDialog(rex::ui::ImGuiDrawer* imgui_drawer);
|
||||
~NativeGraphicsStatusDialog();
|
||||
|
||||
void Show() { visible_ = true; }
|
||||
void ToggleVisible() { visible_ = !visible_; }
|
||||
bool IsVisible() const { return visible_; }
|
||||
|
||||
|
||||
+30
-1
@@ -1 +1,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <rex/rex_app.h>
|
||||
|
||||
#include "ac6_native_graphics_overlay.h"
|
||||
#include "generated/ac6recomp_config.h"
|
||||
|
||||
class Ac6recompApp : public rex::ReXApp {
|
||||
public:
|
||||
using rex::ReXApp::ReXApp;
|
||||
|
||||
static std::unique_ptr<rex::ui::WindowedApp> Create(
|
||||
rex::ui::WindowedAppContext& ctx) {
|
||||
return std::unique_ptr<Ac6recompApp>(new Ac6recompApp(ctx, "ac6recomp", PPCImageConfig));
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) override {
|
||||
rex::ReXApp::OnCreateDialogs(drawer);
|
||||
native_graphics_status_dialog_ =
|
||||
std::make_unique<ac6::graphics::NativeGraphicsStatusDialog>(drawer);
|
||||
native_graphics_status_dialog_->Show();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<ac6::graphics::NativeGraphicsStatusDialog> native_graphics_status_dialog_;
|
||||
};
|
||||
|
||||
|
||||
+19
-1
@@ -1 +1,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <rex/cvar.h>
|
||||
|
||||
#include "d3d_state.h"
|
||||
|
||||
REXCVAR_DECLARE(bool, ac6_render_capture);
|
||||
|
||||
namespace ac6::d3d {
|
||||
|
||||
void OnFrameBoundary();
|
||||
|
||||
DrawStatsSnapshot GetDrawStats();
|
||||
FrameCaptureSnapshot GetFrameCapture();
|
||||
FrameCaptureSummary GetFrameCaptureSummary();
|
||||
ShadowState GetShadowState();
|
||||
|
||||
} // namespace ac6::d3d
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "render_hooks.h"
|
||||
#include "d3d_hooks.h"
|
||||
#include "ac6_native_graphics.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
@@ -47,6 +48,7 @@ void ac6DeltaDivisorHook(PPCRegister& r29) {
|
||||
|
||||
void ac6PresentTimingHook(PPCRegister& /*r31*/) {
|
||||
ac6::d3d::OnFrameBoundary();
|
||||
ac6::graphics::OnFrameBoundary();
|
||||
|
||||
const auto now = Clock::now();
|
||||
double frame_time_ms = 0.0;
|
||||
|
||||
Reference in New Issue
Block a user