mirror of
https://github.com/jessicanataliagta/PSPRecomp
synced 2026-10-06 03:13:40 -04:00
improving graphics
improving graphics
This commit is contained in:
@@ -50,3 +50,4 @@ SAVEDATA/
|
||||
# Python
|
||||
__pycache__/
|
||||
*.pyc
|
||||
/profiles/vcs/host/propershaders/private
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
setlocal
|
||||
cd /d "%~dp0"
|
||||
echo Cleaning obsolete shader files moved into profiles\vcs\host\propershaders\private...
|
||||
if exist "profiles\\vcs\\host\\ge_cloudworks_present_shader.hpp" del /f /q "profiles\\vcs\\host\\ge_cloudworks_present_shader.hpp"
|
||||
if exist "profiles\\vcs\\host\\ge_gpu_hdr_shaders.inc" del /f /q "profiles\\vcs\\host\\ge_gpu_hdr_shaders.inc"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\LICENSE_SIMULATEHDR.txt" del /f /q "profiles\\vcs\\shaders\\hdr\\LICENSE_SIMULATEHDR.txt"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_blur.frag" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_blur.frag"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_blur.frag.spv" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_blur.frag.spv"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_combine.frag" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_combine.frag"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_combine.frag.spv" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_combine.frag.spv"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_composite.frag" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_composite.frag"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_composite.frag.spv" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_composite.frag.spv"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_extract.frag" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_extract.frag"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_extract.frag.spv" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_extract.frag.spv"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_fullscreen.vert" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_fullscreen.vert"
|
||||
if exist "profiles\\vcs\\shaders\\hdr\\hdr_fullscreen.vert.spv" del /f /q "profiles\\vcs\\shaders\\hdr\\hdr_fullscreen.vert.spv"
|
||||
echo Cleanup complete.
|
||||
endlocal
|
||||
@@ -189,6 +189,41 @@ endif()
|
||||
|
||||
set(VCS_GPU_BACKEND_SOURCE host/ge_gpu_backend_dx12.cpp)
|
||||
set(VCS_HDR_POST_SOURCE host/vcs_hdr_post_dx12_stub.cpp)
|
||||
|
||||
# ProperShaders is an optional private extension layer. The public repository can
|
||||
# omit host/propershaders/private entirely and still build a stock VCS renderer.
|
||||
set(VCS_PROPER_SHADERS_SOURCES
|
||||
host/propershaders/ProperShadersConfig.cpp
|
||||
host/propershaders/ProperShadersBridge.cpp
|
||||
)
|
||||
set(VCS_PRIVATE_SHADER_DIR "${VCS_PROFILE_DIR}/host/propershaders/private")
|
||||
set(VCS_PRIVATE_SHADER_REQUIRED
|
||||
"${VCS_PRIVATE_SHADER_DIR}/PipeSources.hpp"
|
||||
"${VCS_PRIVATE_SHADER_DIR}/PrivateShaders.cpp"
|
||||
"${VCS_PRIVATE_SHADER_DIR}/BuildingPipe.cpp"
|
||||
"${VCS_PRIVATE_SHADER_DIR}/SkinPipe.cpp"
|
||||
"${VCS_PRIVATE_SHADER_DIR}/VehiclePipe.cpp"
|
||||
"${VCS_PRIVATE_SHADER_DIR}/RealtimeShadows.cpp"
|
||||
"${VCS_PRIVATE_SHADER_DIR}/VolumetricClouds.cpp")
|
||||
set(VCS_PRIVATE_SHADER_COMPLETE TRUE)
|
||||
foreach(VCS_PRIVATE_SHADER_FILE IN LISTS VCS_PRIVATE_SHADER_REQUIRED)
|
||||
if(NOT EXISTS "${VCS_PRIVATE_SHADER_FILE}")
|
||||
set(VCS_PRIVATE_SHADER_COMPLETE FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
if(VCS_PRIVATE_SHADER_COMPLETE)
|
||||
message(STATUS "VCS ProperShaders: private shader pack present")
|
||||
list(APPEND VCS_PROPER_SHADERS_SOURCES
|
||||
host/propershaders/private/PrivateShaders.cpp
|
||||
host/propershaders/private/BuildingPipe.cpp
|
||||
host/propershaders/private/SkinPipe.cpp
|
||||
host/propershaders/private/VehiclePipe.cpp
|
||||
host/propershaders/private/RealtimeShadows.cpp
|
||||
host/propershaders/private/VolumetricClouds.cpp)
|
||||
else()
|
||||
message(STATUS "VCS ProperShaders: private shader pack absent; building stock-renderer stubs")
|
||||
list(APPEND VCS_PROPER_SHADERS_SOURCES host/propershaders/PrivateShaderStubs.cpp)
|
||||
endif()
|
||||
set(VCS_HOST_SOURCES
|
||||
host/vcs_tier2_superblocks.cpp
|
||||
host/vcs_bootstrap_paths.cpp
|
||||
@@ -210,6 +245,7 @@ set(VCS_HOST_SOURCES
|
||||
host/vcs_project2dfx_lights.cpp
|
||||
host/vcs_draw_distance_patch.cpp
|
||||
host/vcs_runtime_log.cpp
|
||||
${VCS_PROPER_SHADERS_SOURCES}
|
||||
${VCS_HDR_POST_SOURCE}
|
||||
host/ge_renderer.cpp
|
||||
${VCS_GPU_BACKEND_SOURCE}
|
||||
@@ -337,6 +373,7 @@ if(PSPRECOMP_BUILD_PROFILE_TESTS)
|
||||
add_executable(vcs_config_tests
|
||||
tests/vcs_config_tests.cpp
|
||||
host/vcs_config.cpp
|
||||
host/propershaders/ProperShadersConfig.cpp
|
||||
host/vcs_camera_input.cpp
|
||||
host/vcs_vehicle_input.cpp)
|
||||
target_include_directories(vcs_config_tests PRIVATE host)
|
||||
@@ -374,6 +411,7 @@ if(WIN32)
|
||||
host/dx12_presenter.cpp
|
||||
host/vcs_runtime_log.cpp
|
||||
host/vcs_config.cpp
|
||||
host/propershaders/ProperShadersConfig.cpp
|
||||
host/vcs_camera_input.cpp
|
||||
host/vcs_vehicle_input.cpp)
|
||||
target_include_directories(vcs_dx12_probe PRIVATE host "${PROJECT_SOURCE_DIR}/include")
|
||||
@@ -385,6 +423,7 @@ if(WIN32)
|
||||
host/ge_gpu_backend_dx12.cpp
|
||||
host/vcs_runtime_log.cpp
|
||||
host/vcs_config.cpp
|
||||
${VCS_PROPER_SHADERS_SOURCES}
|
||||
host/vcs_camera_input.cpp
|
||||
host/vcs_vehicle_input.cpp)
|
||||
target_include_directories(vcs_dx12_ge_probe PRIVATE host "${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
@@ -15,7 +15,7 @@ if not exist "%BUILD%" (
|
||||
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"$build=[IO.Path]::GetFullPath('%BUILD%');" ^
|
||||
"$names=@('vcs_profile.cpp.obj','savedata_utility_ui.cpp.obj','ge_renderer.cpp.obj','display_window.cpp.obj','main.cpp.obj','vcs_config.cpp.obj','generated_unit_0127.cpp.obj','generated_unit_0172.cpp.obj');" ^
|
||||
"$found=Get-ChildItem -LiteralPath $build -Recurse -File -Filter '*.obj' -ErrorAction SilentlyContinue ^| Where-Object { $names -contains $_.Name };" ^
|
||||
"$found=@(Get-ChildItem -LiteralPath $build -Recurse -File -Filter '*.obj' -ErrorAction SilentlyContinue); $found=@($found.Where({$names -contains $_.Name}));" ^
|
||||
"Write-Host ('[V9.3] stale objects found: ' + $found.Count);" ^
|
||||
"foreach($f in $found){Write-Host (' deleting: ' + $f.FullName); Remove-Item -LiteralPath $f.FullName -Force -ErrorAction Stop};" ^
|
||||
"$src=@('%REPO%\profiles\vcs\host\vcs_profile.cpp','%REPO%\profiles\vcs\host\savedata_utility_ui.cpp','%REPO%\profiles\vcs\host\ge_renderer.cpp','%REPO%\profiles\vcs\host\display_window.cpp','%REPO%\profiles\vcs\host\main.cpp','%REPO%\profiles\vcs\host\vcs_config.cpp','%REPO%\profiles\vcs\generated\generated_unit_0127.cpp','%REPO%\profiles\vcs\generated\generated_unit_0172.cpp');" ^
|
||||
|
||||
@@ -15,7 +15,7 @@ if not exist "%BUILD%" (
|
||||
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"$build=[IO.Path]::GetFullPath('%BUILD%');" ^
|
||||
"$names=@('vcs_profile.cpp.obj','savedata_utility_ui.cpp.obj');" ^
|
||||
"$found=Get-ChildItem -LiteralPath $build -Recurse -File -Filter '*.obj' -ErrorAction SilentlyContinue ^| Where-Object { $names -contains $_.Name };" ^
|
||||
"$found=@(Get-ChildItem -LiteralPath $build -Recurse -File -Filter '*.obj' -ErrorAction SilentlyContinue); $found=@($found.Where({$names -contains $_.Name}));" ^
|
||||
"Write-Host ('[V9.4] stale objects found: ' + $found.Count);" ^
|
||||
"foreach($f in $found){Write-Host (' deleting: ' + $f.FullName); Remove-Item -LiteralPath $f.FullName -Force -ErrorAction Stop};" ^
|
||||
"$src=@('%REPO%\profiles\vcs\host\vcs_profile.cpp','%REPO%\profiles\vcs\host\savedata_utility_ui.cpp');" ^
|
||||
|
||||
@@ -15,7 +15,7 @@ if not exist "%BUILD%" (
|
||||
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"$build=[IO.Path]::GetFullPath('%BUILD%');" ^
|
||||
"$names=@('ge_gpu_backend_dx12.cpp.obj','savedata_utility_ui.cpp.obj');" ^
|
||||
"$found=Get-ChildItem -LiteralPath $build -Recurse -File -Filter '*.obj' -ErrorAction SilentlyContinue ^| Where-Object { $names -contains $_.Name };" ^
|
||||
"$found=@(Get-ChildItem -LiteralPath $build -Recurse -File -Filter '*.obj' -ErrorAction SilentlyContinue); $found=@($found.Where({$names -contains $_.Name}));" ^
|
||||
"Write-Host ('[V9.5] stale objects found: ' + $found.Count);" ^
|
||||
"foreach($f in $found){Write-Host (' deleting: ' + $f.FullName); Remove-Item -LiteralPath $f.FullName -Force -ErrorAction Stop};" ^
|
||||
"$src=@('%REPO%\profiles\vcs\host\ge_gpu_backend_dx12.cpp','%REPO%\profiles\vcs\host\savedata_utility_ui.cpp');" ^
|
||||
|
||||
@@ -15,7 +15,7 @@ if not exist "%BUILD%" (
|
||||
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"$build=[IO.Path]::GetFullPath('%BUILD%');" ^
|
||||
"$names=@('vcs_profile.cpp.obj');" ^
|
||||
"$found=Get-ChildItem -LiteralPath $build -Recurse -File -Filter '*.obj' -ErrorAction SilentlyContinue ^| Where-Object { $names -contains $_.Name };" ^
|
||||
"$found=@(Get-ChildItem -LiteralPath $build -Recurse -File -Filter '*.obj' -ErrorAction SilentlyContinue); $found=@($found.Where({$names -contains $_.Name}));" ^
|
||||
"Write-Host ('[V9.6] stale objects found: ' + $found.Count);" ^
|
||||
"foreach($f in $found){Write-Host (' deleting: ' + $f.FullName); Remove-Item -LiteralPath $f.FullName -Force -ErrorAction Stop};" ^
|
||||
"$src='%REPO%\profiles\vcs\host\vcs_profile.cpp';" ^
|
||||
|
||||
@@ -5,7 +5,9 @@ The VCS profile includes components that are distributed under licenses separate
|
||||
- FFmpeg runtime libraries and import libraries: LGPL 2.1 or later. The bundled notice is `third_party/ffmpeg/COPYING.LGPLv2.1`.
|
||||
- SMAA shader resources: see `third_party/smaa/LICENSE.txt`.
|
||||
- Project2DFX-derived VCS LOD-light data/behavior reference by ThirteenAG: MIT. See `third_party/project2dfx/LICENSE.txt` and `third_party/project2dfx/ATTRIBUTION.md`.
|
||||
- HDR shader material under `shaders/hdr`: see `shaders/hdr/LICENSE_SIMULATEHDR.txt`.
|
||||
- Optional/private HDR shader material, when that local pack is present, lives
|
||||
under `host/propershaders/private/legacy/hdr`; its license is kept beside it
|
||||
as `LICENSE_SIMULATEHDR.txt`.
|
||||
- CloudWorks Alpha 4.0 volumetric-cloud density/noise model by Brian Tu (RTU):
|
||||
CC BY-NC-SA 3.0. See `third_party/cloudworks/ATTRIBUTION.md`.
|
||||
|
||||
|
||||
@@ -1,7 +1,79 @@
|
||||
; CloudWorks/ProperShaders port for VCSNative. Set Enabled=false to restore the
|
||||
; unmodified game sky. Parameters marked PLACEHOLDER are the exact inputs that
|
||||
; ProperShaders obtains from San Andreas timecycle/weather; they stay fixed here
|
||||
; until their VCS guest-side sources are connected.
|
||||
; VCSNative optional shader extension layer.
|
||||
;
|
||||
; The host renderer and the stock game do NOT depend on the private shader pack.
|
||||
; If profiles/vcs/host/propershaders/private is absent when CMake configures the
|
||||
; project, VCSNative builds the public stubs and renders the original game.
|
||||
;
|
||||
; Keep all optional/custom shader configuration in this file. VCSNative.ini is
|
||||
; reserved for the core renderer/runtime.
|
||||
|
||||
[ProperShaders]
|
||||
Enabled=true
|
||||
|
||||
; Dedicated material pipes. Each pipe has its own private .cpp implementation.
|
||||
; WorldPipe (the Building pipe internally) receives ordinary world/building/object geometry.
|
||||
[WorldPipe]
|
||||
Enabled=true
|
||||
DebugColor=false
|
||||
DebugR=0.05
|
||||
DebugG=1.00
|
||||
DebugB=0.05
|
||||
|
||||
; SkinPipe is selected from the actual PSP GE skin-weight vertex layout.
|
||||
[SkinPipe]
|
||||
Enabled=true
|
||||
DebugColor=false
|
||||
DebugR=1.00
|
||||
DebugG=0.05
|
||||
DebugB=1.00
|
||||
|
||||
; VehiclePipe learns recolourable VCS vehicle materials from CLUT mutations.
|
||||
[VehiclePipe]
|
||||
Enabled=true
|
||||
PaletteClassifier=true
|
||||
DebugColor=false
|
||||
DebugR=0.05
|
||||
DebugG=0.55
|
||||
DebugB=1.00
|
||||
|
||||
; Modern DX12 directional shadow map with PCF, sampled directly by each
|
||||
; World/Skin/Vehicle material shader. The old fullscreen contact composite is not used.
|
||||
[RealtimeShadows]
|
||||
; The directional map is now sampled by the actual World/Skin/Vehicle material
|
||||
; shaders. There is no fullscreen/contact-shadow composite in this path.
|
||||
Enabled=true
|
||||
; Stable camera-centred directional shadow map. 2048 is the default quality.
|
||||
MapResolution=2048
|
||||
WorldRadius=140.0
|
||||
DepthRange=420.0
|
||||
MapBias=0.0015
|
||||
PcfRadius=1
|
||||
; Keep shadows and CloudWorks driven by the same sun direction by default.
|
||||
UseCloudSunDirection=true
|
||||
LightDirectionX=0.38
|
||||
LightDirectionY=-0.28
|
||||
LightDirectionZ=0.88
|
||||
Strength=0.58
|
||||
; Shadow debug views (restart required because material variants are compiled at startup):
|
||||
; 0 = normal lighting/shadows
|
||||
; 1 = raw directional shadow map fullscreen (caster/depth proof)
|
||||
; 2 = receiver shadow mask: white=shadow, black=lit
|
||||
; 3 = light projection/coverage: RG=shadow UV, blue=inside map, red=outside
|
||||
; 4 = sampled shadow-map depth on receivers (grayscale)
|
||||
; 5 = receiver depth in light space (grayscale)
|
||||
; 6 = compare result: red=blocked, green=lit
|
||||
DebugMode=0
|
||||
; Legacy contact-shadow setting retained for config compatibility; unused by the material path.
|
||||
ContactShadows=false
|
||||
ContactStrength=0.22
|
||||
Steps=12
|
||||
MaxDistancePixels=28.0
|
||||
Thickness=0.0025
|
||||
LightScreenX=-0.55
|
||||
LightScreenY=0.75
|
||||
|
||||
; CloudWorks/ProperShaders volumetric-cloud port. It now lives in the same
|
||||
; optional private shader module instead of the core GE backend.
|
||||
[VolumetricClouds]
|
||||
Enabled=true
|
||||
DownscaleDiv=2
|
||||
@@ -37,7 +109,12 @@ FogColorG=0.68
|
||||
FogColorB=0.78
|
||||
FogStart=4500.0
|
||||
|
||||
; ProperShaders temporal resolve controls.
|
||||
; Temporal resolve controls.
|
||||
TemporalBlend=0.50
|
||||
TemporalDenoise=1.0
|
||||
TemporalClamp=1.0
|
||||
|
||||
; Reserved for the old SimulateHDR port. Its DX12 implementation is currently
|
||||
; disabled, but its settings live here rather than VCSNative.ini.
|
||||
[SimulateHDR]
|
||||
Enabled=false
|
||||
|
||||
@@ -67,17 +67,13 @@ AspectRatio=auto
|
||||
Enabled=false
|
||||
PerformanceLog=false
|
||||
|
||||
[SimulateHDR]
|
||||
Enabled=false
|
||||
|
||||
[DrawDistance]
|
||||
; Correctness 0.1: implementation is complete but remains opt-in so normal
|
||||
; gameplay/performance can be compared directly against the clean GitHub baseline.
|
||||
; Change only Enabled=true to test the prefilled 1.50x extension.
|
||||
Enabled=false
|
||||
World=1.50
|
||||
Vehicles=1.50
|
||||
NPCs=1.50
|
||||
; 1.0 = original PSP distance. Objects affects world model-info + far clip;
|
||||
; Vehicles/NPCs patch the exact generated guest culling constants as well.
|
||||
Enabled=true
|
||||
Objects=2.00
|
||||
Vehicles=2.00
|
||||
NPCs=2.00
|
||||
|
||||
[Frontend]
|
||||
; V9 load-only startup: the removed BootToGameMenu path can no longer be
|
||||
|
||||
@@ -8769,6 +8769,7 @@ L_089CB33C:
|
||||
}
|
||||
L_089CB38C:
|
||||
if (vcs::g_draw_distance_runtime_scales.npcs > 1.0f) {
|
||||
++vcs::g_draw_distance_runtime_telemetry.npc_constant_hits;
|
||||
const float dd_scale = vcs::g_draw_distance_runtime_scales.npcs;
|
||||
ctx.gpr[19] = ctx.gpr[29] + static_cast<std::uint32_t>(64);
|
||||
ctx.gpr[30] = ctx.gpr[29] + static_cast<std::uint32_t>(16);
|
||||
|
||||
@@ -139,7 +139,7 @@ static const std::uint16_t kEntryIds_recomp_unit_0133[4093] = {
|
||||
};
|
||||
void recomp_unit_0133_entry(Runtime &rt, AllegrexContext &ctx, std::uint16_t direct_entry_id, GuestMemory::AotFastView &aot_mem) {
|
||||
// PSPRECOMP_AOT_REGCACHE_BEGIN
|
||||
// PSPRECOMP_AOT_REGCACHE_META gprs=4,29,5,31,16,6 fprs=12,13,14,15 gpr_occ=3817 fpr_occ=847 gpr_total=5332 fpr_total=1295
|
||||
// PSPRECOMP_AOT_REGCACHE_META gprs=4,29,5,31,16,6 fprs=12,13,14,15 gpr_occ=3817 fpr_occ=848 gpr_total=5332 fpr_total=1296
|
||||
std::uint32_t aot_gpr_4 = ctx.gpr[4];
|
||||
std::uint32_t aot_gpr_29 = ctx.gpr[29];
|
||||
std::uint32_t aot_gpr_5 = ctx.gpr[5];
|
||||
@@ -6514,6 +6514,10 @@ L_08A1AD64:
|
||||
ctx.pc = jump_target;
|
||||
AOT_REGCACHE_SYNC_OUT(); return;
|
||||
L_08A1AD6C:
|
||||
if (vcs::g_draw_distance_runtime_scales.world > 1.0f) {
|
||||
++vcs::g_draw_distance_runtime_telemetry.far_clip_set_hits;
|
||||
aot_fpr_12 *= vcs::g_draw_distance_runtime_scales.world;
|
||||
}
|
||||
jump_target = aot_gpr_31;
|
||||
aot_mem.aot_direct_store32(ctx.gpr[28] + static_cast<std::uint32_t>(7796), std::bit_cast<std::uint32_t>(aot_fpr_12));
|
||||
local_pc = jump_target;
|
||||
|
||||
@@ -139,7 +139,7 @@ static const std::uint16_t kEntryIds_recomp_unit_0136[4092] = {
|
||||
};
|
||||
void recomp_unit_0136_entry(Runtime &rt, AllegrexContext &ctx, std::uint16_t direct_entry_id, GuestMemory::AotFastView &aot_mem) {
|
||||
// PSPRECOMP_AOT_REGCACHE_BEGIN
|
||||
// PSPRECOMP_AOT_REGCACHE_META gprs=4,29,31,16,17,18 fprs=12,20,22,24 gpr_occ=3036 fpr_occ=858 gpr_total=4359 fpr_total=1266
|
||||
// PSPRECOMP_AOT_REGCACHE_META gprs=4,29,31,16,17,18 fprs=12,20,22,24 gpr_occ=3036 fpr_occ=860 gpr_total=4359 fpr_total=1268
|
||||
std::uint32_t aot_gpr_4 = ctx.gpr[4];
|
||||
std::uint32_t aot_gpr_29 = ctx.gpr[29];
|
||||
std::uint32_t aot_gpr_31 = ctx.gpr[31];
|
||||
@@ -1109,11 +1109,16 @@ L_08A24120:
|
||||
if (([&]() { AOT_REGCACHE_SYNC_OUT(); const bool aot_regcache_same_ = (rt.invoke_chained_trusted_direct<&recomp_unit_0133_entry, 133u, 449u, 0x08A1AD6Cu>(ctx, &aot_mem)); if (aot_regcache_same_) AOT_REGCACHE_SYNC_IN(); else aot_regcache_valid = false; return aot_regcache_same_; }()) && ctx.pc == 0x08A24128u) goto L_08A24128;
|
||||
AOT_REGCACHE_SYNC_OUT(); return;
|
||||
L_08A24128:
|
||||
// Proven VCS actor-LOD path: the PSP WidescreenFix replaces the call that
|
||||
// normally follows this store. It writes s0+0x7A0 from s0+0x7A8 times the
|
||||
// requested multiplier and returns that multiplier in f0; the caller then
|
||||
// applies f0 to s0+0x7A8. Do the same directly in the recomp AOT path.
|
||||
if (vcs::g_draw_distance_runtime_scales.entity > 1.0f) {
|
||||
const float dd_base = std::bit_cast<float>(aot_mem.aot_direct_load32(aot_gpr_16 + static_cast<std::uint32_t>(1960)));
|
||||
++vcs::g_draw_distance_runtime_telemetry.actor_lod_hits;
|
||||
const float dd_scale = vcs::g_draw_distance_runtime_scales.entity;
|
||||
aot_fpr_12 = std::bit_cast<float>(aot_mem.aot_direct_load32(aot_gpr_16 + static_cast<std::uint32_t>(1960)));
|
||||
aot_mem.aot_direct_store32(aot_gpr_16 + static_cast<std::uint32_t>(1952),
|
||||
std::bit_cast<std::uint32_t>(dd_base * dd_scale));
|
||||
std::bit_cast<std::uint32_t>(aot_fpr_12 * dd_scale));
|
||||
ctx.fpr[0] = dd_scale;
|
||||
goto L_08A24138;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ static const std::uint16_t kEntryIds_recomp_unit_0186[4093] = {
|
||||
};
|
||||
void recomp_unit_0186_entry(Runtime &rt, AllegrexContext &ctx, std::uint16_t direct_entry_id, GuestMemory::AotFastView &aot_mem) {
|
||||
// PSPRECOMP_AOT_REGCACHE_BEGIN
|
||||
// PSPRECOMP_AOT_REGCACHE_META gprs=4,5,6,31,29,16 fprs=12,14,13,20 gpr_occ=3869 fpr_occ=363 gpr_total=5970 fpr_total=507
|
||||
// PSPRECOMP_AOT_REGCACHE_META gprs=4,5,6,31,29,16 fprs=12,14,13,20 gpr_occ=3869 fpr_occ=363 gpr_total=5971 fpr_total=507
|
||||
std::uint32_t aot_gpr_4 = ctx.gpr[4];
|
||||
std::uint32_t aot_gpr_5 = ctx.gpr[5];
|
||||
std::uint32_t aot_gpr_6 = ctx.gpr[6];
|
||||
@@ -2252,6 +2252,7 @@ L_08AEC904:
|
||||
goto L_08AEC918;
|
||||
}
|
||||
L_08AEC918:
|
||||
vcs::draw_distance_world_table_ready(rt, ctx.gpr[28]);
|
||||
{ std::uint32_t aot_run_words[4]{};
|
||||
aot_mem.aot_direct_load32_block(aot_gpr_29 + static_cast<std::uint32_t>(0), aot_run_words);
|
||||
aot_gpr_16 = aot_run_words[0];
|
||||
|
||||
@@ -139,7 +139,7 @@ static const std::uint16_t kEntryIds_recomp_unit_0208[4093] = {
|
||||
};
|
||||
void recomp_unit_0208_entry(Runtime &rt, AllegrexContext &ctx, std::uint16_t direct_entry_id, GuestMemory::AotFastView &aot_mem) {
|
||||
// PSPRECOMP_AOT_REGCACHE_BEGIN
|
||||
// PSPRECOMP_AOT_REGCACHE_META gprs=4,5,6,29,31,16 fprs=12,13,20,22 gpr_occ=3954 fpr_occ=758 gpr_total=5152 fpr_total=1078
|
||||
// PSPRECOMP_AOT_REGCACHE_META gprs=4,5,6,29,31,16 fprs=12,13,20,22 gpr_occ=3954 fpr_occ=759 gpr_total=5152 fpr_total=1079
|
||||
std::uint32_t aot_gpr_4 = ctx.gpr[4];
|
||||
std::uint32_t aot_gpr_5 = ctx.gpr[5];
|
||||
std::uint32_t aot_gpr_6 = ctx.gpr[6];
|
||||
@@ -4534,6 +4534,13 @@ L_08B45AA4:
|
||||
aot_fpr_13 = std::bit_cast<float>(aot_gpr_4);
|
||||
{ const bool branch_taken = 0u == 0u;
|
||||
{ const float fs = aot_fpr_12; const float ft = aot_fpr_13; if ((std::isinf(fs) && ft == 0.0f) || (std::isinf(ft) && fs == 0.0f)) aot_fpr_12 = std::bit_cast<float>(0x7FC00000u); else aot_fpr_12 = fs * ft; }
|
||||
// This is the dominant vehicle-distance path. The old experiment only
|
||||
// modified L_08B45AC0 below; this unconditional branch normally jumps
|
||||
// straight to AC8, so most vehicles never saw the configured multiplier.
|
||||
if (vcs::g_draw_distance_runtime_scales.vehicles > 1.0f) {
|
||||
++vcs::g_draw_distance_runtime_telemetry.vehicle_dynamic_hits;
|
||||
aot_fpr_12 *= vcs::g_draw_distance_runtime_scales.vehicles;
|
||||
}
|
||||
if (branch_taken) {
|
||||
goto L_08B45AC8;
|
||||
}
|
||||
@@ -4541,6 +4548,7 @@ L_08B45AA4:
|
||||
}
|
||||
L_08B45AC0:
|
||||
if (vcs::g_draw_distance_runtime_scales.vehicles > 1.0f) {
|
||||
++vcs::g_draw_distance_runtime_telemetry.vehicle_fallback_hits;
|
||||
aot_fpr_12 = 60.0f * vcs::g_draw_distance_runtime_scales.vehicles;
|
||||
goto L_08B45AC8;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"files": 234,
|
||||
"changed": 230,
|
||||
"gpr_occurrences": 914095,
|
||||
"fpr_occurrences": 146809,
|
||||
"gpr_total": 1266110,
|
||||
"fpr_total": 198361,
|
||||
"fpr_occurrences": 146813,
|
||||
"gpr_total": 1266111,
|
||||
"fpr_total": 198365,
|
||||
"resident_weight": 6,
|
||||
"units": [
|
||||
{
|
||||
@@ -2805,9 +2805,9 @@
|
||||
15
|
||||
],
|
||||
"gpr_occurrences": 3817,
|
||||
"fpr_occurrences": 847,
|
||||
"fpr_occurrences": 848,
|
||||
"gpr_total": 5332,
|
||||
"fpr_total": 1295
|
||||
"fpr_total": 1296
|
||||
},
|
||||
{
|
||||
"file": "generated_unit_0134.cpp",
|
||||
@@ -2868,9 +2868,9 @@
|
||||
24
|
||||
],
|
||||
"gpr_occurrences": 3036,
|
||||
"fpr_occurrences": 858,
|
||||
"fpr_occurrences": 860,
|
||||
"gpr_total": 4359,
|
||||
"fpr_total": 1266
|
||||
"fpr_total": 1268
|
||||
},
|
||||
{
|
||||
"file": "generated_unit_0137.cpp",
|
||||
@@ -3915,7 +3915,7 @@
|
||||
],
|
||||
"gpr_occurrences": 3869,
|
||||
"fpr_occurrences": 363,
|
||||
"gpr_total": 5970,
|
||||
"gpr_total": 5971,
|
||||
"fpr_total": 507
|
||||
},
|
||||
{
|
||||
@@ -4376,9 +4376,9 @@
|
||||
22
|
||||
],
|
||||
"gpr_occurrences": 3954,
|
||||
"fpr_occurrences": 758,
|
||||
"fpr_occurrences": 759,
|
||||
"gpr_total": 5152,
|
||||
"fpr_total": 1078
|
||||
"fpr_total": 1079
|
||||
},
|
||||
{
|
||||
"file": "generated_unit_0209.cpp",
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace vcs {
|
||||
|
||||
// Direct SM5.1 port of the CloudWorks implementation used by ProperShaders.
|
||||
// Density profiles, adaptive integration, sun shadow march, Beer-Lambert
|
||||
// extinction, Mie/Rayleigh lighting and front-to-back layer composition retain
|
||||
// the source equations and constants. The only platform adaptation is the
|
||||
// fullscreen input/ray contract used by VCSNative's DX12 backend.
|
||||
// CloudWorks: Brian Tu (RTU), CC BY-NC-SA 3.0.
|
||||
inline constexpr char kCloudWorksPresentShaderHlsl[] = R"CLOUD_HLSL(
|
||||
// Cloud pass descriptor contract:
|
||||
// t0 = sparse march texture for CloudTemporalResolvePS, or resolved cloud
|
||||
// history for CloudCompositePS/PresentPS
|
||||
// t1 = previous resolved cloud history for CloudTemporalResolvePS
|
||||
// s0 = clamp sampler (linear for resolve/composite)
|
||||
Texture2D<float4> CloudTexture0 : register(t0);
|
||||
Texture2D<float4> CloudTexture1 : register(t1);
|
||||
SamplerState CloudSampler : register(s0);
|
||||
|
||||
cbuffer CloudState : register(b0) {
|
||||
float3 CloudRayRight; float g_Time;
|
||||
float3 CloudRayUp; float randomSeed;
|
||||
float3 CloudRayForward; float g_Opacity;
|
||||
float3 CloudCameraPosition; uint g_Settings;
|
||||
float3 g_CloudCoverage; float g_CloudSpeed;
|
||||
float3 vSunLightDir; float fDayProgression;
|
||||
float3 g_vSunColor; float g_AtmDense;
|
||||
float3 g_vCloudBaseColor; float g_Mist;
|
||||
float3 g_FogColor; float g_FogDens;
|
||||
float g_Brightness; float3 CloudPadding;
|
||||
};
|
||||
|
||||
// Temporal pass contract (20 DWORDs). Together with CloudState's 40 DWORDs,
|
||||
// a two-SRV descriptor table and one sampler table this consumes 62 of the
|
||||
// D3D12 root signature's 64 DWORD budget.
|
||||
//
|
||||
// Translation invalidates history on the CPU. The previous ray basis below
|
||||
// therefore only has to reproject camera rotation; it is the same world-ray
|
||||
// basis used by CloudState and avoids importing matrix-layout conventions from
|
||||
// either the PSP GE or D3D9 ProperShaders implementation.
|
||||
cbuffer CloudTemporalState : register(b2) {
|
||||
float3 PrevCloudRayRight; float CloudHistoryValid;
|
||||
float3 PrevCloudRayUp; float CloudTemporalBlend;
|
||||
float3 PrevCloudRayForward; float CloudSpatialMix;
|
||||
float2 CloudTexelSize; float2 CloudSubPixel;
|
||||
float CloudFullResolutionMarch;
|
||||
float CloudClampExpand;
|
||||
float2 CloudTemporalPadding;
|
||||
};
|
||||
|
||||
struct PresentVertexOutput { float4 position : SV_POSITION; float2 uv : TEXCOORD0; };
|
||||
PresentVertexOutput PresentVS(uint id : SV_VertexID) {
|
||||
PresentVertexOutput o;
|
||||
if (id == 0u) { o.position=float4(-1,-1,0,1); o.uv=float2(0,1); }
|
||||
else if (id == 1u) { o.position=float4(-1,3,0,1); o.uv=float2(0,-1); }
|
||||
else { o.position=float4(3,-1,0,1); o.uv=float2(2,1); }
|
||||
return o;
|
||||
}
|
||||
float4 PresentPS(PresentVertexOutput i) : SV_TARGET {
|
||||
return CloudTexture0.SampleLevel(CloudSampler, i.uv, 0.0);
|
||||
}
|
||||
|
||||
static const float VC_HASH_MUL = 1332.03398875;
|
||||
float hash(float n) { return frac(sin(n / 1873.1873 + randomSeed) * VC_HASH_MUL); }
|
||||
float noise2d(float3 p) {
|
||||
float3 fr=floor(p), ft=frac(p); float n=1153*fr.x+2381*fr.y+p.z;
|
||||
float nr=n+1153, nd=n+2381, no=nr+2381;
|
||||
return lerp(lerp(hash(n),hash(nr),ft.x),lerp(hash(nd),hash(no),ft.x),ft.y);
|
||||
}
|
||||
float noise3d(float3 p) {
|
||||
float3 fr=floor(p), ft=frac(p); float n=1153*fr.x+2381*fr.y+fr.z;
|
||||
float nr=n+1153, nd=n+2381, no=nr+2381;
|
||||
float v=lerp(hash(n),hash(n+1),ft.z), vr=lerp(hash(nr),hash(nr+1),ft.z);
|
||||
float vd=lerp(hash(nd),hash(nd+1),ft.z), vo=lerp(hash(no),hash(no+1),ft.z);
|
||||
return lerp(lerp(v,vr,ft.x),lerp(vd,vo,ft.x),ft.y);
|
||||
}
|
||||
float map(float x,float a,float b,float c,float d) { return (x-b)/(a-b)*(c-d)+d; }
|
||||
float clampMap(float x,float a,float b,float c,float d) { return saturate((x-b)/(a-b))*(c-d)+d; }
|
||||
|
||||
static const float atmosphereStep=15.0, lightStep=3.0, fix=0.00001;
|
||||
static const float3 sunLightStrength=685.0*float3(1.0,0.96,0.949);
|
||||
static const float LightingDecay=300.0, rayleighStrength=1.85, rayleighDecay=900.0;
|
||||
static const float3 waveLengthFactor=float3(6.5*6.5*6.5*6.5,5.4*5.4*5.4*5.4,4.5*4.5*4.5*4.5);
|
||||
static const float3 scatteringFactor=waveLengthFactor/rayleighDecay;
|
||||
static const float earthRadius=6.421, groundHeight=6.371, game2atm=1000000.0;
|
||||
static const float3 AtmOrigin=float3(0,0,groundHeight);
|
||||
static const float4 earth=float4(0,0,0,earthRadius);
|
||||
float3 Game2Atm(float3 p) { return p/game2atm+AtmOrigin; }
|
||||
float3 Game2Atm_Alt(float3 p) { return float3(0,0,p.z/game2atm)+AtmOrigin; }
|
||||
float4 sphereCast(float3 origin,float3 ray,float4 sphere,float steps,out float3 begin) {
|
||||
begin=origin;
|
||||
float3 p=origin-sphere.xyz; float r=length(p), d=length(cross(p,ray));
|
||||
if(d>sphere.w+fix){begin=0;return 0;} float sr=sqrt(sphere.w*sphere.w-d*d),dr=-dot(p,ray);
|
||||
float3 pc=origin+ray*dr,pf=pc+ray*sr,pb=pc-ray*sr; float sl;
|
||||
if(r>sphere.w){begin=pb;sl=sr*2/steps;}else{begin=origin;sl=length(pf-origin)/steps;}
|
||||
return float4(ray*sl,sl);
|
||||
}
|
||||
float2 Density(float3 pos,float4 sphere,float strength,float condense) {
|
||||
float atmDensity=3.0+g_AtmDense,fogDensity=0.25+g_Mist;
|
||||
float r=groundHeight,h=length(pos-sphere.xyz)-r,ep=exp(-(sphere.w-r)*condense);
|
||||
float fog=fogDensity*(1.0/(1200.0*h+0.5)-0.04)/1.96;
|
||||
if(h<0)return float2(strength,fogDensity);
|
||||
return float2((exp(-h*condense)-ep)/(1.0-ep)*strength,fog);
|
||||
}
|
||||
float3 rayleighScattering(float c){return (1+c*c)*rayleighStrength/waveLengthFactor;}
|
||||
float MiePhase(float c){return 1.0+1.6*exp(20.0*(c-1.0));}
|
||||
float MieScattering(float c){return (0.125+g_Mist*0.1)*MiePhase(c);}
|
||||
float3 LightDecay(float r,float m){return exp(-r/scatteringFactor-m*100.0);}
|
||||
float3 SunLight(float3 light,float3 position,float3 lightDirection,float4 sphere){
|
||||
float3 smp=position;float4 sms=sphereCast(position,lightDirection,sphere,lightStep,smp);float2 dl=0;
|
||||
[unroll]for(int j=0;j<3;j++){smp+=sms.xyz/2;dl+=Density(smp,sphere,3.0+g_AtmDense,1.0)*sms.w;smp+=sms.xyz/2;}
|
||||
return light*LightDecay(dl.x,dl.y)/LightingDecay;
|
||||
}
|
||||
float3 LightSource(float3 active,float day,float3 color,out float3 source){
|
||||
source=active;
|
||||
if(day<-0.2)return sunLightStrength*smoothstep(0.1,0.3,-day)*color;
|
||||
return sunLightStrength*smoothstep(-0.2,-0.1,day)*color;
|
||||
}
|
||||
float3 AtmosphereScattering(float3 background,float3 marchPos,float4 marchStep,float3 ray,
|
||||
float3 lightStrength,float3 lightDirection,float strength,float4 sphere){
|
||||
float3 intensity=0;float ang=dot(ray,lightDirection),mie=MieScattering(ang);float3 raylei=rayleighScattering(ang);
|
||||
if(marchStep.w>0.015)marchStep/=marchStep.w/0.015;float2 dv=0;
|
||||
[loop]for(int i=0;i<15;i++){float3 smp=marchPos;float4 sms=sphereCast(marchPos,lightDirection,sphere,lightStep,smp);
|
||||
float2 sampling=Density(marchPos,sphere,3.0+g_AtmDense,1.0)*marchStep.w;dv+=sampling/2;float2 dl=dv;
|
||||
[unroll]for(int j=0;j<3;j++){smp+=sms.xyz;dl+=Density(smp,sphere,3.0+g_AtmDense,1.0)*sms.w;}
|
||||
intensity+=LightDecay(dl.x,dl.y)*(raylei*sampling.x+mie*sampling.y);dv+=sampling/2;marchPos+=marchStep.xyz;}
|
||||
return lightStrength*intensity*strength+background*LightDecay(dv.x,dv.y);
|
||||
}
|
||||
float3 atmosphere_scattering(float strength,float3 color,float3 camera,float3 ray,float distance,float3 sunDirection,float4 sphere){
|
||||
if(distance<200)return color;float fade=smoothstep(200,300,distance);float4 step=0;
|
||||
step.w=15.0*distance/atmosphereStep/game2atm;step.xyz=ray*step.w;float3 lightDir=sunDirection;
|
||||
float3 light=LightSource(sunDirection,fDayProgression,1.0,lightDir);
|
||||
float3 scattered=AtmosphereScattering(color,Game2Atm_Alt(camera),step,ray,light,lightDir,1.0,sphere);
|
||||
return lerp(color,scattered,fade);
|
||||
}
|
||||
)CLOUD_HLSL"
|
||||
R"CLOUD_HLSL(
|
||||
|
||||
struct CloudBaseColor {float3 BaseColor;float3 BaseColor_Day;float3 BaseColor_Sunset;};
|
||||
struct CloudProfile {
|
||||
float4 march;float2 cutoff;float2 volumeBox;float4 shape;float brightness;float3 range;
|
||||
float2 solidness;float2 densityChunk;float4 shadow;float4 distortion;float fade;
|
||||
float3 densityDetail;float3 scaleChunk;float3 scaleDetail;float3 cloudShift;
|
||||
float3 offsetA;float3 offsetB;float3 offsetC;float3 offsetD;
|
||||
};
|
||||
float gameTime(){return 1000.0+g_Time*g_CloudSpeed/100.0;}
|
||||
float3 PosOnPlane(float3 o,float3 d,float h,inout float dist){dist=(h-o.z)/d.z;return o+d*dist;}
|
||||
float4 CloudShape(float z,float4 shape,float3 range){float soft=map(z,shape.y,shape.x,range.z,range.y);
|
||||
return float4(smoothstep(shape.z,lerp(shape.y,shape.z,shape.w),z)*smoothstep(shape.x,lerp(shape.y,shape.x,shape.w),z),range.x+soft,range.x-soft,soft);}
|
||||
float3 DistortionVec(float lump,float4 d){return float3(cos(lump*d.x)*d.y,0,-lump*d.z);}
|
||||
float Chunk(float3 pos,float2 density,float3 scale,float3 shift,float3 oA,float3 oB,float cs){
|
||||
pos.z/=scale.z;pos+=shift*pos.z;float3 pA=(pos+oA)*scale.x,pB=(pos+oB)*scale.y;
|
||||
return noise3d(pA)*(noise3d(pB)*density.y+density.x)*cs;}
|
||||
float DetailA(float3 pos,float3 density,float3 scale,float3 oC,float3 dist){return density.x*noise3d((pos+oC+dist)*scale.x);}
|
||||
float DetailB(float lump,float3 pos,float3 density,float3 scale,float4 dp,float3 oC,float3 oD,float cs){
|
||||
float3 d=DistortionVec(lump,dp),pD=pos+oD;float dens=DetailA(pos,density,scale,oC,d);d.z-=dens*dp.w;
|
||||
dens+=density.y*noise3d((pD+d/3)*scale.y);dens+=dens*density.z*noise3d((pD+d*8)*scale.z);return dens;}
|
||||
float GetDensity(float df,float height,float low,float high,float2 vb,float2 sol){return clampMap(df,low,high,0,clampMap(height,vb.y,vb.x,sol.y,sol.x));}
|
||||
float ShadowMarching(float dens,float3 p,CloudProfile a,float3 threshold,float3 sunDir){
|
||||
uint shadowSteps=(g_Settings>>8)&15u;
|
||||
if(dens<=0.025)return dens*a.shadow.x;
|
||||
// ProperShaders used four large samples for the DX9/SM3 instruction budget.
|
||||
// DX12 can split the same physical shadow-march reach into up to eight
|
||||
// samples, removing the dark density contours without changing its extent.
|
||||
float stepLen=a.shadow.x*(8.0/max((float)shadowSteps,1.0));
|
||||
float limit=2.0/a.shadow.w/stepLen,d=0;float4 st=float4(sunDir*stepLen,stepLen);
|
||||
[loop]for(uint i=0;i<8;i++){if(i>=shadowSteps||d>=limit||p.z>=a.volumeBox.x||p.z<=a.volumeBox.y)break;
|
||||
p+=st.xyz;float4 cs=CloudShape(p.z,a.shape,threshold);float d1=Chunk(p,a.densityChunk,a.scaleChunk,a.cloudShift,a.offsetA,a.offsetB,cs.x);
|
||||
float d2=DetailA(p,a.densityDetail,a.scaleDetail,a.offsetC,DistortionVec(d1,a.distortion))*a.shadow.y;
|
||||
d+=GetDensity(d1*d2+d1,p.z,cs.z-a.shadow.z,cs.y,a.volumeBox,a.solidness);}
|
||||
return d*a.shadow.w*st.w;}
|
||||
|
||||
float4 CloudAtRay(CloudProfile a,CloudBaseColor b,float3 dir,float3 cam,float3 light,float3 lightDir,float time,inout float distance){
|
||||
float4 d=float4(0,0,0,a.march.y);if(abs(dir.z)<1e-6)return float4(0,0,0,1);
|
||||
float3 p=PosOnPlane(cam,dir,clamp(cam.z,a.volumeBox.y+0.001,a.volumeBox.x-0.001),d.x);d.y=d.x;
|
||||
if(d.x>=0&&distance>d.x){a.range.x=1/a.range.x;float3 fx=float3(0,0,1);float last=0,pdf=0;
|
||||
[loop]for(int i=0;i<64;i++){if(fx.z<=0||p.z>a.volumeBox.x||p.z<a.volumeBox.y||i>=(int)a.march.w||d.x-d.w>=distance||d.x>=a.fade)break;
|
||||
float3 cs=CloudShape(p.z,a.shape,a.range).xyz;float d1=Chunk(p,a.densityChunk,a.scaleChunk,a.cloudShift,a.offsetA,a.offsetB,cs.x);
|
||||
float d2=DetailB(d1,p,a.densityDetail,a.scaleDetail,a.distortion,a.offsetC,a.offsetD,cs.x);float df=d1*d2+d1;
|
||||
if(df>cs.z){float dens=GetDensity(df,p.z,cs.z,cs.y,a.volumeBox,a.solidness);float cd=(dens+last)*a.march.x/2;last=dens;
|
||||
if(d.x>=distance)cd*=d.z/d.w;if(cd>0)d.y=d.y*(1-fx.z)+fx.z*d.x;fx.y+=cd;fx.z=(exp(-fx.y)-a.cutoff.y)/(1-a.cutoff.y);d.z=distance-d.x;
|
||||
if(fx.y<2.3)fx.x+=cd*exp(-ShadowMarching(cd,p,a,a.range,lightDir)-fx.y);}
|
||||
d.w=clampMap(2*df-pdf,cs.z*0.85,a.cutoff.x,a.march.x,a.march.y);d.w*=clampMap(d.x,0,a.fade,1,a.march.z);
|
||||
// The stochastic step offset is intentional. ProperShaders averages it in
|
||||
// the reprojected temporal history instead of exposing one undersampled
|
||||
// march directly on screen.
|
||||
d.w+=noise2d(p+g_Time)*a.march.x;pdf=df;p+=dir*d.w;d.x+=d.w;}
|
||||
if(fx.z<1){fx=saturate(fx);float3 z=float3(0,0,cam.z);float3 cbright=SunLight(light,Game2Atm(z+dir*d.y),lightDir,earth)*a.brightness;
|
||||
float3 C=cbright*fx.x*MiePhase(dot(lightDir,dir))+(b.BaseColor*g_vCloudBaseColor)*(1-fx.z);
|
||||
C=atmosphere_scattering(1-fx.z,C,Game2Atm(z),dir,d.y/game2atm,lightDir,earth);
|
||||
distance=distance*fx.z+d.y*(1-fx.z);return float4(C,fx.z);}}
|
||||
return float4(0,0,0,1);}
|
||||
|
||||
float4 CloudAtRayHighLite(CloudBaseColor b,float3 dir,float3 cam,float3 light,float3 lightDir,float time,inout float distance){
|
||||
const float top=3600.0,bottom=3500.0;float4 d=float4(0,0,0,75);
|
||||
float3 p=PosOnPlane(cam,dir,clamp(cam.z,bottom+.001,top-.001),d.x);d.y=d.x;
|
||||
if(d.x>=0&&distance>d.x){
|
||||
float coverage=g_CloudCoverage.z;float3 range=float3(1+coverage*.3,.2,.35);
|
||||
float grow=noise3d(float3(3800,bottom,time/2000))*.45+.65;
|
||||
range.x*=grow*(1-coverage)+coverage;range.x=1/range.x;
|
||||
const float2 volumeBox=float2(top,bottom),solidness=float2(.25,0),densityChunk=float2(.4,.3);
|
||||
const float3 scaleChunk=float3(.00016,.0008,1.5),densityDetail=float3(.2,.1,.6),scaleDetail=float3(.004,.006667,.02);
|
||||
const float4 distortion=float4(2.5,15000,0,0);
|
||||
float3 oA=float3(1.3,-1.8,0)*-time,oB=float3(1.6,.8,0)*-time;
|
||||
float3 oC=float3(2.5,.2,.5)*-time,oD=float3(3,.1,-.1)*-time;
|
||||
float3 fx=float3(0,0,1);float last=0,pdf=0;
|
||||
[loop]for(int i=0;i<32;i++){
|
||||
if(fx.z<=0||p.z>top||p.z<bottom||d.x-d.w>=distance||d.x>=60000)break;
|
||||
float3 cs=CloudShape(p.z,float4(3800,3520,3450,0),range).xyz;
|
||||
float d1=Chunk(p,densityChunk,scaleChunk,0,oA,oB,cs.x);
|
||||
float d2=DetailB(d1,p,densityDetail,scaleDetail,distortion,oC,oD,cs.x);float df=d1*d2+d1;
|
||||
if(df>cs.z){float dens=GetDensity(df,p.z,cs.z,cs.y,volumeBox,solidness);float cd=(dens+last)*2.5;last=dens;
|
||||
if(d.x>=distance)cd*=d.z/d.w;if(cd>0)d.y=d.y*(1-fx.z)+fx.z*d.x;
|
||||
fx.y+=cd;fx.z=(exp(-fx.y)-.2)/.8;d.z=distance-d.x;if(fx.y<2.3)fx.x+=cd*exp(-fx.y);}
|
||||
d.w=clampMap(2*df-pdf,cs.z*.85,0,5,75);d.w*=clampMap(d.x,0,2000000,1,500);
|
||||
d.w+=noise2d(p+g_Time)*5;pdf=df;p+=dir*d.w;d.x+=d.w;}
|
||||
if(fx.z<1){fx=saturate(fx);float3 cbright=light*(.5/LightingDecay);
|
||||
float3 C=cbright*fx.x*MiePhase(dot(lightDir,dir))+(b.BaseColor*g_vCloudBaseColor)*(1-fx.z);
|
||||
distance=distance*fx.z+d.y*(1-fx.z);return float4(C,fx.z);}}
|
||||
return float4(0,0,0,1);}
|
||||
|
||||
CloudProfile BuildProfile0(float time,float coverage){CloudProfile p=(CloudProfile)0;
|
||||
p.march=float4(5,80,8,64);p.cutoff=float2(0,.2);p.volumeBox=float2(900,500);p.shape=float4(900,650,0,0);p.brightness=.5;
|
||||
p.range=float3(.9+coverage*.16,.1,.2+coverage*.4);p.solidness=float2(5,0)*coverage;p.densityChunk=float2(.3,.5);
|
||||
p.shadow=float4(60,1.75,.1,.03);p.distortion=float4(1.6,60,8,16);p.fade=6000;p.densityDetail=float3(.3,.2,.6);
|
||||
p.scaleChunk=float3(.0008,.005,1);p.scaleDetail=float3(.02,.04,.1);p.cloudShift=float3(-.5,0,0);
|
||||
p.offsetA=float3(1.8,-1,0)*-time;p.offsetB=float3(2,.2,0)*-time;p.offsetC=float3(3,0,.5)*-time;p.offsetD=float3(3.5,0,-.1)*-time;
|
||||
float grow=noise3d(float3(p.shape.x,p.volumeBox.y,time/2000))*.45+.65;p.range.x*=grow*(1-coverage)+coverage;return p;}
|
||||
CloudProfile BuildProfile1(float time,float coverage){CloudProfile p=(CloudProfile)0;
|
||||
p.march=float4(12,70,8,64);p.cutoff=float2(0,.2);p.volumeBox=float2(1900,1500);p.shape=float4(2100,1650,0,0);p.brightness=.5;
|
||||
p.range=float3(.85+coverage*.78,0,.3+coverage*.16);p.solidness=float2(.35,.1)*coverage;p.densityChunk=float2(.25,.6);
|
||||
p.shadow=float4(30,1,.15,.1);p.distortion=float4(6,50,100,50);p.fade=20000;p.densityDetail=float3(.5,.25,.5);
|
||||
p.scaleChunk=float3(.0008,.004,1.5);p.scaleDetail=float3(.0142857,.0285714,.08);p.cloudShift=0;
|
||||
p.offsetA=float3(1.5,-1.2,0)*-time;p.offsetB=float3(1.9,.5,0)*-time;p.offsetC=float3(2.5,0,.5)*-time;p.offsetD=float3(3,.1,-.1)*-time;
|
||||
float grow=noise3d(float3(p.shape.x,p.volumeBox.y,time/2000))*.45+.65;p.range.x*=grow*(1-coverage)+coverage;return p;}
|
||||
CloudProfile BuildProfile2(float time,float coverage){CloudProfile p=(CloudProfile)0;
|
||||
p.march=float4(5,75,500,50);p.cutoff=float2(0,.2);p.volumeBox=float2(3600,3500);p.shape=float4(3800,3520,3450,0);p.brightness=.5;
|
||||
p.range=float3(1+coverage*.9,.2,.35);p.solidness=float2(.25,0);p.densityChunk=float2(.4,.3);
|
||||
p.shadow=float4(50,1.5,.02,.1);p.distortion=float4(2.5,15000,0,0);p.fade=2000000;p.densityDetail=float3(.2,.1,.6);
|
||||
p.scaleChunk=float3(.00016,.0008,1.5);p.scaleDetail=float3(.004,.006667,.02);p.cloudShift=0;
|
||||
p.offsetA=float3(1.3,-1.8,0)*-time;p.offsetB=float3(1.6,.8,0)*-time;p.offsetC=float3(2.5,.2,.5)*-time;p.offsetD=float3(3,.1,-.1)*-time;
|
||||
float grow=noise3d(float3(p.shape.x,p.volumeBox.y,time/2000))*.45+.65;p.range.x*=grow*(1-coverage)+coverage;return p;}
|
||||
CloudBaseColor GetCloudsColor(float3 sunDir){CloudBaseColor b=(CloudBaseColor)0;b.BaseColor=.2;b.BaseColor_Day=.2;b.BaseColor_Sunset=.2;
|
||||
float night=smoothstep(.3,.1,fDayProgression),day=smoothstep(-.03,.05,fDayProgression),sunset=night*day;
|
||||
b.BaseColor+=lerp(b.BaseColor_Day,b.BaseColor_Sunset,sunset)*day;return b;}
|
||||
float4 RenderClouds(float3 dir,float3 cam){float time=gameTime();CloudBaseColor base=GetCloudsColor(vSunLightDir);
|
||||
float3 lightDir=normalize(vSunLightDir);float3 light=LightSource(lightDir,fDayProgression,g_vSunColor,lightDir);float distance=100000;
|
||||
float4 result=CloudAtRay(BuildProfile0(time,g_CloudCoverage.x),base,dir,cam,light,lightDir,time,distance);
|
||||
uint layers=g_Settings&3u;if(layers>=3u&&result.w>.01){float4 mid=CloudAtRay(BuildProfile1(time,g_CloudCoverage.y),base,dir,cam,light,lightDir,time,distance);result.rgb+=mid.rgb*result.w;result.w*=mid.w;}
|
||||
if(layers>=2u&&result.w>.01){float4 high=CloudAtRayHighLite(base,dir,cam,light,lightDir,time,distance);result.rgb+=high.rgb*result.w;result.w*=high.w;}
|
||||
return result;}
|
||||
float3 WorldRay(float2 uv){float2 ndc=float2(uv.x*2-1,1-uv.y*2);return normalize(CloudRayForward+CloudRayRight*ndc.x+CloudRayUp*ndc.y);}
|
||||
|
||||
static const float VC_TEMPORAL_DIV=2.0;
|
||||
static const float VC_INV_TEMPORAL_DIV=0.5;
|
||||
static const float VC_RAIL_FLOOR=4.0;
|
||||
|
||||
// A sparse march target contains one texel for each 2x2 block of the resolved
|
||||
// cloud history. SV_POSITION identifies the sparse texel exactly; deriving UV
|
||||
// from it avoids interpolation and half-pixel disagreements between APIs.
|
||||
float2 CloudMarchUV(float2 position){
|
||||
float2 pixel=floor(position);
|
||||
float2 sparseUV=(pixel*VC_TEMPORAL_DIV+CloudSubPixel+0.5)*CloudTexelSize;
|
||||
float2 fullUV=(pixel+0.5)*CloudTexelSize;
|
||||
return lerp(sparseUV,fullUV,saturate(CloudFullResolutionMarch));
|
||||
}
|
||||
|
||||
// History stores CloudWorks' native representation: premultiplied scattered
|
||||
// light in rgb and TRANSMITTANCE in alpha (clear sky is 0,0,0,1).
|
||||
float4 CloudMarchPS(PresentVertexOutput i):SV_TARGET {
|
||||
if((g_Settings&0x10000u)==0u)return float4(0,0,0,1);
|
||||
float3 dir=WorldRay(CloudMarchUV(i.position.xy));
|
||||
return RenderClouds(dir,CloudCameraPosition);
|
||||
}
|
||||
|
||||
// Kept as an entry-point alias while the backend moves from its former direct
|
||||
// cloud target to the full/sparse march paths.
|
||||
float4 CloudTargetPS(PresentVertexOutput i):SV_TARGET {
|
||||
return CloudMarchPS(i);
|
||||
}
|
||||
|
||||
// Reproject a current world direction into the previous camera's ray basis.
|
||||
// If d = q.x*R + q.y*U + q.z*F, previous NDC is q.xy/q.z. Cramer's rule keeps
|
||||
// this exact for asymmetric projections and avoids a separate 4x4 matrix.
|
||||
float3 PreviousCloudNdc(float3 dir){
|
||||
float det=dot(PrevCloudRayRight,cross(PrevCloudRayUp,PrevCloudRayForward));
|
||||
float safeDet=(abs(det)>1e-8)?det:((det<0)?-1e-8:1e-8);
|
||||
float3 q=float3(
|
||||
dot(dir,cross(PrevCloudRayUp,PrevCloudRayForward)),
|
||||
dot(PrevCloudRayRight,cross(dir,PrevCloudRayForward)),
|
||||
dot(PrevCloudRayRight,cross(PrevCloudRayUp,dir)))/safeDet;
|
||||
return float3(q.xy/max(q.z,1e-8),q.z);
|
||||
}
|
||||
|
||||
float CloudSlabEntry(float cameraZ,float rayZ,float bottom,float top){
|
||||
if(abs(rayZ)<1e-6)return 50000.0;
|
||||
if(cameraZ>=bottom&&cameraZ<=top)return 0.0;
|
||||
float a=(bottom-cameraZ)/rayZ,b=(top-cameraZ)/rayZ;
|
||||
float entry=min(a,b),leave=max(a,b);
|
||||
return leave<0.0?50000.0:max(entry,0.0);
|
||||
}
|
||||
|
||||
// Reproject translation as well as rotation. CloudPadding carries the previous
|
||||
// camera position. A world point on the nearest enabled physical cloud slab is
|
||||
// stable under the orbiting VCS third-person camera, unlike a direction-only
|
||||
// reprojection that forces the history to reset whenever the camera moves.
|
||||
float3 PreviousCloudDirection(float2 uv){
|
||||
float3 dir=WorldRay(uv);
|
||||
float distance=CloudSlabEntry(CloudCameraPosition.z,dir.z,500.0,900.0);
|
||||
if((g_Settings&3u)>=2u)
|
||||
distance=min(distance,CloudSlabEntry(CloudCameraPosition.z,dir.z,3500.0,3600.0));
|
||||
if((g_Settings&3u)>=3u)
|
||||
distance=min(distance,CloudSlabEntry(CloudCameraPosition.z,dir.z,1500.0,1900.0));
|
||||
distance=min(max(distance,1.0),50000.0);
|
||||
float3 worldPoint=CloudCameraPosition+dir*distance;
|
||||
return normalize(worldPoint-CloudPadding);
|
||||
}
|
||||
|
||||
// Literal SM5 adaptation of ProperShaders' PS_TemporalResolve. The march fills
|
||||
// one Bayer slot per 2x2 block; every other pixel keeps its own reprojected
|
||||
// history and leaks slightly toward the smooth current-frame reconstruction.
|
||||
float4 CloudTemporalResolvePS(PresentVertexOutput i):SV_TARGET {
|
||||
float2 pixel=floor(i.position.xy);
|
||||
float2 uv=(pixel+0.5)*CloudTexelSize;
|
||||
float2 marchTexel=CloudTexelSize*VC_TEMPORAL_DIV;
|
||||
|
||||
float2 block=floor(pixel*VC_INV_TEMPORAL_DIV);
|
||||
float2 slot=pixel-block*VC_TEMPORAL_DIV;
|
||||
float2 blockUV=(block+0.5)*marchTexel;
|
||||
float4 c=CloudTexture0.SampleLevel(CloudSampler,blockUV,0.0);
|
||||
|
||||
float2 freshDelta=abs(slot-CloudSubPixel);
|
||||
float fresh=step(freshDelta.x+freshDelta.y,0.5);
|
||||
|
||||
float2 spatialUV=uv-(CloudSubPixel-(VC_TEMPORAL_DIV-1.0)*0.5)*CloudTexelSize;
|
||||
float2 sp=spatialUV/marchTexel-0.5;
|
||||
float2 sf=frac(sp);
|
||||
float2 sb=(floor(sp)+0.5)*marchTexel;
|
||||
float4 t00=CloudTexture0.SampleLevel(CloudSampler,sb,0.0);
|
||||
float4 t10=CloudTexture0.SampleLevel(CloudSampler,sb+float2(marchTexel.x,0),0.0);
|
||||
float4 t01=CloudTexture0.SampleLevel(CloudSampler,sb+float2(0,marchTexel.y),0.0);
|
||||
float4 t11=CloudTexture0.SampleLevel(CloudSampler,sb+marchTexel,0.0);
|
||||
float4 spatial=lerp(lerp(t00,t10,sf.x),lerp(t01,t11,sf.x),sf.y);
|
||||
|
||||
float3 previous=PreviousCloudNdc(PreviousCloudDirection(uv));
|
||||
float2 prevUV=float2(previous.x*0.5+0.5,0.5-previous.y*0.5);
|
||||
float2 inside=step(float2(0,0),prevUV)*step(prevUV,float2(1,1));
|
||||
float valid=CloudHistoryValid*inside.x*inside.y*step(1e-8,previous.z);
|
||||
float4 hist=CloudTexture1.SampleLevel(CloudSampler,prevUV,0.0);
|
||||
|
||||
// Loose safety rail from ProperShaders. RGB and transmittance must move as a
|
||||
// single value; clamping channels independently creates black pinholes.
|
||||
float4 mn=min(min(min(t00,t10),min(t01,t11)),c);
|
||||
float4 mx=max(max(max(t00,t10),max(t01,t11)),c);
|
||||
float4 mid=(mn+mx)*0.5;
|
||||
float3 spanRGB=mx.rgb-mn.rgb;
|
||||
float span=max(max(spanRGB.r,spanRGB.g),max(spanRGB.b,mx.a-mn.a));
|
||||
float ext=max(span*CloudClampExpand,VC_RAIL_FLOOR);
|
||||
float4 dev=abs(hist-mid)-ext;
|
||||
float over=max(max(dev.r,dev.g),max(dev.b,dev.a));
|
||||
hist=lerp(hist,mid,saturate(over));
|
||||
|
||||
float4 src=lerp(spatial,c,fresh);
|
||||
float w=lerp(1.0-CloudSpatialMix,CloudTemporalBlend,fresh)*valid;
|
||||
return lerp(src,hist,w);
|
||||
}
|
||||
|
||||
// Manual four-tap bilinear upscale matches ProperShaders even if the bound
|
||||
// sampler is point-filtered. The backend blends this premultiplied result over
|
||||
// the world target with ONE / INV_SRC_ALPHA.
|
||||
float4 CloudCompositePS(PresentVertexOutput i):SV_TARGET {
|
||||
float2 texelPos=i.uv/CloudTexelSize-0.5;
|
||||
float2 f=frac(texelPos);
|
||||
float2 base=(floor(texelPos)+0.5)*CloudTexelSize;
|
||||
float4 c00=CloudTexture0.SampleLevel(CloudSampler,base,0.0);
|
||||
float4 c10=CloudTexture0.SampleLevel(CloudSampler,base+float2(CloudTexelSize.x,0),0.0);
|
||||
float4 c01=CloudTexture0.SampleLevel(CloudSampler,base+float2(0,CloudTexelSize.y),0.0);
|
||||
float4 c11=CloudTexture0.SampleLevel(CloudSampler,base+CloudTexelSize,0.0);
|
||||
float4 clouds=lerp(lerp(c00,c10,f.x),lerp(c01,c11,f.x),f.y);
|
||||
float alpha=saturate((1.0-clouds.a)*g_Opacity);
|
||||
return float4(clouds.rgb*g_Opacity*g_Brightness,alpha);
|
||||
}
|
||||
)CLOUD_HLSL";
|
||||
|
||||
} // namespace vcs
|
||||
@@ -14,10 +14,18 @@ enum class GeGpuBackendKind : std::uint8_t {
|
||||
DirectX12,
|
||||
};
|
||||
|
||||
enum class GeShaderPipe : std::uint8_t {
|
||||
Native = 0,
|
||||
Building = 1,
|
||||
Skin = 2,
|
||||
Vehicle = 3,
|
||||
};
|
||||
|
||||
struct GeGpuDrawDescriptor {
|
||||
std::uint32_t primitive{};
|
||||
std::uint32_t vertex_count{};
|
||||
std::uint32_t vertex_type{};
|
||||
GeShaderPipe shader_pipe{GeShaderPipe::Native};
|
||||
// GE render target for this draw. Stage 33 uses it to exclude prelight,
|
||||
// reflection and other offscreen passes from the presented framebuffer.
|
||||
std::uint32_t framebuffer_address{};
|
||||
@@ -122,6 +130,9 @@ struct GeGpuDrawDescriptor {
|
||||
// triangles. The backend folds viewport/composition into model_to_clip once per
|
||||
// draw and pushes the final constants to the vertex shader.
|
||||
struct GeGpuHardwareTransform {
|
||||
// Kept separately from model_to_clip for private material/shadow passes.
|
||||
// Lit geometry that has already been transformed to world space stores identity.
|
||||
std::array<float, 16> model_to_world{};
|
||||
std::array<float, 16> model_to_clip{};
|
||||
std::array<float, 4> model_to_view_z{};
|
||||
float viewport_scale_x{};
|
||||
@@ -430,7 +441,7 @@ void ge_gpu_backend_record_draw(const GeGpuDrawDescriptor &draw) noexcept;
|
||||
// The matrices are observed with the draw, before the GE state advances.
|
||||
void ge_gpu_backend_observe_camera(const std::array<float, 12> &view,
|
||||
const std::array<float, 16> &projection,
|
||||
const std::array<float, 6> &viewport,
|
||||
const std::array<float, 8> &viewport,
|
||||
const std::array<float, 3> &camera_position,
|
||||
const GeGpuDrawDescriptor &draw,
|
||||
std::uint32_t vertex_weight) noexcept;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,400 +0,0 @@
|
||||
// Generated by tools/build_hdr_spirv.sh. Do not edit by hand.
|
||||
//
|
||||
// SimulateHDR, ported from ProperShaders, itself a fork of "Blooming HDR"
|
||||
// by Jose Negrete (BlueSkyDefender). CC BY-SA 4.0, changes were made; the
|
||||
// full notice is in shaders/hdr/LICENSE_SIMULATEHDR.txt.
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace vcs::hdr_shaders {
|
||||
|
||||
inline constexpr std::array<std::uint32_t, 233> hdr_fullscreen_vert{{
|
||||
0x07230203u, 0x00010000u, 0x000D000Bu, 0x0000002Cu, 0x00000000u, 0x00020011u, 0x00000001u,
|
||||
0x0006000Bu, 0x00000001u, 0x4C534C47u, 0x6474732Eu, 0x3035342Eu, 0x00000000u, 0x0003000Eu,
|
||||
0x00000000u, 0x00000001u, 0x0008000Fu, 0x00000000u, 0x00000004u, 0x6E69616Du, 0x00000000u,
|
||||
0x00000009u, 0x0000000Cu, 0x0000001Du, 0x00040047u, 0x00000009u, 0x0000001Eu, 0x00000000u,
|
||||
0x00040047u, 0x0000000Cu, 0x0000000Bu, 0x0000002Au, 0x00030047u, 0x0000001Bu, 0x00000002u,
|
||||
0x00050048u, 0x0000001Bu, 0x00000000u, 0x0000000Bu, 0x00000000u, 0x00050048u, 0x0000001Bu,
|
||||
0x00000001u, 0x0000000Bu, 0x00000001u, 0x00050048u, 0x0000001Bu, 0x00000002u, 0x0000000Bu,
|
||||
0x00000003u, 0x00050048u, 0x0000001Bu, 0x00000003u, 0x0000000Bu, 0x00000004u, 0x00020013u,
|
||||
0x00000002u, 0x00030021u, 0x00000003u, 0x00000002u, 0x00030016u, 0x00000006u, 0x00000020u,
|
||||
0x00040017u, 0x00000007u, 0x00000006u, 0x00000002u, 0x00040020u, 0x00000008u, 0x00000003u,
|
||||
0x00000007u, 0x0004003Bu, 0x00000008u, 0x00000009u, 0x00000003u, 0x00040015u, 0x0000000Au,
|
||||
0x00000020u, 0x00000001u, 0x00040020u, 0x0000000Bu, 0x00000001u, 0x0000000Au, 0x0004003Bu,
|
||||
0x0000000Bu, 0x0000000Cu, 0x00000001u, 0x0004002Bu, 0x0000000Au, 0x0000000Eu, 0x00000001u,
|
||||
0x0004002Bu, 0x0000000Au, 0x00000010u, 0x00000002u, 0x00040017u, 0x00000017u, 0x00000006u,
|
||||
0x00000004u, 0x00040015u, 0x00000018u, 0x00000020u, 0x00000000u, 0x0004002Bu, 0x00000018u,
|
||||
0x00000019u, 0x00000001u, 0x0004001Cu, 0x0000001Au, 0x00000006u, 0x00000019u, 0x0006001Eu,
|
||||
0x0000001Bu, 0x00000017u, 0x00000006u, 0x0000001Au, 0x0000001Au, 0x00040020u, 0x0000001Cu,
|
||||
0x00000003u, 0x0000001Bu, 0x0004003Bu, 0x0000001Cu, 0x0000001Du, 0x00000003u, 0x0004002Bu,
|
||||
0x0000000Au, 0x0000001Eu, 0x00000000u, 0x0004002Bu, 0x00000006u, 0x00000020u, 0x40000000u,
|
||||
0x0004002Bu, 0x00000006u, 0x00000022u, 0x3F800000u, 0x0004002Bu, 0x00000006u, 0x00000025u,
|
||||
0x00000000u, 0x00040020u, 0x00000029u, 0x00000003u, 0x00000017u, 0x0005002Cu, 0x00000007u,
|
||||
0x0000002Bu, 0x00000022u, 0x00000022u, 0x00050036u, 0x00000002u, 0x00000004u, 0x00000000u,
|
||||
0x00000003u, 0x000200F8u, 0x00000005u, 0x0004003Du, 0x0000000Au, 0x0000000Du, 0x0000000Cu,
|
||||
0x000500C4u, 0x0000000Au, 0x0000000Fu, 0x0000000Du, 0x0000000Eu, 0x000500C7u, 0x0000000Au,
|
||||
0x00000011u, 0x0000000Fu, 0x00000010u, 0x0004006Fu, 0x00000006u, 0x00000012u, 0x00000011u,
|
||||
0x000500C7u, 0x0000000Au, 0x00000014u, 0x0000000Du, 0x00000010u, 0x0004006Fu, 0x00000006u,
|
||||
0x00000015u, 0x00000014u, 0x00050050u, 0x00000007u, 0x00000016u, 0x00000012u, 0x00000015u,
|
||||
0x0003003Eu, 0x00000009u, 0x00000016u, 0x0004003Du, 0x00000007u, 0x0000001Fu, 0x00000009u,
|
||||
0x0005008Eu, 0x00000007u, 0x00000021u, 0x0000001Fu, 0x00000020u, 0x00050083u, 0x00000007u,
|
||||
0x00000024u, 0x00000021u, 0x0000002Bu, 0x00050051u, 0x00000006u, 0x00000026u, 0x00000024u,
|
||||
0x00000000u, 0x00050051u, 0x00000006u, 0x00000027u, 0x00000024u, 0x00000001u, 0x00070050u,
|
||||
0x00000017u, 0x00000028u, 0x00000026u, 0x00000027u, 0x00000025u, 0x00000022u, 0x00050041u,
|
||||
0x00000029u, 0x0000002Au, 0x0000001Du, 0x0000001Eu, 0x0003003Eu, 0x0000002Au, 0x00000028u,
|
||||
0x000100FDu, 0x00010038u,
|
||||
}};
|
||||
|
||||
inline constexpr std::array<std::uint32_t, 360> hdr_extract_frag{{
|
||||
0x07230203u, 0x00010000u, 0x000D000Bu, 0x0000005Cu, 0x00000000u, 0x00020011u, 0x00000001u,
|
||||
0x0006000Bu, 0x00000001u, 0x4C534C47u, 0x6474732Eu, 0x3035342Eu, 0x00000000u, 0x0003000Eu,
|
||||
0x00000000u, 0x00000001u, 0x0007000Fu, 0x00000004u, 0x00000004u, 0x6E69616Du, 0x00000000u,
|
||||
0x0000001Du, 0x0000004Cu, 0x00030010u, 0x00000004u, 0x00000007u, 0x00040047u, 0x00000019u,
|
||||
0x00000021u, 0x00000000u, 0x00040047u, 0x00000019u, 0x00000022u, 0x00000000u, 0x00040047u,
|
||||
0x0000001Du, 0x0000001Eu, 0x00000000u, 0x00030047u, 0x00000029u, 0x00000002u, 0x00050048u,
|
||||
0x00000029u, 0x00000000u, 0x00000023u, 0x00000000u, 0x00050048u, 0x00000029u, 0x00000001u,
|
||||
0x00000023u, 0x00000004u, 0x00050048u, 0x00000029u, 0x00000002u, 0x00000023u, 0x00000008u,
|
||||
0x00040047u, 0x0000004Cu, 0x0000001Eu, 0x00000000u, 0x00020013u, 0x00000002u, 0x00030021u,
|
||||
0x00000003u, 0x00000002u, 0x00030016u, 0x00000006u, 0x00000020u, 0x00040017u, 0x00000007u,
|
||||
0x00000006u, 0x00000003u, 0x0004002Bu, 0x00000006u, 0x0000000Eu, 0x3E59B3D0u, 0x0004002Bu,
|
||||
0x00000006u, 0x0000000Fu, 0x3F371759u, 0x0004002Bu, 0x00000006u, 0x00000010u, 0x3D93DD98u,
|
||||
0x0006002Cu, 0x00000007u, 0x00000011u, 0x0000000Eu, 0x0000000Fu, 0x00000010u, 0x00090019u,
|
||||
0x00000016u, 0x00000006u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u,
|
||||
0x00000000u, 0x0003001Bu, 0x00000017u, 0x00000016u, 0x00040020u, 0x00000018u, 0x00000000u,
|
||||
0x00000017u, 0x0004003Bu, 0x00000018u, 0x00000019u, 0x00000000u, 0x00040017u, 0x0000001Bu,
|
||||
0x00000006u, 0x00000002u, 0x00040020u, 0x0000001Cu, 0x00000001u, 0x0000001Bu, 0x0004003Bu,
|
||||
0x0000001Cu, 0x0000001Du, 0x00000001u, 0x00040017u, 0x0000001Fu, 0x00000006u, 0x00000004u,
|
||||
0x0005001Eu, 0x00000029u, 0x00000006u, 0x00000006u, 0x00000006u, 0x00040020u, 0x0000002Au,
|
||||
0x00000009u, 0x00000029u, 0x0004003Bu, 0x0000002Au, 0x0000002Bu, 0x00000009u, 0x00040015u,
|
||||
0x0000002Cu, 0x00000020u, 0x00000001u, 0x0004002Bu, 0x0000002Cu, 0x0000002Du, 0x00000000u,
|
||||
0x00040020u, 0x0000002Eu, 0x00000009u, 0x00000006u, 0x0004002Bu, 0x00000006u, 0x00000034u,
|
||||
0x3A83126Fu, 0x0004002Bu, 0x00000006u, 0x00000039u, 0x00000000u, 0x0004002Bu, 0x0000002Cu,
|
||||
0x0000003Bu, 0x00000001u, 0x0004002Bu, 0x0000002Cu, 0x00000046u, 0x00000002u, 0x00040020u,
|
||||
0x0000004Bu, 0x00000003u, 0x0000001Fu, 0x0004003Bu, 0x0000004Bu, 0x0000004Cu, 0x00000003u,
|
||||
0x0004002Bu, 0x00000006u, 0x0000004Eu, 0x3F800000u, 0x0006002Cu, 0x00000007u, 0x0000005Au,
|
||||
0x00000039u, 0x00000039u, 0x00000039u, 0x0006002Cu, 0x00000007u, 0x0000005Bu, 0x0000004Eu,
|
||||
0x0000004Eu, 0x0000004Eu, 0x00050036u, 0x00000002u, 0x00000004u, 0x00000000u, 0x00000003u,
|
||||
0x000200F8u, 0x00000005u, 0x0004003Du, 0x00000017u, 0x0000001Au, 0x00000019u, 0x0004003Du,
|
||||
0x0000001Bu, 0x0000001Eu, 0x0000001Du, 0x00050057u, 0x0000001Fu, 0x00000020u, 0x0000001Au,
|
||||
0x0000001Eu, 0x0008004Fu, 0x00000007u, 0x00000021u, 0x00000020u, 0x00000020u, 0x00000000u,
|
||||
0x00000001u, 0x00000002u, 0x00050094u, 0x00000006u, 0x00000059u, 0x00000021u, 0x00000011u,
|
||||
0x0006000Cu, 0x00000007u, 0x00000028u, 0x00000001u, 0x00000004u, 0x00000021u, 0x00050041u,
|
||||
0x0000002Eu, 0x0000002Fu, 0x0000002Bu, 0x0000002Du, 0x0004003Du, 0x00000006u, 0x00000030u,
|
||||
0x0000002Fu, 0x00060050u, 0x00000007u, 0x00000031u, 0x00000030u, 0x00000030u, 0x00000030u,
|
||||
0x0007000Cu, 0x00000007u, 0x00000032u, 0x00000001u, 0x0000001Au, 0x00000028u, 0x00000031u,
|
||||
0x0007000Cu, 0x00000006u, 0x00000035u, 0x00000001u, 0x00000028u, 0x00000059u, 0x00000034u,
|
||||
0x00060050u, 0x00000007u, 0x00000036u, 0x00000035u, 0x00000035u, 0x00000035u, 0x00050088u,
|
||||
0x00000007u, 0x00000037u, 0x00000032u, 0x00000036u, 0x00050041u, 0x0000002Eu, 0x0000003Cu,
|
||||
0x0000002Bu, 0x0000003Bu, 0x0004003Du, 0x00000006u, 0x0000003Du, 0x0000003Cu, 0x00050083u,
|
||||
0x00000006u, 0x0000003Eu, 0x00000059u, 0x0000003Du, 0x0007000Cu, 0x00000006u, 0x0000003Fu,
|
||||
0x00000001u, 0x00000028u, 0x00000039u, 0x0000003Eu, 0x0005008Eu, 0x00000007u, 0x00000042u,
|
||||
0x00000037u, 0x0000003Fu, 0x00060050u, 0x00000007u, 0x00000044u, 0x0000003Fu, 0x0000003Fu,
|
||||
0x0000003Fu, 0x00050041u, 0x0000002Eu, 0x00000047u, 0x0000002Bu, 0x00000046u, 0x0004003Du,
|
||||
0x00000006u, 0x00000048u, 0x00000047u, 0x00060050u, 0x00000007u, 0x00000049u, 0x00000048u,
|
||||
0x00000048u, 0x00000048u, 0x0008000Cu, 0x00000007u, 0x0000004Au, 0x00000001u, 0x0000002Eu,
|
||||
0x00000044u, 0x00000042u, 0x00000049u, 0x0008000Cu, 0x00000007u, 0x00000051u, 0x00000001u,
|
||||
0x0000002Bu, 0x0000004Au, 0x0000005Au, 0x0000005Bu, 0x00050051u, 0x00000006u, 0x00000052u,
|
||||
0x00000051u, 0x00000000u, 0x00050051u, 0x00000006u, 0x00000053u, 0x00000051u, 0x00000001u,
|
||||
0x00050051u, 0x00000006u, 0x00000054u, 0x00000051u, 0x00000002u, 0x00070050u, 0x0000001Fu,
|
||||
0x00000055u, 0x00000052u, 0x00000053u, 0x00000054u, 0x00000039u, 0x0003003Eu, 0x0000004Cu,
|
||||
0x00000055u, 0x000100FDu, 0x00010038u,
|
||||
}};
|
||||
|
||||
inline constexpr std::array<std::uint32_t, 299> hdr_blur_frag{{
|
||||
0x07230203u, 0x00010000u, 0x000D000Bu, 0x00000048u, 0x00000000u, 0x00020011u, 0x00000001u,
|
||||
0x0006000Bu, 0x00000001u, 0x4C534C47u, 0x6474732Eu, 0x3035342Eu, 0x00000000u, 0x0003000Eu,
|
||||
0x00000000u, 0x00000001u, 0x0007000Fu, 0x00000004u, 0x00000004u, 0x6E69616Du, 0x00000000u,
|
||||
0x0000002Du, 0x00000044u, 0x00030010u, 0x00000004u, 0x00000007u, 0x00040047u, 0x0000001Eu,
|
||||
0x00000006u, 0x00000010u, 0x00030047u, 0x0000001Fu, 0x00000002u, 0x00050048u, 0x0000001Fu,
|
||||
0x00000000u, 0x00000023u, 0x00000000u, 0x00040047u, 0x0000002Au, 0x00000021u, 0x00000000u,
|
||||
0x00040047u, 0x0000002Au, 0x00000022u, 0x00000000u, 0x00040047u, 0x0000002Du, 0x0000001Eu,
|
||||
0x00000000u, 0x00040047u, 0x00000044u, 0x0000001Eu, 0x00000000u, 0x00020013u, 0x00000002u,
|
||||
0x00030021u, 0x00000003u, 0x00000002u, 0x00030016u, 0x00000006u, 0x00000020u, 0x00040017u,
|
||||
0x00000007u, 0x00000006u, 0x00000004u, 0x0004002Bu, 0x00000006u, 0x0000000Au, 0x00000000u,
|
||||
0x0007002Cu, 0x00000007u, 0x0000000Bu, 0x0000000Au, 0x0000000Au, 0x0000000Au, 0x0000000Au,
|
||||
0x00040015u, 0x0000000Cu, 0x00000020u, 0x00000001u, 0x0004002Bu, 0x0000000Cu, 0x0000000Fu,
|
||||
0x00000000u, 0x0004002Bu, 0x0000000Cu, 0x00000016u, 0x00000004u, 0x00020014u, 0x00000017u,
|
||||
0x00040017u, 0x00000019u, 0x00000006u, 0x00000002u, 0x00040015u, 0x0000001Cu, 0x00000020u,
|
||||
0x00000000u, 0x0004002Bu, 0x0000001Cu, 0x0000001Du, 0x00000004u, 0x0004001Cu, 0x0000001Eu,
|
||||
0x00000007u, 0x0000001Du, 0x0003001Eu, 0x0000001Fu, 0x0000001Eu, 0x00040020u, 0x00000020u,
|
||||
0x00000009u, 0x0000001Fu, 0x0004003Bu, 0x00000020u, 0x00000021u, 0x00000009u, 0x00040020u,
|
||||
0x00000023u, 0x00000009u, 0x00000007u, 0x00090019u, 0x00000027u, 0x00000006u, 0x00000001u,
|
||||
0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x0003001Bu, 0x00000028u,
|
||||
0x00000027u, 0x00040020u, 0x00000029u, 0x00000000u, 0x00000028u, 0x0004003Bu, 0x00000029u,
|
||||
0x0000002Au, 0x00000000u, 0x00040020u, 0x0000002Cu, 0x00000001u, 0x00000019u, 0x0004003Bu,
|
||||
0x0000002Cu, 0x0000002Du, 0x00000001u, 0x0004002Bu, 0x0000001Cu, 0x00000039u, 0x00000002u,
|
||||
0x00040020u, 0x0000003Au, 0x00000009u, 0x00000006u, 0x0004002Bu, 0x0000000Cu, 0x00000041u,
|
||||
0x00000001u, 0x00040020u, 0x00000043u, 0x00000003u, 0x00000007u, 0x0004003Bu, 0x00000043u,
|
||||
0x00000044u, 0x00000003u, 0x00050036u, 0x00000002u, 0x00000004u, 0x00000000u, 0x00000003u,
|
||||
0x000200F8u, 0x00000005u, 0x000200F9u, 0x00000010u, 0x000200F8u, 0x00000010u, 0x000700F5u,
|
||||
0x00000007u, 0x00000047u, 0x0000000Bu, 0x00000005u, 0x0000003Fu, 0x00000011u, 0x000700F5u,
|
||||
0x0000000Cu, 0x00000046u, 0x0000000Fu, 0x00000005u, 0x00000042u, 0x00000011u, 0x000500B1u,
|
||||
0x00000017u, 0x00000018u, 0x00000046u, 0x00000016u, 0x000400F6u, 0x00000012u, 0x00000011u,
|
||||
0x00000000u, 0x000400FAu, 0x00000018u, 0x00000011u, 0x00000012u, 0x000200F8u, 0x00000011u,
|
||||
0x00060041u, 0x00000023u, 0x00000024u, 0x00000021u, 0x0000000Fu, 0x00000046u, 0x0004003Du,
|
||||
0x00000007u, 0x00000025u, 0x00000024u, 0x0007004Fu, 0x00000019u, 0x00000026u, 0x00000025u,
|
||||
0x00000025u, 0x00000000u, 0x00000001u, 0x0004003Du, 0x00000028u, 0x0000002Bu, 0x0000002Au,
|
||||
0x0004003Du, 0x00000019u, 0x0000002Eu, 0x0000002Du, 0x00050081u, 0x00000019u, 0x00000030u,
|
||||
0x0000002Eu, 0x00000026u, 0x00050057u, 0x00000007u, 0x00000031u, 0x0000002Bu, 0x00000030u,
|
||||
0x0004003Du, 0x00000028u, 0x00000032u, 0x0000002Au, 0x00050083u, 0x00000019u, 0x00000035u,
|
||||
0x0000002Eu, 0x00000026u, 0x00050057u, 0x00000007u, 0x00000036u, 0x00000032u, 0x00000035u,
|
||||
0x00050081u, 0x00000007u, 0x00000037u, 0x00000031u, 0x00000036u, 0x00070041u, 0x0000003Au,
|
||||
0x0000003Bu, 0x00000021u, 0x0000000Fu, 0x00000046u, 0x00000039u, 0x0004003Du, 0x00000006u,
|
||||
0x0000003Cu, 0x0000003Bu, 0x0005008Eu, 0x00000007u, 0x0000003Du, 0x00000037u, 0x0000003Cu,
|
||||
0x00050081u, 0x00000007u, 0x0000003Fu, 0x00000047u, 0x0000003Du, 0x00050080u, 0x0000000Cu,
|
||||
0x00000042u, 0x00000046u, 0x00000041u, 0x000200F9u, 0x00000010u, 0x000200F8u, 0x00000012u,
|
||||
0x0003003Eu, 0x00000044u, 0x00000047u, 0x000100FDu, 0x00010038u,
|
||||
}};
|
||||
|
||||
inline constexpr std::array<std::uint32_t, 372> hdr_combine_frag{{
|
||||
0x07230203u, 0x00010000u, 0x000D000Bu, 0x0000004Au, 0x00000000u, 0x00020011u, 0x00000001u,
|
||||
0x0006000Bu, 0x00000001u, 0x4C534C47u, 0x6474732Eu, 0x3035342Eu, 0x00000000u, 0x0003000Eu,
|
||||
0x00000000u, 0x00000001u, 0x0007000Fu, 0x00000004u, 0x00000004u, 0x6E69616Du, 0x00000000u,
|
||||
0x00000011u, 0x0000003Au, 0x00030010u, 0x00000004u, 0x00000007u, 0x00040047u, 0x0000000Du,
|
||||
0x00000021u, 0x00000000u, 0x00040047u, 0x0000000Du, 0x00000022u, 0x00000000u, 0x00040047u,
|
||||
0x00000011u, 0x0000001Eu, 0x00000000u, 0x00040047u, 0x00000016u, 0x00000021u, 0x00000001u,
|
||||
0x00040047u, 0x00000016u, 0x00000022u, 0x00000000u, 0x00040047u, 0x0000001Du, 0x00000021u,
|
||||
0x00000002u, 0x00040047u, 0x0000001Du, 0x00000022u, 0x00000000u, 0x00040047u, 0x00000024u,
|
||||
0x00000021u, 0x00000003u, 0x00040047u, 0x00000024u, 0x00000022u, 0x00000000u, 0x00040047u,
|
||||
0x0000002Bu, 0x00000021u, 0x00000004u, 0x00040047u, 0x0000002Bu, 0x00000022u, 0x00000000u,
|
||||
0x00040047u, 0x00000032u, 0x00000021u, 0x00000005u, 0x00040047u, 0x00000032u, 0x00000022u,
|
||||
0x00000000u, 0x00040047u, 0x0000003Au, 0x0000001Eu, 0x00000000u, 0x00030047u, 0x0000003Cu,
|
||||
0x00000002u, 0x00050048u, 0x0000003Cu, 0x00000000u, 0x00000023u, 0x00000000u, 0x00020013u,
|
||||
0x00000002u, 0x00030021u, 0x00000003u, 0x00000002u, 0x00030016u, 0x00000006u, 0x00000020u,
|
||||
0x00040017u, 0x00000007u, 0x00000006u, 0x00000003u, 0x00090019u, 0x0000000Au, 0x00000006u,
|
||||
0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x0003001Bu,
|
||||
0x0000000Bu, 0x0000000Au, 0x00040020u, 0x0000000Cu, 0x00000000u, 0x0000000Bu, 0x0004003Bu,
|
||||
0x0000000Cu, 0x0000000Du, 0x00000000u, 0x00040017u, 0x0000000Fu, 0x00000006u, 0x00000002u,
|
||||
0x00040020u, 0x00000010u, 0x00000001u, 0x0000000Fu, 0x0004003Bu, 0x00000010u, 0x00000011u,
|
||||
0x00000001u, 0x00040017u, 0x00000013u, 0x00000006u, 0x00000004u, 0x0004003Bu, 0x0000000Cu,
|
||||
0x00000016u, 0x00000000u, 0x0004003Bu, 0x0000000Cu, 0x0000001Du, 0x00000000u, 0x0004003Bu,
|
||||
0x0000000Cu, 0x00000024u, 0x00000000u, 0x0004003Bu, 0x0000000Cu, 0x0000002Bu, 0x00000000u,
|
||||
0x0004003Bu, 0x0000000Cu, 0x00000032u, 0x00000000u, 0x00040020u, 0x00000039u, 0x00000003u,
|
||||
0x00000013u, 0x0004003Bu, 0x00000039u, 0x0000003Au, 0x00000003u, 0x0003001Eu, 0x0000003Cu,
|
||||
0x00000006u, 0x00040020u, 0x0000003Du, 0x00000009u, 0x0000003Cu, 0x0004003Bu, 0x0000003Du,
|
||||
0x0000003Eu, 0x00000009u, 0x00040015u, 0x0000003Fu, 0x00000020u, 0x00000001u, 0x0004002Bu,
|
||||
0x0000003Fu, 0x00000040u, 0x00000000u, 0x00040020u, 0x00000041u, 0x00000009u, 0x00000006u,
|
||||
0x0004002Bu, 0x00000006u, 0x00000045u, 0x00000000u, 0x00050036u, 0x00000002u, 0x00000004u,
|
||||
0x00000000u, 0x00000003u, 0x000200F8u, 0x00000005u, 0x0004003Du, 0x0000000Bu, 0x0000000Eu,
|
||||
0x0000000Du, 0x0004003Du, 0x0000000Fu, 0x00000012u, 0x00000011u, 0x00050057u, 0x00000013u,
|
||||
0x00000014u, 0x0000000Eu, 0x00000012u, 0x0008004Fu, 0x00000007u, 0x00000015u, 0x00000014u,
|
||||
0x00000014u, 0x00000000u, 0x00000001u, 0x00000002u, 0x0004003Du, 0x0000000Bu, 0x00000017u,
|
||||
0x00000016u, 0x00050057u, 0x00000013u, 0x00000019u, 0x00000017u, 0x00000012u, 0x0008004Fu,
|
||||
0x00000007u, 0x0000001Au, 0x00000019u, 0x00000019u, 0x00000000u, 0x00000001u, 0x00000002u,
|
||||
0x00050081u, 0x00000007u, 0x0000001Cu, 0x00000015u, 0x0000001Au, 0x0004003Du, 0x0000000Bu,
|
||||
0x0000001Eu, 0x0000001Du, 0x00050057u, 0x00000013u, 0x00000020u, 0x0000001Eu, 0x00000012u,
|
||||
0x0008004Fu, 0x00000007u, 0x00000021u, 0x00000020u, 0x00000020u, 0x00000000u, 0x00000001u,
|
||||
0x00000002u, 0x00050081u, 0x00000007u, 0x00000023u, 0x0000001Cu, 0x00000021u, 0x0004003Du,
|
||||
0x0000000Bu, 0x00000025u, 0x00000024u, 0x00050057u, 0x00000013u, 0x00000027u, 0x00000025u,
|
||||
0x00000012u, 0x0008004Fu, 0x00000007u, 0x00000028u, 0x00000027u, 0x00000027u, 0x00000000u,
|
||||
0x00000001u, 0x00000002u, 0x00050081u, 0x00000007u, 0x0000002Au, 0x00000023u, 0x00000028u,
|
||||
0x0004003Du, 0x0000000Bu, 0x0000002Cu, 0x0000002Bu, 0x00050057u, 0x00000013u, 0x0000002Eu,
|
||||
0x0000002Cu, 0x00000012u, 0x0008004Fu, 0x00000007u, 0x0000002Fu, 0x0000002Eu, 0x0000002Eu,
|
||||
0x00000000u, 0x00000001u, 0x00000002u, 0x00050081u, 0x00000007u, 0x00000031u, 0x0000002Au,
|
||||
0x0000002Fu, 0x0004003Du, 0x0000000Bu, 0x00000033u, 0x00000032u, 0x00050057u, 0x00000013u,
|
||||
0x00000035u, 0x00000033u, 0x00000012u, 0x0008004Fu, 0x00000007u, 0x00000036u, 0x00000035u,
|
||||
0x00000035u, 0x00000000u, 0x00000001u, 0x00000002u, 0x00050081u, 0x00000007u, 0x00000038u,
|
||||
0x00000031u, 0x00000036u, 0x00050041u, 0x00000041u, 0x00000042u, 0x0000003Eu, 0x00000040u,
|
||||
0x0004003Du, 0x00000006u, 0x00000043u, 0x00000042u, 0x0005008Eu, 0x00000007u, 0x00000044u,
|
||||
0x00000038u, 0x00000043u, 0x00050051u, 0x00000006u, 0x00000046u, 0x00000044u, 0x00000000u,
|
||||
0x00050051u, 0x00000006u, 0x00000047u, 0x00000044u, 0x00000001u, 0x00050051u, 0x00000006u,
|
||||
0x00000048u, 0x00000044u, 0x00000002u, 0x00070050u, 0x00000013u, 0x00000049u, 0x00000046u,
|
||||
0x00000047u, 0x00000048u, 0x00000045u, 0x0003003Eu, 0x0000003Au, 0x00000049u, 0x000100FDu,
|
||||
0x00010038u,
|
||||
}};
|
||||
|
||||
inline constexpr std::array<std::uint32_t, 1320> hdr_composite_frag{{
|
||||
0x07230203u, 0x00010000u, 0x000D000Bu, 0x000001F3u, 0x00000000u, 0x00020011u, 0x00000001u,
|
||||
0x0006000Bu, 0x00000001u, 0x4C534C47u, 0x6474732Eu, 0x3035342Eu, 0x00000000u, 0x0003000Eu,
|
||||
0x00000000u, 0x00000001u, 0x0007000Fu, 0x00000004u, 0x00000004u, 0x6E69616Du, 0x00000000u,
|
||||
0x000000DBu, 0x00000162u, 0x00030010u, 0x00000004u, 0x00000007u, 0x00030047u, 0x0000005Bu,
|
||||
0x00000002u, 0x00050048u, 0x0000005Bu, 0x00000000u, 0x00000023u, 0x00000000u, 0x00050048u,
|
||||
0x0000005Bu, 0x00000001u, 0x00000023u, 0x00000010u, 0x00050048u, 0x0000005Bu, 0x00000002u,
|
||||
0x00000023u, 0x00000020u, 0x00050048u, 0x0000005Bu, 0x00000003u, 0x00000023u, 0x00000028u,
|
||||
0x00050048u, 0x0000005Bu, 0x00000004u, 0x00000023u, 0x0000002Cu, 0x00050048u, 0x0000005Bu,
|
||||
0x00000005u, 0x00000023u, 0x00000030u, 0x00050048u, 0x0000005Bu, 0x00000006u, 0x00000023u,
|
||||
0x00000034u, 0x00050048u, 0x0000005Bu, 0x00000007u, 0x00000023u, 0x00000038u, 0x00050048u,
|
||||
0x0000005Bu, 0x00000008u, 0x00000023u, 0x0000003Cu, 0x00050048u, 0x0000005Bu, 0x00000009u,
|
||||
0x00000023u, 0x00000040u, 0x00050048u, 0x0000005Bu, 0x0000000Au, 0x00000023u, 0x00000044u,
|
||||
0x00050048u, 0x0000005Bu, 0x0000000Bu, 0x00000023u, 0x00000048u, 0x00050048u, 0x0000005Bu,
|
||||
0x0000000Cu, 0x00000023u, 0x0000004Cu, 0x00040047u, 0x000000D8u, 0x00000021u, 0x00000001u,
|
||||
0x00040047u, 0x000000D8u, 0x00000022u, 0x00000000u, 0x00040047u, 0x000000DBu, 0x0000001Eu,
|
||||
0x00000000u, 0x00040047u, 0x000000FFu, 0x00000021u, 0x00000000u, 0x00040047u, 0x000000FFu,
|
||||
0x00000022u, 0x00000000u, 0x00040047u, 0x00000162u, 0x0000001Eu, 0x00000000u, 0x00020013u,
|
||||
0x00000002u, 0x00030021u, 0x00000003u, 0x00000002u, 0x00030016u, 0x00000006u, 0x00000020u,
|
||||
0x00040017u, 0x00000007u, 0x00000006u, 0x00000003u, 0x00040017u, 0x0000000Du, 0x00000006u,
|
||||
0x00000002u, 0x0004002Bu, 0x00000006u, 0x00000022u, 0x3E59B3D0u, 0x0004002Bu, 0x00000006u,
|
||||
0x00000023u, 0x3F371759u, 0x0004002Bu, 0x00000006u, 0x00000024u, 0x3D93DD98u, 0x0006002Cu,
|
||||
0x00000007u, 0x00000025u, 0x00000022u, 0x00000023u, 0x00000024u, 0x00040015u, 0x0000002Au,
|
||||
0x00000020u, 0x00000000u, 0x0004002Bu, 0x0000002Au, 0x0000002Bu, 0x00000000u, 0x0004002Bu,
|
||||
0x00000006u, 0x0000002Eu, 0x3D897143u, 0x0004002Bu, 0x0000002Au, 0x00000030u, 0x00000001u,
|
||||
0x0004002Bu, 0x00000006u, 0x00000033u, 0x3BBF4590u, 0x0004002Bu, 0x00000006u, 0x00000036u,
|
||||
0x4253EE82u, 0x0004002Bu, 0x00000006u, 0x00000038u, 0x00000000u, 0x0004002Bu, 0x00000006u,
|
||||
0x00000039u, 0x3EA2F984u, 0x0004002Bu, 0x00000006u, 0x0000003Au, 0x3F22F984u, 0x0006002Cu,
|
||||
0x00000007u, 0x0000003Bu, 0x00000038u, 0x00000039u, 0x0000003Au, 0x0004002Bu, 0x00000006u,
|
||||
0x00000047u, 0x358637BDu, 0x0004002Bu, 0x0000002Au, 0x0000004Cu, 0x00000002u, 0x00040017u,
|
||||
0x00000059u, 0x00000006u, 0x00000004u, 0x00040015u, 0x0000005Au, 0x00000020u, 0x00000001u,
|
||||
0x000F001Eu, 0x0000005Bu, 0x00000059u, 0x00000059u, 0x0000000Du, 0x00000006u, 0x00000006u,
|
||||
0x00000006u, 0x00000006u, 0x00000006u, 0x00000006u, 0x00000006u, 0x00000006u, 0x00000006u,
|
||||
0x0000005Au, 0x00040020u, 0x0000005Cu, 0x00000009u, 0x0000005Bu, 0x0004003Bu, 0x0000005Cu,
|
||||
0x0000005Du, 0x00000009u, 0x0004002Bu, 0x0000005Au, 0x0000005Eu, 0x00000000u, 0x00040020u,
|
||||
0x0000005Fu, 0x00000009u, 0x00000006u, 0x0004002Bu, 0x0000005Au, 0x0000006Eu, 0x00000001u,
|
||||
0x0004002Bu, 0x00000006u, 0x0000008Eu, 0x3CC9590Fu, 0x0004002Bu, 0x00000006u, 0x00000092u,
|
||||
0x38BDDEAFu, 0x0004002Bu, 0x00000006u, 0x00000097u, 0x3F7BD5AAu, 0x0004002Bu, 0x00000006u,
|
||||
0x0000009Au, 0x3EDDABC1u, 0x0004002Bu, 0x00000006u, 0x0000009Eu, 0x3E73CB81u, 0x0004002Bu,
|
||||
0x00000006u, 0x000000A7u, 0x3F000000u, 0x00040018u, 0x000000ABu, 0x00000007u, 0x00000003u,
|
||||
0x0004002Bu, 0x00000006u, 0x000000ACu, 0x3F18E172u, 0x0004002Bu, 0x00000006u, 0x000000ADu,
|
||||
0x3D9BA5E3u, 0x0004002Bu, 0x00000006u, 0x000000AEu, 0x3CE8A71Eu, 0x0006002Cu, 0x00000007u,
|
||||
0x000000AFu, 0x000000ACu, 0x000000ADu, 0x000000AEu, 0x0004002Bu, 0x00000006u, 0x000000B0u,
|
||||
0x3EB58B82u, 0x0004002Bu, 0x00000006u, 0x000000B1u, 0x3F6888F8u, 0x0004002Bu, 0x00000006u,
|
||||
0x000000B2u, 0x3E090ABBu, 0x0006002Cu, 0x00000007u, 0x000000B3u, 0x000000B0u, 0x000000B1u,
|
||||
0x000000B2u, 0x0004002Bu, 0x00000006u, 0x000000B4u, 0x3D458CD2u, 0x0004002Bu, 0x00000006u,
|
||||
0x000000B5u, 0x3C804966u, 0x0004002Bu, 0x00000006u, 0x000000B6u, 0x3F567818u, 0x0006002Cu,
|
||||
0x00000007u, 0x000000B7u, 0x000000B4u, 0x000000B5u, 0x000000B6u, 0x0006002Cu, 0x000000ABu,
|
||||
0x000000B8u, 0x000000AFu, 0x000000B3u, 0x000000B7u, 0x0004002Bu, 0x00000006u, 0x000000BEu,
|
||||
0x3FCD6873u, 0x0004002Bu, 0x00000006u, 0x000000BFu, 0xBDD10F52u, 0x0004002Bu, 0x00000006u,
|
||||
0x000000C0u, 0xBB564D7Fu, 0x0006002Cu, 0x00000007u, 0x000000C1u, 0x000000BEu, 0x000000BFu,
|
||||
0x000000C0u, 0x0004002Bu, 0x00000006u, 0x000000C2u, 0xBF07F4DCu, 0x0004002Bu, 0x00000006u,
|
||||
0x000000C3u, 0x3F8DD734u, 0x0004002Bu, 0x00000006u, 0x000000C4u, 0xBD950332u, 0x0006002Cu,
|
||||
0x00000007u, 0x000000C5u, 0x000000C2u, 0x000000C3u, 0x000000C4u, 0x0004002Bu, 0x00000006u,
|
||||
0x000000C6u, 0xBD96E04Cu, 0x0004002Bu, 0x00000006u, 0x000000C7u, 0xBBC63F14u, 0x0004002Bu,
|
||||
0x00000006u, 0x000000C8u, 0x3F89BB06u, 0x0006002Cu, 0x00000007u, 0x000000C9u, 0x000000C6u,
|
||||
0x000000C7u, 0x000000C8u, 0x0006002Cu, 0x000000ABu, 0x000000CAu, 0x000000C1u, 0x000000C5u,
|
||||
0x000000C9u, 0x0004002Bu, 0x0000005Au, 0x000000CEu, 0x0000000Bu, 0x00090019u, 0x000000D5u,
|
||||
0x00000006u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u,
|
||||
0x0003001Bu, 0x000000D6u, 0x000000D5u, 0x00040020u, 0x000000D7u, 0x00000000u, 0x000000D6u,
|
||||
0x0004003Bu, 0x000000D7u, 0x000000D8u, 0x00000000u, 0x00040020u, 0x000000DAu, 0x00000001u,
|
||||
0x0000000Du, 0x0004003Bu, 0x000000DAu, 0x000000DBu, 0x00000001u, 0x0004002Bu, 0x0000005Au,
|
||||
0x000000E1u, 0x00000002u, 0x00040020u, 0x000000E2u, 0x00000009u, 0x0000000Du, 0x0004002Bu,
|
||||
0x00000006u, 0x000000EAu, 0x3DCCCCCDu, 0x0004002Bu, 0x0000005Au, 0x000000F0u, 0x00000003u,
|
||||
0x0004002Bu, 0x00000006u, 0x000000F5u, 0x3F800000u, 0x0004002Bu, 0x0000005Au, 0x000000F9u,
|
||||
0x00000004u, 0x0004003Bu, 0x000000D7u, 0x000000FFu, 0x00000000u, 0x0004002Bu, 0x0000005Au,
|
||||
0x00000104u, 0x0000000Cu, 0x00040020u, 0x00000105u, 0x00000009u, 0x0000005Au, 0x00020014u,
|
||||
0x00000108u, 0x0004002Bu, 0x0000005Au, 0x00000111u, 0x00000009u, 0x0004002Bu, 0x0000005Au,
|
||||
0x00000118u, 0x00000007u, 0x0006002Cu, 0x00000007u, 0x0000011Du, 0x00000038u, 0x00000038u,
|
||||
0x00000038u, 0x0004002Bu, 0x0000005Au, 0x00000123u, 0x00000005u, 0x0004002Bu, 0x00000006u,
|
||||
0x00000126u, 0x3A83126Fu, 0x0004002Bu, 0x0000005Au, 0x0000013Du, 0x00000006u, 0x0004002Bu,
|
||||
0x0000005Au, 0x0000014Eu, 0x00000008u, 0x0004002Bu, 0x0000005Au, 0x0000015Bu, 0x0000000Au,
|
||||
0x00040020u, 0x00000161u, 0x00000003u, 0x00000059u, 0x0004003Bu, 0x00000161u, 0x00000162u,
|
||||
0x00000003u, 0x0006002Cu, 0x00000007u, 0x000001ECu, 0x000000EAu, 0x000000EAu, 0x000000EAu,
|
||||
0x0006002Cu, 0x00000007u, 0x000001EDu, 0x000000F5u, 0x000000F5u, 0x000000F5u, 0x0006002Cu,
|
||||
0x00000007u, 0x000001EEu, 0x0000008Eu, 0x0000008Eu, 0x0000008Eu, 0x0006002Cu, 0x00000007u,
|
||||
0x000001EFu, 0x00000092u, 0x00000092u, 0x00000092u, 0x0006002Cu, 0x00000007u, 0x000001F0u,
|
||||
0x0000009Au, 0x0000009Au, 0x0000009Au, 0x0006002Cu, 0x00000007u, 0x000001F1u, 0x0000009Eu,
|
||||
0x0000009Eu, 0x0000009Eu, 0x0006002Cu, 0x00000007u, 0x000001F2u, 0x000000A7u, 0x000000A7u,
|
||||
0x000000A7u, 0x00050036u, 0x00000002u, 0x00000004u, 0x00000000u, 0x00000003u, 0x000200F8u,
|
||||
0x00000005u, 0x0004003Du, 0x000000D6u, 0x000000D9u, 0x000000D8u, 0x0004003Du, 0x0000000Du,
|
||||
0x000000DCu, 0x000000DBu, 0x00050057u, 0x00000059u, 0x000000DDu, 0x000000D9u, 0x000000DCu,
|
||||
0x0008004Fu, 0x00000007u, 0x000000DEu, 0x000000DDu, 0x000000DDu, 0x00000000u, 0x00000001u,
|
||||
0x00000002u, 0x00050041u, 0x000000E2u, 0x000000E3u, 0x0000005Du, 0x000000E1u, 0x0004003Du,
|
||||
0x0000000Du, 0x000000E4u, 0x000000E3u, 0x00050085u, 0x0000000Du, 0x000000E5u, 0x000000DCu,
|
||||
0x000000E4u, 0x00050051u, 0x00000006u, 0x0000016Cu, 0x000000E5u, 0x00000000u, 0x00050085u,
|
||||
0x00000006u, 0x0000016Du, 0x0000016Cu, 0x0000002Eu, 0x00050051u, 0x00000006u, 0x0000016Fu,
|
||||
0x000000E5u, 0x00000001u, 0x00050085u, 0x00000006u, 0x00000170u, 0x0000016Fu, 0x00000033u,
|
||||
0x00050081u, 0x00000006u, 0x00000171u, 0x0000016Du, 0x00000170u, 0x00060050u, 0x00000007u,
|
||||
0x00000173u, 0x00000171u, 0x00000171u, 0x00000171u, 0x00050081u, 0x00000007u, 0x00000174u,
|
||||
0x00000173u, 0x0000003Bu, 0x0006000Cu, 0x00000007u, 0x00000175u, 0x00000001u, 0x0000000Au,
|
||||
0x00000174u, 0x0005008Eu, 0x00000007u, 0x00000176u, 0x00000175u, 0x00000036u, 0x0006000Cu,
|
||||
0x00000007u, 0x00000177u, 0x00000001u, 0x0000000Au, 0x00000176u, 0x0008000Cu, 0x00000007u,
|
||||
0x000000EEu, 0x00000001u, 0x00000031u, 0x0000011Du, 0x000001ECu, 0x000000DEu, 0x00050085u,
|
||||
0x00000007u, 0x000000EFu, 0x00000177u, 0x000000EEu, 0x00050041u, 0x0000005Fu, 0x000000F1u,
|
||||
0x0000005Du, 0x000000F0u, 0x0004003Du, 0x00000006u, 0x000000F2u, 0x000000F1u, 0x0005008Eu,
|
||||
0x00000007u, 0x000000F3u, 0x000000EFu, 0x000000F2u, 0x00050081u, 0x00000007u, 0x000000F4u,
|
||||
0x000000DEu, 0x000000F3u, 0x0008000Cu, 0x00000007u, 0x000000F8u, 0x00000001u, 0x0000002Bu,
|
||||
0x000000F4u, 0x0000011Du, 0x000001EDu, 0x00050041u, 0x0000005Fu, 0x000000FAu, 0x0000005Du,
|
||||
0x000000F9u, 0x0004003Du, 0x00000006u, 0x000000FBu, 0x000000FAu, 0x0005008Eu, 0x00000007u,
|
||||
0x000000FDu, 0x000000F8u, 0x000000FBu, 0x0004003Du, 0x000000D6u, 0x00000100u, 0x000000FFu,
|
||||
0x00050057u, 0x00000059u, 0x00000102u, 0x00000100u, 0x000000DCu, 0x0008004Fu, 0x00000007u,
|
||||
0x00000103u, 0x00000102u, 0x00000102u, 0x00000000u, 0x00000001u, 0x00000002u, 0x00050041u,
|
||||
0x00000105u, 0x00000106u, 0x0000005Du, 0x00000104u, 0x0004003Du, 0x0000005Au, 0x00000107u,
|
||||
0x00000106u, 0x000500AAu, 0x00000108u, 0x00000109u, 0x00000107u, 0x0000006Eu, 0x000300F7u,
|
||||
0x0000010Bu, 0x00000000u, 0x000400FAu, 0x00000109u, 0x0000010Au, 0x0000010Bu, 0x000200F8u,
|
||||
0x0000010Au, 0x00050094u, 0x00000006u, 0x0000017Bu, 0x00000103u, 0x00000025u, 0x00060050u,
|
||||
0x00000007u, 0x0000010Fu, 0x0000017Bu, 0x0000017Bu, 0x0000017Bu, 0x00050041u, 0x0000005Fu,
|
||||
0x00000112u, 0x0000005Du, 0x00000111u, 0x0004003Du, 0x00000006u, 0x00000113u, 0x00000112u,
|
||||
0x00060050u, 0x00000007u, 0x00000114u, 0x00000113u, 0x00000113u, 0x00000113u, 0x0008000Cu,
|
||||
0x00000007u, 0x00000115u, 0x00000001u, 0x0000002Eu, 0x0000010Fu, 0x00000103u, 0x00000114u,
|
||||
0x000200F9u, 0x0000010Bu, 0x000200F8u, 0x0000010Bu, 0x000700F5u, 0x00000007u, 0x000001E9u,
|
||||
0x00000103u, 0x00000005u, 0x00000115u, 0x0000010Au, 0x0006000Cu, 0x00000007u, 0x00000117u,
|
||||
0x00000001u, 0x00000004u, 0x000001E9u, 0x00050041u, 0x0000005Fu, 0x00000119u, 0x0000005Du,
|
||||
0x00000118u, 0x0004003Du, 0x00000006u, 0x0000011Au, 0x00000119u, 0x00060050u, 0x00000007u,
|
||||
0x0000011Bu, 0x0000011Au, 0x0000011Au, 0x0000011Au, 0x0007000Cu, 0x00000007u, 0x0000011Cu,
|
||||
0x00000001u, 0x0000001Au, 0x00000117u, 0x0000011Bu, 0x00050081u, 0x00000007u, 0x00000120u,
|
||||
0x0000011Cu, 0x000000FDu, 0x0007000Cu, 0x00000007u, 0x00000121u, 0x00000001u, 0x00000028u,
|
||||
0x0000011Du, 0x00000120u, 0x00050041u, 0x0000005Fu, 0x00000124u, 0x0000005Du, 0x00000123u,
|
||||
0x0004003Du, 0x00000006u, 0x00000125u, 0x00000124u, 0x0007000Cu, 0x00000006u, 0x00000127u,
|
||||
0x00000001u, 0x00000028u, 0x00000125u, 0x00000126u, 0x00050081u, 0x00000006u, 0x00000128u,
|
||||
0x000000F5u, 0x00000127u, 0x00050051u, 0x00000006u, 0x0000012Au, 0x00000121u, 0x00000000u,
|
||||
0x00050051u, 0x00000006u, 0x0000012Cu, 0x00000121u, 0x00000001u, 0x00050051u, 0x00000006u,
|
||||
0x0000012Eu, 0x00000121u, 0x00000002u, 0x0007000Cu, 0x00000006u, 0x0000012Fu, 0x00000001u,
|
||||
0x00000028u, 0x0000012Cu, 0x0000012Eu, 0x0007000Cu, 0x00000006u, 0x00000130u, 0x00000001u,
|
||||
0x00000028u, 0x0000012Au, 0x0000012Fu, 0x00050083u, 0x00000006u, 0x00000131u, 0x00000128u,
|
||||
0x00000130u, 0x0007000Cu, 0x00000006u, 0x00000133u, 0x00000001u, 0x00000028u, 0x00000131u,
|
||||
0x00000126u, 0x00050088u, 0x00000006u, 0x00000134u, 0x000000F5u, 0x00000133u, 0x0005008Eu,
|
||||
0x00000007u, 0x00000136u, 0x00000121u, 0x00000134u, 0x000500AAu, 0x00000108u, 0x00000139u,
|
||||
0x00000107u, 0x0000005Eu, 0x000300F7u, 0x0000013Cu, 0x00000000u, 0x000400FAu, 0x00000139u,
|
||||
0x0000013Bu, 0x00000144u, 0x000200F8u, 0x0000013Bu, 0x00050041u, 0x0000005Fu, 0x00000141u,
|
||||
0x0000005Du, 0x0000013Du, 0x0004003Du, 0x00000006u, 0x00000142u, 0x00000141u, 0x0005008Eu,
|
||||
0x00000007u, 0x00000184u, 0x00000136u, 0x00000142u, 0x00050051u, 0x00000006u, 0x00000186u,
|
||||
0x00000184u, 0x00000000u, 0x00050051u, 0x00000006u, 0x00000188u, 0x00000184u, 0x00000001u,
|
||||
0x00050051u, 0x00000006u, 0x0000018Au, 0x00000184u, 0x00000002u, 0x0007000Cu, 0x00000006u,
|
||||
0x0000018Bu, 0x00000001u, 0x00000028u, 0x00000188u, 0x0000018Au, 0x0007000Cu, 0x00000006u,
|
||||
0x0000018Cu, 0x00000001u, 0x00000028u, 0x00000186u, 0x0000018Bu, 0x0007000Cu, 0x00000006u,
|
||||
0x0000018Du, 0x00000001u, 0x00000028u, 0x00000047u, 0x0000018Cu, 0x00060050u, 0x00000007u,
|
||||
0x00000190u, 0x0000018Du, 0x0000018Du, 0x0000018Du, 0x00050088u, 0x00000007u, 0x00000191u,
|
||||
0x00000184u, 0x00000190u, 0x00060041u, 0x0000005Fu, 0x00000193u, 0x0000005Du, 0x0000005Eu,
|
||||
0x0000002Bu, 0x0004003Du, 0x00000006u, 0x00000194u, 0x00000193u, 0x0007000Cu, 0x00000006u,
|
||||
0x00000195u, 0x00000001u, 0x0000001Au, 0x0000018Du, 0x00000194u, 0x00060041u, 0x0000005Fu,
|
||||
0x00000198u, 0x0000005Du, 0x0000005Eu, 0x00000030u, 0x0004003Du, 0x00000006u, 0x00000199u,
|
||||
0x00000198u, 0x00050085u, 0x00000006u, 0x0000019Au, 0x00000195u, 0x00000199u, 0x00060041u,
|
||||
0x0000005Fu, 0x0000019Bu, 0x0000005Du, 0x0000005Eu, 0x0000004Cu, 0x0004003Du, 0x00000006u,
|
||||
0x0000019Cu, 0x0000019Bu, 0x00050081u, 0x00000006u, 0x0000019Du, 0x0000019Au, 0x0000019Cu,
|
||||
0x00050088u, 0x00000006u, 0x0000019Eu, 0x00000195u, 0x0000019Du, 0x0006000Cu, 0x00000007u,
|
||||
0x000001A0u, 0x00000001u, 0x00000004u, 0x00000191u, 0x00060041u, 0x0000005Fu, 0x000001A1u,
|
||||
0x0000005Du, 0x0000006Eu, 0x0000002Bu, 0x0004003Du, 0x00000006u, 0x000001A2u, 0x000001A1u,
|
||||
0x00060050u, 0x00000007u, 0x000001A3u, 0x000001A2u, 0x000001A2u, 0x000001A2u, 0x0007000Cu,
|
||||
0x00000007u, 0x000001A4u, 0x00000001u, 0x0000001Au, 0x000001A0u, 0x000001A3u, 0x00050085u,
|
||||
0x00000006u, 0x000001A7u, 0x0000019Eu, 0x0000019Eu, 0x00060041u, 0x0000005Fu, 0x000001A9u,
|
||||
0x0000005Du, 0x0000006Eu, 0x0000004Cu, 0x0004003Du, 0x00000006u, 0x000001AAu, 0x000001A9u,
|
||||
0x00060050u, 0x00000007u, 0x000001ABu, 0x000001AAu, 0x000001AAu, 0x000001AAu, 0x00050085u,
|
||||
0x00000006u, 0x000001AEu, 0x000001A7u, 0x000001A7u, 0x00060050u, 0x00000007u, 0x000001AFu,
|
||||
0x000001AEu, 0x000001AEu, 0x000001AEu, 0x0008000Cu, 0x00000007u, 0x000001B0u, 0x00000001u,
|
||||
0x0000002Eu, 0x000001A4u, 0x000001ABu, 0x000001AFu, 0x0006000Cu, 0x00000007u, 0x000001B2u,
|
||||
0x00000001u, 0x00000004u, 0x000001B0u, 0x00060041u, 0x0000005Fu, 0x000001B3u, 0x0000005Du,
|
||||
0x0000006Eu, 0x00000030u, 0x0004003Du, 0x00000006u, 0x000001B4u, 0x000001B3u, 0x00060050u,
|
||||
0x00000007u, 0x000001B5u, 0x000001B4u, 0x000001B4u, 0x000001B4u, 0x0007000Cu, 0x00000007u,
|
||||
0x000001B6u, 0x00000001u, 0x0000001Au, 0x000001B2u, 0x000001B5u, 0x0005008Eu, 0x00000007u,
|
||||
0x000001B9u, 0x000001B6u, 0x0000019Eu, 0x000200F9u, 0x0000013Cu, 0x000200F8u, 0x00000144u,
|
||||
0x00050041u, 0x0000005Fu, 0x00000148u, 0x0000005Du, 0x0000013Du, 0x0004003Du, 0x00000006u,
|
||||
0x00000149u, 0x00000148u, 0x00050081u, 0x00000006u, 0x000001BEu, 0x00000149u, 0x000000A7u,
|
||||
0x0005008Eu, 0x00000007u, 0x000001C0u, 0x00000136u, 0x000001BEu, 0x00050091u, 0x00000007u,
|
||||
0x000001C2u, 0x000000B8u, 0x000001C0u, 0x00050081u, 0x00000007u, 0x000001D2u, 0x000001C2u,
|
||||
0x000001EEu, 0x00050085u, 0x00000007u, 0x000001D3u, 0x000001C2u, 0x000001D2u, 0x00050083u,
|
||||
0x00000007u, 0x000001D5u, 0x000001D3u, 0x000001EFu, 0x0005008Eu, 0x00000007u, 0x000001D8u,
|
||||
0x000001C2u, 0x00000097u, 0x00050081u, 0x00000007u, 0x000001DAu, 0x000001D8u, 0x000001F0u,
|
||||
0x00050085u, 0x00000007u, 0x000001DBu, 0x000001C2u, 0x000001DAu, 0x00050081u, 0x00000007u,
|
||||
0x000001DDu, 0x000001DBu, 0x000001F1u, 0x00050088u, 0x00000007u, 0x000001E0u, 0x000001D5u,
|
||||
0x000001DDu, 0x00050091u, 0x00000007u, 0x000001C6u, 0x000000CAu, 0x000001E0u, 0x00050041u,
|
||||
0x0000005Fu, 0x000001C8u, 0x0000005Du, 0x000000CEu, 0x0004003Du, 0x00000006u, 0x000001C9u,
|
||||
0x000001C8u, 0x0005008Eu, 0x00000007u, 0x000001CAu, 0x000001C6u, 0x000001C9u, 0x000200F9u,
|
||||
0x0000013Cu, 0x000200F8u, 0x0000013Cu, 0x000700F5u, 0x00000007u, 0x000001EAu, 0x000001B9u,
|
||||
0x0000013Bu, 0x000001CAu, 0x00000144u, 0x0006000Cu, 0x00000007u, 0x0000014Du, 0x00000001u,
|
||||
0x00000004u, 0x000001EAu, 0x00050041u, 0x0000005Fu, 0x0000014Fu, 0x0000005Du, 0x0000014Eu,
|
||||
0x0004003Du, 0x00000006u, 0x00000150u, 0x0000014Fu, 0x00060050u, 0x00000007u, 0x00000151u,
|
||||
0x00000150u, 0x00000150u, 0x00000150u, 0x0007000Cu, 0x00000007u, 0x00000152u, 0x00000001u,
|
||||
0x0000001Au, 0x0000014Du, 0x00000151u, 0x000300F7u, 0x00000157u, 0x00000000u, 0x000400FAu,
|
||||
0x00000109u, 0x00000156u, 0x00000157u, 0x000200F8u, 0x00000156u, 0x00050083u, 0x00000007u,
|
||||
0x0000015Au, 0x00000152u, 0x000001F2u, 0x00050041u, 0x0000005Fu, 0x0000015Cu, 0x0000005Du,
|
||||
0x0000015Bu, 0x0004003Du, 0x00000006u, 0x0000015Du, 0x0000015Cu, 0x0005008Eu, 0x00000007u,
|
||||
0x0000015Eu, 0x0000015Au, 0x0000015Du, 0x00050081u, 0x00000007u, 0x00000160u, 0x0000015Eu,
|
||||
0x000001F2u, 0x000200F9u, 0x00000157u, 0x000200F8u, 0x00000157u, 0x000700F5u, 0x00000007u,
|
||||
0x000001EBu, 0x00000152u, 0x0000013Cu, 0x00000160u, 0x00000156u, 0x00050051u, 0x00000006u,
|
||||
0x00000164u, 0x000001EBu, 0x00000000u, 0x00050051u, 0x00000006u, 0x00000165u, 0x000001EBu,
|
||||
0x00000001u, 0x00050051u, 0x00000006u, 0x00000166u, 0x000001EBu, 0x00000002u, 0x00070050u,
|
||||
0x00000059u, 0x00000167u, 0x00000164u, 0x00000165u, 0x00000166u, 0x000000F5u, 0x0003003Eu,
|
||||
0x00000162u, 0x00000167u, 0x000100FDu, 0x00010038u,
|
||||
}};
|
||||
|
||||
} // namespace vcs::hdr_shaders
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ge_renderer.hpp"
|
||||
#include "ge_gpu_backend.hpp"
|
||||
#include "propershaders/ProperShadersBridge.hpp"
|
||||
#include "vcs_config.hpp"
|
||||
#include "vcs_project2dfx.hpp"
|
||||
#include "vcs_fps_overlay.hpp"
|
||||
@@ -1008,6 +1009,7 @@ GeGpuHardwareTransform build_gpu_hardware_transform(
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f}
|
||||
: affine_4x3_to_mat4(transform.world);
|
||||
hw.model_to_world = world;
|
||||
const auto view = affine_4x3_to_mat4(transform.view);
|
||||
const auto model_to_view = multiply_mat4(view, world);
|
||||
// No widescreen correction on this matrix: transform.projection was already
|
||||
@@ -4209,14 +4211,21 @@ bool render_ge_primitive(psprecomp::GuestMemory &memory,
|
||||
}
|
||||
gpu_draw.texture_content_signature = any_signature ? signature : 0u;
|
||||
}
|
||||
// Semantic pipe tag is resolved only after the mutable CLUT checksum is
|
||||
// known. Skin is exact from the PSP weight format; vehicle recognition
|
||||
// can learn the palette mutation VCS uses for recolourable cars.
|
||||
gpu_draw.shader_pipe = proper_shaders_classify_draw(
|
||||
gpu_draw, layout.weight_type != 0u);
|
||||
ge_gpu_backend_record_draw(gpu_draw);
|
||||
if (!gpu_draw.through && !gpu_draw.clear_mode &&
|
||||
primitive >= 3u && primitive <= 5u) {
|
||||
const std::array<float, 6> cloud_viewport{
|
||||
const std::array<float, 8> cloud_viewport{
|
||||
decode_float24(data24(commands[0x42u])),
|
||||
decode_float24(data24(commands[0x43u])),
|
||||
decode_float24(data24(commands[0x44u])),
|
||||
decode_float24(data24(commands[0x45u])),
|
||||
decode_float24(data24(commands[0x46u])),
|
||||
decode_float24(data24(commands[0x47u])),
|
||||
static_cast<float>(data24(commands[0x4Cu]) & 0xFFFFu) / 16.0f,
|
||||
static_cast<float>(data24(commands[0x4Du]) & 0xFFFFu) / 16.0f};
|
||||
// VCS' authoritative camera origin. The affine GE view used by
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "vcs_texture_replacement.hpp"
|
||||
#include "vcs_bootstrap_paths.hpp"
|
||||
#include "vcs_project2dfx.hpp"
|
||||
#include "vcs_draw_distance_patch.hpp"
|
||||
#include "vcs_hdr_post.hpp"
|
||||
#include "vcs_runtime_log.hpp"
|
||||
|
||||
@@ -215,10 +216,11 @@ int main(int argc, char **argv) {
|
||||
const std::uint32_t user_arena_start =
|
||||
static_cast<std::uint32_t>((image_end + 0xFFu) & ~0xFFull);
|
||||
psprecomp::register_generated_functions(runtime);
|
||||
vcs::install_draw_distance_patch(runtime, configuration.source_path);
|
||||
vcs::install_project2dfx(runtime, configuration.source_path, 0u);
|
||||
// Reads [SimulateHDR] out of the same ini. The effect itself is built
|
||||
// lazily on the first frame the Vulkan backend records.
|
||||
vcs::hdr_post_configure(configuration.source_path);
|
||||
// Legacy HDR configuration, if re-enabled later, belongs with the
|
||||
// optional shader layer rather than core VCSNative.ini.
|
||||
vcs::hdr_post_configure(executable_directory / "ProperShaders.ini");
|
||||
vcs::install_profile(runtime, user_arena_start);
|
||||
|
||||
std::string gpu_backend_error;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "propershaders/ProperShadersBridge.hpp"
|
||||
|
||||
namespace vcs {
|
||||
bool proper_shaders_private_available() noexcept { return false; }
|
||||
std::string proper_shaders_make_pipe_hlsl(GeShaderPipe, std::string_view native_ge_hlsl, bool) {
|
||||
return std::string(native_ge_hlsl);
|
||||
}
|
||||
const char *proper_shaders_volumetric_clouds_hlsl() noexcept { return nullptr; }
|
||||
const char *proper_shaders_realtime_shadows_hlsl() noexcept { return nullptr; }
|
||||
const char *proper_shaders_material_shadow_hlsl() noexcept { return nullptr; }
|
||||
} // namespace vcs
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "propershaders/ProperShadersBridge.hpp"
|
||||
#include "vcs_config.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace vcs {
|
||||
namespace {
|
||||
struct PaletteIdentity {
|
||||
std::uint32_t checksum{};
|
||||
bool mutated{};
|
||||
std::uint64_t last_epoch{};
|
||||
};
|
||||
std::unordered_map<std::uint64_t, PaletteIdentity> g_palettes;
|
||||
std::uint64_t g_epoch{};
|
||||
|
||||
std::uint64_t palette_key(const GeGpuDrawDescriptor &draw) noexcept {
|
||||
std::uint64_t key = static_cast<std::uint64_t>(draw.texture_address) << 32u;
|
||||
key ^= static_cast<std::uint64_t>(draw.clut_address);
|
||||
key ^= static_cast<std::uint64_t>(draw.texture_format & 0xFu) << 60u;
|
||||
return key;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void proper_shaders_begin_frame(std::uint64_t frame_epoch) noexcept {
|
||||
g_epoch = frame_epoch;
|
||||
// Streaming constantly changes addresses. Keep the classifier bounded.
|
||||
if ((frame_epoch % 600u) == 0u && g_palettes.size() > 4096u) g_palettes.clear();
|
||||
}
|
||||
|
||||
GeShaderPipe proper_shaders_classify_draw(GeGpuDrawDescriptor &draw, bool skinned) noexcept {
|
||||
draw.shader_pipe = GeShaderPipe::Native;
|
||||
const auto &cfg = vcs_configuration().proper_shaders;
|
||||
if (!cfg.enabled || !proper_shaders_private_available() ||
|
||||
draw.through || draw.clear_mode || draw.primitive < 3u || draw.primitive > 5u)
|
||||
return draw.shader_pipe;
|
||||
|
||||
if (skinned && cfg.skin_pipe.enabled) {
|
||||
draw.shader_pipe = GeShaderPipe::Skin;
|
||||
return draw.shader_pipe;
|
||||
}
|
||||
|
||||
if (cfg.vehicle_pipe.enabled && cfg.vehicle_pipe.palette_classifier &&
|
||||
draw.texture_enabled && draw.texture_format >= 4u && draw.texture_format <= 7u &&
|
||||
draw.clut_address != 0u && draw.clut_checksum != 0u) {
|
||||
auto &identity = g_palettes[palette_key(draw)];
|
||||
if (identity.checksum != 0u && identity.checksum != draw.clut_checksum)
|
||||
identity.mutated = true;
|
||||
identity.checksum = draw.clut_checksum;
|
||||
identity.last_epoch = g_epoch;
|
||||
if (identity.mutated) {
|
||||
draw.shader_pipe = GeShaderPipe::Vehicle;
|
||||
return draw.shader_pipe;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.building_pipe.enabled) draw.shader_pipe = GeShaderPipe::Building;
|
||||
return draw.shader_pipe;
|
||||
}
|
||||
|
||||
} // namespace vcs
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "ge_gpu_backend.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace vcs {
|
||||
|
||||
// Host semantic classification. It is deliberately small and game-profile
|
||||
// local: the generic PSP renderer only knows GE state, while VCS decides which
|
||||
// custom pipe a draw belongs to.
|
||||
[[nodiscard]] GeShaderPipe proper_shaders_classify_draw(GeGpuDrawDescriptor &draw,
|
||||
bool skinned) noexcept;
|
||||
void proper_shaders_begin_frame(std::uint64_t frame_epoch) noexcept;
|
||||
|
||||
// Optional private shader module. Public/GitHub builds link the stubs and keep
|
||||
// the native PSP shader unchanged.
|
||||
[[nodiscard]] bool proper_shaders_private_available() noexcept;
|
||||
[[nodiscard]] std::string proper_shaders_make_pipe_hlsl(
|
||||
GeShaderPipe pipe, std::string_view native_ge_hlsl,
|
||||
bool material_shadows = true);
|
||||
[[nodiscard]] const char *proper_shaders_volumetric_clouds_hlsl() noexcept;
|
||||
[[nodiscard]] const char *proper_shaders_realtime_shadows_hlsl() noexcept;
|
||||
[[nodiscard]] const char *proper_shaders_material_shadow_hlsl() noexcept;
|
||||
|
||||
} // namespace vcs
|
||||
@@ -0,0 +1,108 @@
|
||||
#include "propershaders/ProperShadersConfig.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace vcs {
|
||||
namespace {
|
||||
std::string trim(std::string value) {
|
||||
const auto ok=[](unsigned char c){return std::isspace(c)==0;};
|
||||
value.erase(value.begin(),std::find_if(value.begin(),value.end(),ok));
|
||||
value.erase(std::find_if(value.rbegin(),value.rend(),ok).base(),value.end());
|
||||
return value;
|
||||
}
|
||||
std::string lower(std::string value) {
|
||||
std::transform(value.begin(),value.end(),value.begin(),[](unsigned char c){return static_cast<char>(std::tolower(c));});
|
||||
return value;
|
||||
}
|
||||
std::string uncomment(std::string value) {
|
||||
bool quoted=false; char q='\0';
|
||||
for(std::size_t i=0;i<value.size();++i){const char c=value[i]; if(c=='\''||c=='"'){if(!quoted){quoted=true;q=c;}else if(q==c)quoted=false;}else if(!quoted&&(c==';'||c=='#')){value.resize(i);break;}}
|
||||
return trim(std::move(value));
|
||||
}
|
||||
bool boolean(std::string value,bool &out){value=lower(trim(std::move(value)));if(value=="1"||value=="true"||value=="yes"||value=="on"){out=true;return true;}if(value=="0"||value=="false"||value=="no"||value=="off"){out=false;return true;}return false;}
|
||||
bool real(std::string value,float lo,float hi,float &out){value=trim(std::move(value));char *end=nullptr;errno=0;float v=std::strtof(value.c_str(),&end);if(errno!=0||end==value.c_str()||*end!='\0'||!std::isfinite(v)||v<lo||v>hi)return false;out=v;return true;}
|
||||
bool integer(std::string value,std::uint32_t lo,std::uint32_t hi,std::uint32_t &out){value=trim(std::move(value));char *end=nullptr;errno=0;unsigned long v=std::strtoul(value.c_str(),&end,10);if(errno!=0||end==value.c_str()||*end!='\0'||v<lo||v>hi)return false;out=static_cast<std::uint32_t>(v);return true;}
|
||||
void warn(std::vector<std::string> &warnings,std::size_t line,const std::string &text){std::ostringstream s;s<<"line "<<line<<": ProperShaders.ini: "<<text;warnings.push_back(s.str());}
|
||||
} // namespace
|
||||
|
||||
void load_proper_shaders_configuration(ProperShadersConfiguration &cfg,
|
||||
const std::filesystem::path &path,
|
||||
std::vector<std::string> &warnings) {
|
||||
std::ifstream input(path); if(!input)return;
|
||||
std::string section,line; std::size_t line_no=0;
|
||||
while(std::getline(input,line)){
|
||||
++line_no; line=uncomment(std::move(line)); if(line.empty())continue;
|
||||
if(line.front()=='['&&line.back()==']'){section=lower(trim(line.substr(1,line.size()-2)));continue;}
|
||||
const auto eq=line.find('='); if(eq==std::string::npos){warn(warnings,line_no,"expected key=value");continue;}
|
||||
const std::string key=lower(trim(line.substr(0,eq))); const std::string value=uncomment(line.substr(eq+1));
|
||||
auto b=[&](bool &dst,const char *name){if(!boolean(value,dst))warn(warnings,line_no,std::string(name)+" expects true/false");};
|
||||
auto f=[&](float &dst,float lo,float hi,const char *name){if(!real(value,lo,hi,dst))warn(warnings,line_no,std::string("invalid ")+name);};
|
||||
auto u=[&](std::uint32_t &dst,std::uint32_t lo,std::uint32_t hi,const char *name){if(!integer(value,lo,hi,dst))warn(warnings,line_no,std::string("invalid ")+name);};
|
||||
if(section=="propershaders"||section=="proper shaders") { if(key=="enabled") b(cfg.enabled,"Enabled"); else warn(warnings,line_no,"unknown [ProperShaders] key '"+key+"'"); }
|
||||
else if(section=="buildingpipe"||section=="building pipe"||section=="worldpipe"||section=="world pipe") {
|
||||
auto &c=cfg.building_pipe;
|
||||
if(key=="enabled") b(c.enabled,"Enabled");
|
||||
else if(key=="debug"||key=="debugcolor") b(c.debug_color,"DebugColor");
|
||||
else if(key=="debugr") f(c.debug_r,0.0f,1.0f,"DebugR");
|
||||
else if(key=="debugg") f(c.debug_g,0.0f,1.0f,"DebugG");
|
||||
else if(key=="debugb") f(c.debug_b,0.0f,1.0f,"DebugB");
|
||||
else warn(warnings,line_no,"unknown [WorldPipe/BuildingPipe] key '"+key+"'");
|
||||
}
|
||||
else if(section=="skinpipe"||section=="skin pipe") {
|
||||
auto &c=cfg.skin_pipe;
|
||||
if(key=="enabled") b(c.enabled,"Enabled");
|
||||
else if(key=="debug"||key=="debugcolor") b(c.debug_color,"DebugColor");
|
||||
else if(key=="debugr") f(c.debug_r,0.0f,1.0f,"DebugR");
|
||||
else if(key=="debugg") f(c.debug_g,0.0f,1.0f,"DebugG");
|
||||
else if(key=="debugb") f(c.debug_b,0.0f,1.0f,"DebugB");
|
||||
else warn(warnings,line_no,"unknown [SkinPipe] key '"+key+"'");
|
||||
}
|
||||
else if(section=="vehiclepipe"||section=="vehicle pipe") {
|
||||
auto &c=cfg.vehicle_pipe;
|
||||
if(key=="enabled") b(c.enabled,"Enabled");
|
||||
else if(key=="paletteclassifier") b(c.palette_classifier,"PaletteClassifier");
|
||||
else if(key=="debug"||key=="debugcolor") b(c.debug_color,"DebugColor");
|
||||
else if(key=="debugr") f(c.debug_r,0.0f,1.0f,"DebugR");
|
||||
else if(key=="debugg") f(c.debug_g,0.0f,1.0f,"DebugG");
|
||||
else if(key=="debugb") f(c.debug_b,0.0f,1.0f,"DebugB");
|
||||
else warn(warnings,line_no,"unknown [VehiclePipe] key '"+key+"'");
|
||||
}
|
||||
else if(section=="realtimeshadows"||section=="realtime shadows") {
|
||||
auto &c=cfg.realtime_shadows;
|
||||
if(key=="enabled") b(c.enabled,"Enabled");
|
||||
else if(key=="mapresolution") u(c.map_resolution,512u,4096u,"MapResolution");
|
||||
else if(key=="worldradius") f(c.world_radius,20.0f,1000.0f,"WorldRadius");
|
||||
else if(key=="depthrange") f(c.depth_range,40.0f,2000.0f,"DepthRange");
|
||||
else if(key=="mapbias") f(c.map_bias,0.000001f,0.05f,"MapBias");
|
||||
else if(key=="pcfradius") u(c.pcf_radius,0u,3u,"PcfRadius");
|
||||
else if(key=="usecloudsundirection") b(c.use_cloud_sun_direction,"UseCloudSunDirection");
|
||||
else if(key=="lightdirectionx") f(c.light_direction_x,-1.0f,1.0f,"LightDirectionX");
|
||||
else if(key=="lightdirectiony") f(c.light_direction_y,-1.0f,1.0f,"LightDirectionY");
|
||||
else if(key=="lightdirectionz") f(c.light_direction_z,-1.0f,1.0f,"LightDirectionZ");
|
||||
else if(key=="strength") f(c.strength,0.0f,1.0f,"Strength");
|
||||
else if(key=="debugmode") u(c.debug_mode,0u,6u,"DebugMode");
|
||||
else if(key=="contactshadows") b(c.contact_shadows,"ContactShadows");
|
||||
else if(key=="steps") u(c.steps,2u,32u,"Steps");
|
||||
else if(key=="maxdistancepixels") f(c.max_distance_pixels,1.0f,256.0f,"MaxDistancePixels");
|
||||
else if(key=="thickness") f(c.thickness,0.00001f,0.1f,"Thickness");
|
||||
else if(key=="contactstrength") f(c.contact_strength,0.0f,1.0f,"ContactStrength");
|
||||
else if(key=="lightscreenx") f(c.light_screen_x,-2.0f,2.0f,"LightScreenX");
|
||||
else if(key=="lightscreeny") f(c.light_screen_y,-2.0f,2.0f,"LightScreenY");
|
||||
else warn(warnings,line_no,"unknown [RealtimeShadows] key '"+key+"'");
|
||||
}
|
||||
else if(section=="volumetricclouds"||section=="volumetric clouds") {
|
||||
auto &c=cfg.volumetric_clouds;
|
||||
if(key=="enabled")b(c.enabled,"Enabled"); else if(key=="downscalediv")u(c.downscale_div,1,8,"DownscaleDiv"); else if(key=="layers")u(c.layers,1,3,"Layers"); else if(key=="shadowsteps")u(c.shadow_steps,2,8,"ShadowSteps");
|
||||
else if(key=="coveragelow")f(c.coverage_low,0,1,"CoverageLow"); else if(key=="coveragemid")f(c.coverage_mid,0,1,"CoverageMid"); else if(key=="coveragehigh")f(c.coverage_high,0,1,"CoverageHigh"); else if(key=="opacity")f(c.opacity,0,1,"Opacity"); else if(key=="speed")f(c.speed,0,1000,"Speed"); else if(key=="brightness")f(c.brightness,0,8,"Brightness"); else if(key=="randomseed")f(c.random_seed,0,6.2831855f,"RandomSeed");
|
||||
else if(key=="sundirectionx")f(c.sun_direction_x,-1,1,"SunDirectionX"); else if(key=="sundirectiony")f(c.sun_direction_y,-1,1,"SunDirectionY"); else if(key=="sundirectionz")f(c.sun_direction_z,-1,1,"SunDirectionZ"); else if(key=="suncolorr")f(c.sun_color_r,0,4,"SunColorR"); else if(key=="suncolorg")f(c.sun_color_g,0,4,"SunColorG"); else if(key=="suncolorb")f(c.sun_color_b,0,4,"SunColorB");
|
||||
else if(key=="cloudbasecolorr")f(c.cloud_base_color_r,0,4,"CloudBaseColorR"); else if(key=="cloudbasecolorg")f(c.cloud_base_color_g,0,4,"CloudBaseColorG"); else if(key=="cloudbasecolorb")f(c.cloud_base_color_b,0,4,"CloudBaseColorB"); else if(key=="atmospheredensity")f(c.atmosphere_density,0,4,"AtmosphereDensity"); else if(key=="mist")f(c.mist,0,1,"Mist"); else if(key=="fogcolorr")f(c.fog_color_r,0,4,"FogColorR"); else if(key=="fogcolorg")f(c.fog_color_g,0,4,"FogColorG"); else if(key=="fogcolorb")f(c.fog_color_b,0,4,"FogColorB"); else if(key=="fogstart")f(c.fog_start,1,100000,"FogStart"); else if(key=="dayprogression")f(c.day_progression,-1,1,"DayProgression"); else if(key=="temporalblend")f(c.temporal_blend,0,.95f,"TemporalBlend"); else if(key=="temporaldenoise")f(c.temporal_denoise,0,16,"TemporalDenoise"); else if(key=="temporalclamp")f(c.temporal_clamp,0,16,"TemporalClamp"); else warn(warnings,line_no,"unknown [VolumetricClouds] key '"+key+"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace vcs
|
||||
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace vcs {
|
||||
|
||||
struct ShaderPipeConfiguration {
|
||||
bool enabled{true};
|
||||
|
||||
// Diagnostic proof that this is a real material shader pipe. When enabled,
|
||||
// ApplyProperPipePixel replaces RGB on the surface in the private HLSL.
|
||||
bool debug_color{false};
|
||||
float debug_r{1.0f};
|
||||
float debug_g{0.0f};
|
||||
float debug_b{1.0f};
|
||||
};
|
||||
|
||||
struct VehiclePipeConfiguration : ShaderPipeConfiguration {
|
||||
// VCS recolours cars by rewriting CLUT data while keeping the same texture.
|
||||
// Tracking that mutation gives the native GE frontend a semantic vehicle tag
|
||||
// without baking game-model IDs into the renderer.
|
||||
bool palette_classifier{true};
|
||||
};
|
||||
|
||||
struct RealtimeShadowsConfiguration {
|
||||
bool enabled{true};
|
||||
|
||||
// Stable camera-centred directional shadow map. The private DX12 layer uses
|
||||
// the same world matrices as the Building/Skin/Vehicle material pipes.
|
||||
std::uint32_t map_resolution{2048u};
|
||||
float world_radius{140.0f};
|
||||
float depth_range{420.0f};
|
||||
float map_bias{0.0015f};
|
||||
std::uint32_t pcf_radius{1u};
|
||||
bool use_cloud_sun_direction{true};
|
||||
float light_direction_x{0.38f};
|
||||
float light_direction_y{-0.28f};
|
||||
float light_direction_z{0.88f};
|
||||
float strength{0.58f};
|
||||
|
||||
// Shadow diagnostics. 0=normal, 1=raw shadow map fullscreen,
|
||||
// 2=receiver shadow mask, 3=light UV/frustum coverage,
|
||||
// 4=sampled map depth, 5=receiver light depth, 6=lit/blocked compare.
|
||||
std::uint32_t debug_mode{0u};
|
||||
|
||||
// Legacy fullscreen contact-shadow controls are retained for INI
|
||||
// compatibility only. The DX12 path now receives directional shadows in
|
||||
// Building/Skin/Vehicle material shaders, so the ghost-prone composite is
|
||||
// disabled by default and is not used as the world-shadow implementation.
|
||||
bool contact_shadows{false};
|
||||
std::uint32_t steps{12u};
|
||||
float max_distance_pixels{28.0f};
|
||||
float thickness{0.0025f};
|
||||
float contact_strength{0.22f};
|
||||
float light_screen_x{-0.55f};
|
||||
float light_screen_y{0.75f};
|
||||
};
|
||||
|
||||
struct VolumetricCloudsConfiguration {
|
||||
bool enabled{false};
|
||||
std::uint32_t downscale_div{2u};
|
||||
std::uint32_t layers{2u};
|
||||
std::uint32_t shadow_steps{8u};
|
||||
float coverage_low{0.35f};
|
||||
float coverage_mid{0.25f};
|
||||
float coverage_high{0.18f};
|
||||
float opacity{1.0f};
|
||||
float speed{0.0f};
|
||||
float brightness{1.0f};
|
||||
float random_seed{0.0f};
|
||||
float sun_direction_x{0.38f};
|
||||
float sun_direction_y{-0.28f};
|
||||
float sun_direction_z{0.88f};
|
||||
float sun_color_r{1.0f};
|
||||
float sun_color_g{0.97f};
|
||||
float sun_color_b{0.88f};
|
||||
float cloud_base_color_r{0.70f};
|
||||
float cloud_base_color_g{0.70f};
|
||||
float cloud_base_color_b{0.70f};
|
||||
float atmosphere_density{0.0f};
|
||||
float mist{0.50f};
|
||||
float fog_color_r{0.58f};
|
||||
float fog_color_g{0.68f};
|
||||
float fog_color_b{0.78f};
|
||||
float fog_start{4500.0f};
|
||||
float day_progression{0.88f};
|
||||
float temporal_blend{0.50f};
|
||||
float temporal_denoise{1.0f};
|
||||
float temporal_clamp{1.0f};
|
||||
};
|
||||
|
||||
struct ProperShadersConfiguration {
|
||||
bool enabled{true};
|
||||
ShaderPipeConfiguration building_pipe{};
|
||||
ShaderPipeConfiguration skin_pipe{};
|
||||
VehiclePipeConfiguration vehicle_pipe{};
|
||||
RealtimeShadowsConfiguration realtime_shadows{};
|
||||
VolumetricCloudsConfiguration volumetric_clouds{};
|
||||
};
|
||||
|
||||
// Parses only ProperShaders.ini. Unknown sections/keys are reported through
|
||||
// warnings so shader configuration never pollutes VCSNative.ini.
|
||||
void load_proper_shaders_configuration(ProperShadersConfiguration &config,
|
||||
const std::filesystem::path &path,
|
||||
std::vector<std::string> &warnings);
|
||||
|
||||
} // namespace vcs
|
||||
@@ -126,102 +126,6 @@ void warning(VcsConfiguration &config, std::size_t line, const std::string &mess
|
||||
config.warnings.push_back(stream.str());
|
||||
}
|
||||
|
||||
void load_proper_shaders_configuration(VcsConfiguration &config,
|
||||
const std::filesystem::path &path) {
|
||||
std::ifstream input(path);
|
||||
if (!input) return;
|
||||
std::string section;
|
||||
std::string raw_line;
|
||||
std::size_t line_number = 0u;
|
||||
while (std::getline(input, raw_line)) {
|
||||
++line_number;
|
||||
std::string line = trim_copy(raw_line);
|
||||
if (line.empty() || line[0] == ';' || line[0] == '#') continue;
|
||||
if (line.front() == '[' && line.back() == ']') {
|
||||
section = lowercase_copy(trim_copy(line.substr(1u, line.size() - 2u)));
|
||||
continue;
|
||||
}
|
||||
if (section != "volumetricclouds" && section != "volumetric clouds") continue;
|
||||
const std::size_t separator = line.find('=');
|
||||
if (separator == std::string::npos) {
|
||||
warning(config, line_number, "ProperShaders.ini: expected key=value");
|
||||
continue;
|
||||
}
|
||||
const std::string key = lowercase_copy(trim_copy(line.substr(0u, separator)));
|
||||
const std::string value = strip_inline_comment(line.substr(separator + 1u));
|
||||
auto bad_float = [&](const char *name) {
|
||||
warning(config, line_number, std::string("ProperShaders.ini: invalid ") + name);
|
||||
};
|
||||
if (key == "enabled") {
|
||||
if (!parse_bool(value, config.volumetric_clouds.enabled))
|
||||
warning(config, line_number, "ProperShaders.ini: Enabled expects true/false");
|
||||
} else if (key == "downscalediv") {
|
||||
if (!parse_u32(value, 1u, 8u, config.volumetric_clouds.downscale_div))
|
||||
warning(config, line_number, "ProperShaders.ini: DownscaleDiv must be between 1 and 8");
|
||||
} else if (key == "layers") {
|
||||
if (!parse_u32(value, 1u, 3u, config.volumetric_clouds.layers))
|
||||
warning(config, line_number, "ProperShaders.ini: Layers must be between 1 and 3");
|
||||
} else if (key == "shadowsteps") {
|
||||
if (!parse_u32(value, 2u, 8u, config.volumetric_clouds.shadow_steps))
|
||||
warning(config, line_number, "ProperShaders.ini: ShadowSteps must be between 2 and 8");
|
||||
} else if (key == "coveragelow") {
|
||||
if (!parse_float(value, 0.0f, 1.0f, config.volumetric_clouds.coverage_low)) bad_float("CoverageLow");
|
||||
} else if (key == "coveragemid") {
|
||||
if (!parse_float(value, 0.0f, 1.0f, config.volumetric_clouds.coverage_mid)) bad_float("CoverageMid");
|
||||
} else if (key == "coveragehigh") {
|
||||
if (!parse_float(value, 0.0f, 1.0f, config.volumetric_clouds.coverage_high)) bad_float("CoverageHigh");
|
||||
} else if (key == "opacity") {
|
||||
if (!parse_float(value, 0.0f, 1.0f, config.volumetric_clouds.opacity)) bad_float("Opacity");
|
||||
} else if (key == "speed") {
|
||||
if (!parse_float(value, 0.0f, 1000.0f, config.volumetric_clouds.speed)) bad_float("Speed");
|
||||
} else if (key == "brightness") {
|
||||
if (!parse_float(value, 0.0f, 8.0f, config.volumetric_clouds.brightness)) bad_float("Brightness");
|
||||
} else if (key == "randomseed") {
|
||||
if (!parse_float(value, 0.0f, 6.2831855f, config.volumetric_clouds.random_seed)) bad_float("RandomSeed");
|
||||
} else if (key == "sundirectionx") {
|
||||
if (!parse_float(value, -1.0f, 1.0f, config.volumetric_clouds.sun_direction_x)) bad_float("SunDirectionX");
|
||||
} else if (key == "sundirectiony") {
|
||||
if (!parse_float(value, -1.0f, 1.0f, config.volumetric_clouds.sun_direction_y)) bad_float("SunDirectionY");
|
||||
} else if (key == "sundirectionz") {
|
||||
if (!parse_float(value, -1.0f, 1.0f, config.volumetric_clouds.sun_direction_z)) bad_float("SunDirectionZ");
|
||||
} else if (key == "suncolorr") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.sun_color_r)) bad_float("SunColorR");
|
||||
} else if (key == "suncolorg") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.sun_color_g)) bad_float("SunColorG");
|
||||
} else if (key == "suncolorb") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.sun_color_b)) bad_float("SunColorB");
|
||||
} else if (key == "cloudbasecolorr") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.cloud_base_color_r)) bad_float("CloudBaseColorR");
|
||||
} else if (key == "cloudbasecolorg") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.cloud_base_color_g)) bad_float("CloudBaseColorG");
|
||||
} else if (key == "cloudbasecolorb") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.cloud_base_color_b)) bad_float("CloudBaseColorB");
|
||||
} else if (key == "atmospheredensity") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.atmosphere_density)) bad_float("AtmosphereDensity");
|
||||
} else if (key == "mist") {
|
||||
if (!parse_float(value, 0.0f, 1.0f, config.volumetric_clouds.mist)) bad_float("Mist");
|
||||
} else if (key == "fogcolorr") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.fog_color_r)) bad_float("FogColorR");
|
||||
} else if (key == "fogcolorg") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.fog_color_g)) bad_float("FogColorG");
|
||||
} else if (key == "fogcolorb") {
|
||||
if (!parse_float(value, 0.0f, 4.0f, config.volumetric_clouds.fog_color_b)) bad_float("FogColorB");
|
||||
} else if (key == "fogstart") {
|
||||
if (!parse_float(value, 1.0f, 100000.0f, config.volumetric_clouds.fog_start)) bad_float("FogStart");
|
||||
} else if (key == "dayprogression") {
|
||||
if (!parse_float(value, -1.0f, 1.0f, config.volumetric_clouds.day_progression)) bad_float("DayProgression");
|
||||
} else if (key == "temporalblend") {
|
||||
if (!parse_float(value, 0.0f, 0.95f, config.volumetric_clouds.temporal_blend)) bad_float("TemporalBlend");
|
||||
} else if (key == "temporaldenoise") {
|
||||
if (!parse_float(value, 0.0f, 16.0f, config.volumetric_clouds.temporal_denoise)) bad_float("TemporalDenoise");
|
||||
} else if (key == "temporalclamp") {
|
||||
if (!parse_float(value, 0.0f, 16.0f, config.volumetric_clouds.temporal_clamp)) bad_float("TemporalClamp");
|
||||
} else {
|
||||
warning(config, line_number, "ProperShaders.ini: unknown [VolumetricClouds] key '" + key + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void apply_display_key(VcsConfiguration &config, const std::string &key,
|
||||
const std::string &value, std::size_t line) {
|
||||
if (key == "enabled") {
|
||||
@@ -780,10 +684,11 @@ VcsConfiguration load_vcs_configuration(const std::filesystem::path &path) {
|
||||
apply_frontend_key(config, key, value, line_number);
|
||||
else if (section == "textures" || section == "texturereplacement")
|
||||
apply_textures_key(config, key, value, line_number);
|
||||
// These sections belong to the optional Project2DFX module, which
|
||||
// deliberately owns its parser so it can be compiled independently of
|
||||
// the core display/input configuration. They are nevertheless valid
|
||||
// VCSNative.ini sections and must not be reported as unknown here.
|
||||
// Optional modules deliberately own these parsers so the core
|
||||
// display/input configuration stays game-neutral. DrawDistance is now
|
||||
// installed independently of Project2DFX; SimulateHDR is accepted only
|
||||
// as a legacy VCSNative.ini section (new shader settings live in
|
||||
// ProperShaders.ini).
|
||||
else if (section == "project2dfx" || section == "project 2dfx" ||
|
||||
section == "lodlights" || section == "lod lights" ||
|
||||
section == "trafficlights" || section == "traffic lights" ||
|
||||
@@ -792,7 +697,8 @@ VcsConfiguration load_vcs_configuration(const std::filesystem::path &path) {
|
||||
section == "heli height" || section == "drawdistance" ||
|
||||
section == "draw distance" || section == "simulatehdr" ||
|
||||
section == "simulate hdr") {
|
||||
// Parsed by install_project2dfx() or hdr_post_configure().
|
||||
// Parsed by install_project2dfx(), install_draw_distance_patch(),
|
||||
// or retained for legacy configuration compatibility.
|
||||
}
|
||||
else if (section.empty())
|
||||
warning(config, line_number, "key outside a section");
|
||||
@@ -812,7 +718,7 @@ void initialize_vcs_configuration(const std::filesystem::path &executable_direct
|
||||
}
|
||||
|
||||
VcsConfiguration loaded = load_vcs_configuration(path);
|
||||
load_proper_shaders_configuration(loaded, executable_directory / "ProperShaders.ini");
|
||||
load_proper_shaders_configuration(loaded.proper_shaders, executable_directory / "ProperShaders.ini", loaded.warnings);
|
||||
// SAVE_REPRO is intentionally off in the shipped INI. The internal restore
|
||||
// script/environment is an explicit developer opt-in and may enable it for
|
||||
// that process without requiring the user's normal configuration to change.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "propershaders/ProperShadersConfig.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
@@ -187,44 +189,6 @@ struct WidescreenConfiguration {
|
||||
std::uint32_t aspect_y{0u};
|
||||
};
|
||||
|
||||
// Standalone ProperShaders.ini feature. Values normally supplied by the San
|
||||
// Andreas timecycle/weather integration remain explicit placeholders until the
|
||||
// equivalent VCS guest hooks exist. Keeping the inputs separate is important:
|
||||
// collapsing the three decks and lighting state into one "coverage" value
|
||||
// materially changes CloudWorks' appearance.
|
||||
struct VolumetricCloudsConfiguration {
|
||||
bool enabled{false};
|
||||
std::uint32_t downscale_div{2u};
|
||||
std::uint32_t layers{2u};
|
||||
std::uint32_t shadow_steps{8u};
|
||||
float coverage_low{0.35f};
|
||||
float coverage_mid{0.25f};
|
||||
float coverage_high{0.18f};
|
||||
float opacity{1.0f};
|
||||
float speed{0.0f};
|
||||
float brightness{1.0f};
|
||||
float random_seed{0.0f};
|
||||
float sun_direction_x{0.38f};
|
||||
float sun_direction_y{-0.28f};
|
||||
float sun_direction_z{0.88f};
|
||||
float sun_color_r{1.0f};
|
||||
float sun_color_g{0.97f};
|
||||
float sun_color_b{0.88f};
|
||||
float cloud_base_color_r{0.70f};
|
||||
float cloud_base_color_g{0.70f};
|
||||
float cloud_base_color_b{0.70f};
|
||||
float atmosphere_density{0.0f};
|
||||
float mist{0.50f};
|
||||
float fog_color_r{0.58f};
|
||||
float fog_color_g{0.68f};
|
||||
float fog_color_b{0.78f};
|
||||
float fog_start{4500.0f};
|
||||
float day_progression{0.88f};
|
||||
float temporal_blend{0.50f};
|
||||
float temporal_denoise{1.0f};
|
||||
float temporal_clamp{1.0f};
|
||||
};
|
||||
|
||||
// The aspect the game itself builds its projection with. VCS loads the
|
||||
// constant 0x3FE38E39 -- exactly 16/9 -- and everything is relative to it.
|
||||
inline constexpr float kGameNativeAspectRatio = 16.0f / 9.0f;
|
||||
@@ -281,7 +245,7 @@ struct VcsConfiguration {
|
||||
DiagnosticsConfiguration diagnostics{};
|
||||
TestingConfiguration testing{};
|
||||
WidescreenConfiguration widescreen{};
|
||||
VolumetricCloudsConfiguration volumetric_clouds{};
|
||||
ProperShadersConfiguration proper_shaders{};
|
||||
std::filesystem::path source_path{};
|
||||
// Where the executable lives. Saves go beside it rather than into the game
|
||||
// data, so a player who points the runtime at a read-only or shared copy of
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
//
|
||||
// [DrawDistance]
|
||||
// Enabled = 1
|
||||
// World = 1.50
|
||||
// Objects = 1.50
|
||||
// Vehicles = 1.50
|
||||
// NPCs = 1.50
|
||||
//
|
||||
// 1.0 = original PSP distance. Values below 1.0 are clamped to 1.0.
|
||||
// World is allowed up to 8.0; Vehicles/NPCs up to 4.0.
|
||||
// Objects/World/Vehicles/NPCs are allowed up to 8.0 for explicit testing.
|
||||
// For mission compatibility, keep Vehicles/NPCs <= 2.0 unless tested.
|
||||
//
|
||||
// Integration (no header required):
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "vcs_draw_distance_patch.hpp"
|
||||
#include "psprecomp/runtime.hpp"
|
||||
#include "psprecomp/common.hpp" // hex32, para o relatorio de hooks vivos/mortos
|
||||
#include "vcs_runtime_log.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
@@ -39,6 +40,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
@@ -46,6 +48,7 @@
|
||||
namespace vcs {
|
||||
|
||||
DrawDistanceRuntimeScales g_draw_distance_runtime_scales{};
|
||||
DrawDistanceRuntimeTelemetry g_draw_distance_runtime_telemetry{};
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -83,10 +86,6 @@ struct OriginalWorldModel {
|
||||
};
|
||||
|
||||
std::unordered_map<std::uint32_t, OriginalWorldModel> g_original_world_models;
|
||||
bool g_far_clip_seen{};
|
||||
float g_far_clip_last_raw{};
|
||||
float g_far_clip_last_scaled{};
|
||||
|
||||
std::string trim_copy(std::string value) {
|
||||
auto is_space = [](unsigned char c) { return std::isspace(c) != 0; };
|
||||
while (!value.empty() && is_space(static_cast<unsigned char>(value.front())))
|
||||
@@ -171,7 +170,9 @@ DrawDistanceConfig load_config(const std::filesystem::path &path) {
|
||||
|
||||
if (key == "enabled") {
|
||||
parse_bool(value, cfg.enabled);
|
||||
} else if (key == "world" || key == "worldmultiplier") {
|
||||
} else if (key == "world" || key == "worldmultiplier" ||
|
||||
key == "objects" || key == "buildings" ||
|
||||
key == "objectmultiplier" || key == "buildingmultiplier") {
|
||||
parse_float(value, cfg.world);
|
||||
} else if (key == "vehicles" || key == "cars" || key == "vehiclemultiplier") {
|
||||
parse_float(value, cfg.vehicles);
|
||||
@@ -181,8 +182,8 @@ DrawDistanceConfig load_config(const std::filesystem::path &path) {
|
||||
}
|
||||
|
||||
cfg.world = std::clamp(cfg.world, 1.0f, 8.0f);
|
||||
cfg.vehicles = std::clamp(cfg.vehicles, 1.0f, 4.0f);
|
||||
cfg.npcs = std::clamp(cfg.npcs, 1.0f, 4.0f);
|
||||
cfg.vehicles = std::clamp(cfg.vehicles, 1.0f, 8.0f);
|
||||
cfg.npcs = std::clamp(cfg.npcs, 1.0f, 8.0f);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@@ -309,6 +310,10 @@ bool patch_world_model_table(psprecomp::Runtime &runtime, std::uint32_t gp) {
|
||||
std::cerr << " [dd-verifica] passada=" << verifications
|
||||
<< " intactos=" << intact << " revertidos=" << reverted << "\n";
|
||||
}
|
||||
if (patched != 0u) {
|
||||
++g_draw_distance_runtime_telemetry.world_table_patch_hits;
|
||||
g_draw_distance_runtime_telemetry.world_models_patched += patched;
|
||||
}
|
||||
return patched != 0u;
|
||||
}
|
||||
|
||||
@@ -318,12 +323,11 @@ void install_draw_distance_patch(psprecomp::Runtime &runtime,
|
||||
const std::filesystem::path &ini_path) {
|
||||
g_config = load_config(ini_path);
|
||||
g_original_world_models.clear();
|
||||
g_far_clip_seen = false;
|
||||
g_far_clip_last_raw = 0.0f;
|
||||
g_far_clip_last_scaled = 0.0f;
|
||||
g_draw_distance_runtime_scales = {};
|
||||
g_draw_distance_runtime_telemetry = {};
|
||||
if (g_config.enabled) {
|
||||
g_draw_distance_runtime_scales.entity = std::max(g_config.vehicles, g_config.npcs);
|
||||
g_draw_distance_runtime_scales.world = g_config.world;
|
||||
g_draw_distance_runtime_scales.entity = std::max({g_config.world, g_config.vehicles, g_config.npcs});
|
||||
g_draw_distance_runtime_scales.vehicles = g_config.vehicles;
|
||||
g_draw_distance_runtime_scales.npcs = g_config.npcs;
|
||||
}
|
||||
@@ -333,17 +337,15 @@ void install_draw_distance_patch(psprecomp::Runtime &runtime,
|
||||
return;
|
||||
}
|
||||
|
||||
// World is maintained at vblank. Entity/vehicle/NPC constants are
|
||||
// patched directly at their generated local labels, because gameplay reaches
|
||||
// Far clip and entity/vehicle/NPC constants are patched directly at
|
||||
// their generated local labels, because gameplay reaches
|
||||
// those labels with intra-unit gotos that cannot be intercepted by the runtime
|
||||
// function registry.
|
||||
|
||||
if (g_config.world > 1.0f) {
|
||||
// World distance is maintained from the display-vblank boundary. Both
|
||||
// historical entry hooks can be reached as local labels inside an AOT
|
||||
// unit and therefore bypass Runtime::register_function entirely. Keeping
|
||||
// them registered also poisons direct chaining for no reliable benefit.
|
||||
std::cerr << "[draw-distance] world path=vblank (no fragile far_clip/IDE AOT hooks)\n";
|
||||
// Far clip is scaled at the exact gp+7796 setter. Model-info LODs are
|
||||
// patched at IDE completion and refreshed at vblank if streaming rebuilds them.
|
||||
std::cerr << "[draw-distance] world path=exact far-clip setter + IDE model table\n";
|
||||
}
|
||||
|
||||
if (g_config.vehicles > 1.0f || g_config.npcs > 1.0f) {
|
||||
@@ -351,51 +353,86 @@ void install_draw_distance_patch(psprecomp::Runtime &runtime,
|
||||
// generated units. Runtime::register_function cannot intercept those
|
||||
// paths. The generated corpus now reads g_draw_distance_runtime_scales
|
||||
// at the exact labels instead, so do not install misleading dead hooks.
|
||||
std::cerr << "[draw-distance] entity/vehicle/NPC path=generated-local-label" << "\n";
|
||||
std::cerr << "[draw-distance] entity path=verified WidescreenFix semantic + vehicle/NPC local constants" << "\n";
|
||||
}
|
||||
std::cerr << "[draw-distance] enabled"
|
||||
<< " world=" << g_config.world
|
||||
<< " vehicles=" << g_config.vehicles
|
||||
<< " npcs=" << g_config.npcs
|
||||
<< " entity_lod=" << std::max(g_config.vehicles, g_config.npcs)
|
||||
<< " entity_lod=" << std::max({g_config.world, g_config.vehicles, g_config.npcs})
|
||||
<< "\n";
|
||||
{
|
||||
std::ostringstream line;
|
||||
line << "draw-distance config enabled=1"
|
||||
<< " world=" << g_config.world
|
||||
<< " vehicles=" << g_config.vehicles
|
||||
<< " npcs=" << g_config.npcs
|
||||
<< " common_lod=" << std::max({g_config.world, g_config.vehicles, g_config.npcs});
|
||||
runtime_log_line(line.str());
|
||||
}
|
||||
}
|
||||
|
||||
void draw_distance_world_table_ready(psprecomp::Runtime &runtime,
|
||||
std::uint32_t guest_gp) noexcept {
|
||||
if (!g_config.enabled || g_config.world <= 1.0f || guest_gp == 0u) return;
|
||||
try {
|
||||
if (patch_world_model_table(runtime, guest_gp)) {
|
||||
std::cerr << "[draw-distance] world table patched at authoritative IDE init"
|
||||
<< " gp=" << psprecomp::hex32(guest_gp) << "\n";
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "[draw-distance] world IDE init patch skipped: " << e.what() << "\n";
|
||||
} catch (...) {
|
||||
std::cerr << "[draw-distance] world IDE init patch skipped: unknown exception\n";
|
||||
}
|
||||
}
|
||||
|
||||
void draw_distance_vblank_tick(psprecomp::Runtime &runtime,
|
||||
std::uint32_t guest_gp,
|
||||
std::uint64_t vblank_index) noexcept {
|
||||
if (!g_config.enabled || g_config.world <= 1.0f || guest_gp == 0u) return;
|
||||
if (!g_config.enabled || guest_gp == 0u) return;
|
||||
try {
|
||||
const std::uint32_t far_address = guest_gp + kGpFarClipOffset;
|
||||
if (runtime.memory().contains(far_address, sizeof(std::uint32_t))) {
|
||||
const float current = load_float(runtime, far_address);
|
||||
if (std::isfinite(current) && current > 0.0f) {
|
||||
// Never multiply our own value again. If the game writes a new
|
||||
// dynamic far clip (weather/interior/etc.), treat that new value
|
||||
// as the next raw baseline and scale it exactly once.
|
||||
if (!g_far_clip_seen ||
|
||||
(!nearly_equal(current, g_far_clip_last_scaled) &&
|
||||
!nearly_equal(current, g_far_clip_last_raw))) {
|
||||
g_far_clip_seen = true;
|
||||
g_far_clip_last_raw = current;
|
||||
g_far_clip_last_scaled = current * g_config.world;
|
||||
}
|
||||
if (g_far_clip_seen && !nearly_equal(current, g_far_clip_last_scaled))
|
||||
store_float(runtime, far_address, g_far_clip_last_scaled);
|
||||
}
|
||||
}
|
||||
|
||||
// The model-info table can appear after the first gameplay vblanks and
|
||||
// can be repopulated by streaming. Retry aggressively at startup, then
|
||||
// refresh twice a second-ish without touching generated guest code.
|
||||
if (vblank_index < 240u || (vblank_index % 120u) == 0u)
|
||||
// Far clip is now multiplied at the actual CDraw::SetFarClipZ AOT
|
||||
// setter (0x08A1AD6C), so vblank must never multiply it a second time.
|
||||
// World model-info is still refreshed here because streaming may rebuild
|
||||
// entries after the original IDE load.
|
||||
if (g_config.world > 1.0f &&
|
||||
(vblank_index < 240u || (vblank_index % 120u) == 0u))
|
||||
(void)patch_world_model_table(runtime, guest_gp);
|
||||
|
||||
if ((vblank_index % 120u) == 0u) {
|
||||
const std::uint32_t count = runtime.memory().contains(
|
||||
guest_gp + kGpIdeCountOffset, sizeof(std::uint32_t))
|
||||
? runtime.memory().load32(guest_gp + kGpIdeCountOffset) : 0u;
|
||||
const std::uint32_t table = runtime.memory().contains(
|
||||
guest_gp + kGpIdeTableOffset, sizeof(std::uint32_t))
|
||||
? runtime.memory().load32(guest_gp + kGpIdeTableOffset) : 0u;
|
||||
float far_clip = 0.0f;
|
||||
if (runtime.memory().contains(guest_gp + kGpFarClipOffset,
|
||||
sizeof(std::uint32_t)))
|
||||
far_clip = load_float(runtime, guest_gp + kGpFarClipOffset);
|
||||
std::ostringstream line;
|
||||
line << "draw-distance telemetry vblank=" << vblank_index
|
||||
<< " gp=" << psprecomp::hex32(guest_gp)
|
||||
<< " far_clip=" << far_clip
|
||||
<< " model_count=" << count
|
||||
<< " model_table=" << psprecomp::hex32(table)
|
||||
<< " far_set_hits=" << g_draw_distance_runtime_telemetry.far_clip_set_hits
|
||||
<< " actor_hits=" << g_draw_distance_runtime_telemetry.actor_lod_hits
|
||||
<< " npc_hits=" << g_draw_distance_runtime_telemetry.npc_constant_hits
|
||||
<< " veh_dynamic_hits=" << g_draw_distance_runtime_telemetry.vehicle_dynamic_hits
|
||||
<< " veh_fallback_hits=" << g_draw_distance_runtime_telemetry.vehicle_fallback_hits
|
||||
<< " table_patch_hits=" << g_draw_distance_runtime_telemetry.world_table_patch_hits
|
||||
<< " world_models_written=" << g_draw_distance_runtime_telemetry.world_models_patched;
|
||||
runtime_log_line(line.str());
|
||||
}
|
||||
} catch (const std::exception &error) {
|
||||
static bool logged = false;
|
||||
if (!logged) {
|
||||
logged = true;
|
||||
std::cerr << "[draw-distance] vblank maintenance disabled after error: "
|
||||
<< error.what() << "\n";
|
||||
runtime_log_error("draw-distance telemetry", error.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,23 +8,40 @@ namespace psprecomp { class Runtime; }
|
||||
namespace vcs {
|
||||
|
||||
struct DrawDistanceRuntimeScales {
|
||||
float world{1.0f};
|
||||
float entity{1.0f};
|
||||
float vehicles{1.0f};
|
||||
float npcs{1.0f};
|
||||
};
|
||||
|
||||
// Read-only after profile installation. Generated AOT code reads these three
|
||||
// values directly at the exact local labels that the old Runtime hook could
|
||||
// not intercept.
|
||||
struct DrawDistanceRuntimeTelemetry {
|
||||
std::uint64_t far_clip_set_hits{};
|
||||
std::uint64_t actor_lod_hits{};
|
||||
std::uint64_t npc_constant_hits{};
|
||||
std::uint64_t vehicle_dynamic_hits{};
|
||||
std::uint64_t vehicle_fallback_hits{};
|
||||
std::uint64_t world_table_patch_hits{};
|
||||
std::uint64_t world_models_patched{};
|
||||
};
|
||||
|
||||
// Scales are read-only after profile installation. Generated AOT code reads
|
||||
// them directly at exact local labels that Runtime function hooks cannot
|
||||
// intercept. Telemetry counters are incremented by those same sites.
|
||||
extern DrawDistanceRuntimeScales g_draw_distance_runtime_scales;
|
||||
extern DrawDistanceRuntimeTelemetry g_draw_distance_runtime_telemetry;
|
||||
|
||||
void install_draw_distance_patch(psprecomp::Runtime &runtime,
|
||||
const std::filesystem::path &ini_path);
|
||||
|
||||
// Authoritative world-distance maintenance point. Called once per display
|
||||
// vblank so it cannot be bypassed by generated AOT local gotos.
|
||||
// Streaming refresh/telemetry point. The authoritative far-clip write itself
|
||||
// is patched at its generated AOT setter.
|
||||
void draw_distance_vblank_tick(psprecomp::Runtime &runtime,
|
||||
std::uint32_t guest_gp,
|
||||
std::uint64_t vblank_index) noexcept;
|
||||
|
||||
// Called by generated VCS AOT at the exact completion point of the IDE/model
|
||||
// info table initializer. This avoids relying on a vblank-time GP snapshot.
|
||||
void draw_distance_world_table_ready(psprecomp::Runtime &runtime,
|
||||
std::uint32_t guest_gp) noexcept;
|
||||
|
||||
} // namespace vcs
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "vcs_project2dfx.hpp"
|
||||
#include "vcs_project2dfx_lights.hpp"
|
||||
#include "vcs_draw_distance_patch.hpp"
|
||||
#include "ge_gpu_backend.hpp"
|
||||
#include "psprecomp/runtime.hpp"
|
||||
|
||||
@@ -580,10 +579,6 @@ void install_project2dfx(psprecomp::Runtime &runtime,
|
||||
std::uint32_t guest_scratch_base){
|
||||
g_runtime=&runtime;g_projection_scratch=guest_scratch_base;
|
||||
g_ini_path=ini_path;g_cfg=read_config(ini_path);g_camera_candidates.clear();g_hot_camera=nullptr;g_hot_camera_revision=0u;g_hot_camera_target=0u;g_last_rendered_vblank=std::numeric_limits<std::uint64_t>::max();
|
||||
// O draw distance tem [DrawDistance] Enabled proprio e nao faz parte do
|
||||
// Project2DFX original, entao instala antes do return abaixo. Estava depois
|
||||
// dele, o que amarrava um recurso independente ao outro sem dizer nada.
|
||||
install_draw_distance_patch(runtime,ini_path);
|
||||
if(!g_cfg.enabled){std::cerr<<"[Project2DFX] disabled\n";return;}
|
||||
if(g_cfg.performance_log){
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -89,14 +89,16 @@ void runtime_log_initialize(const VcsConfiguration &configuration) {
|
||||
<< " gpr_shadow_clusters=4 gpr_shadow_regs=24 gpr_shadow_occurrences=3461 geometry_shadow=0"
|
||||
<< " perf_layer=16 cpu_lean_revision=2 cpu_aggressive_revision=10 correctness_revision=8272 recovery_from_821=1"
|
||||
<< " save_transaction=1 save_lifecycle_v82=1 sas_endflag_latched=1 sas_loop_history_restore=1"
|
||||
<< " atrac_virtual_source=1 atrac_stall_diag=1 atrac_stream_resident_status=1 atrac_nonloop_resident=-2 atrac_loop_resident=-3 output2_success_zero=1 output2_master_watermark=1 output2_late_catchup=0 save_repro_checkpoint=1 save_repro_trace=1 save_repro_hotkey_f8=1 save_repro_trace_hotkey_f10=1 save_repro_auto_restore=1 save_repro_dispatch_sample_stride=64 save_repro_passive_until_f8=1 save_repro_hle_hotpath=0 save_repro_ui_hotkeys=1 save_repro_f10_async_fallback=1 save_repro_collector_partial_bundle=1 save_repro_internal_ini_gate=1 save_repro_default_enabled=0 save_exitdelete_semantics=1 save_repro_legacy_exitdelete_repair=1 save_partition_reuse=1 news_atrac_v825_guard=1 runtime_chain_telemetry_default=0 arch_fastmem=1 aot_direct_fastmem_default=1 aot_hard_fastmem=1 aot_branchless_mem=1 aot_vfpu_block32=19455 aot_scalar_run_blocks=10665 aot_scalar_run_words=53173 aot_load_runs=5633 aot_store_runs=5032 vfpu_default_dest_fast=1 vfpu_vmscl_default_fast=1 vfpu_default_fastlane=1 vfpu_vec3_fastlane_sites=2469 vfpu_unary_fastlane_sites=1607 vfpu_vdot_default_fast=1 vfpu_vscl_default_fast=1 radio_atrac_identity_guard=1 atrac_direct_header_validation=1 atrac_identity_cache=1 atrac_header_only_producer_hint=1 vfpu_vtfm_ct=1 vfpu_vtfm_ct_sites=337 vfpu_vi2f_ct=1 vfpu_vi2f_ct_sites=164 vfpu_vcmp_default_fast=1 vfpu_vcmp_ct_sites=558 vfpu_vcmov_default_fast=1 vfpu_vcmov_ct_sites=461 vfpu_cross_default_fast=1 vfpu_cross_ct_sites=217 vfpu_helper_ct2=1 trusted_chain=1 trusted_chain_sites=45968 trusted_chain_poisonable_sites=3240 compact_leaf_dispatch=1 compact_leaf_targets=4 compact_leaf_sites=1885 outer_entry_dispatch=1 outer_aot_view_reuse=1 v87_tiny_leaf_reverted=1 aot_register_residency=1 aot_register_residency_units=230 aot_gpr_resident_slots=6 aot_fpr_resident_slots=4 aot_gpr_resident_occurrences=914095 aot_fpr_resident_occurrences=146809 aot_resident_region_weight=6 resident_regions=1 resident_region_targets=83 resident_region_sites=11171 resident_region_files=220 resident_region_sync_out_removed=11171 resident_region_sync_in_removed=11171 resident_region_resident_args=53234 resident_region_ctx_args=26183 resident_region_scheduler_guard=1 resident_region_scheduler_fallback_sites=11171"
|
||||
<< " atrac_virtual_source=1 atrac_stall_diag=1 atrac_stream_resident_status=1 atrac_nonloop_resident=-2 atrac_loop_resident=-3 output2_success_zero=1 output2_master_watermark=1 output2_late_catchup=0 save_repro_checkpoint=1 save_repro_trace=1 save_repro_hotkey_f8=1 save_repro_trace_hotkey_f10=1 save_repro_auto_restore=1 save_repro_dispatch_sample_stride=64 save_repro_passive_until_f8=1 save_repro_hle_hotpath=0 save_repro_ui_hotkeys=1 save_repro_f10_async_fallback=1 save_repro_collector_partial_bundle=1 save_repro_internal_ini_gate=1 save_repro_default_enabled=0 save_exitdelete_semantics=1 save_repro_legacy_exitdelete_repair=1 save_partition_reuse=1 news_atrac_v825_guard=1 runtime_chain_telemetry_default=0 arch_fastmem=1 aot_direct_fastmem_default=1 aot_hard_fastmem=1 aot_branchless_mem=1 aot_vfpu_block32=19455 aot_scalar_run_blocks=10665 aot_scalar_run_words=53173 aot_load_runs=5633 aot_store_runs=5032 vfpu_default_dest_fast=1 vfpu_vmscl_default_fast=1 vfpu_default_fastlane=1 vfpu_vec3_fastlane_sites=2469 vfpu_unary_fastlane_sites=1607 vfpu_vdot_default_fast=1 vfpu_vscl_default_fast=1 radio_atrac_identity_guard=1 atrac_direct_header_validation=1 atrac_identity_cache=1 atrac_header_only_producer_hint=1 vfpu_vtfm_ct=1 vfpu_vtfm_ct_sites=337 vfpu_vi2f_ct=1 vfpu_vi2f_ct_sites=164 vfpu_vcmp_default_fast=1 vfpu_vcmp_ct_sites=558 vfpu_vcmov_default_fast=1 vfpu_vcmov_ct_sites=461 vfpu_cross_default_fast=1 vfpu_cross_ct_sites=217 vfpu_helper_ct2=1 trusted_chain=1 trusted_chain_sites=45968 trusted_chain_poisonable_sites=3240 compact_leaf_dispatch=1 compact_leaf_targets=4 compact_leaf_sites=1885 outer_entry_dispatch=1 outer_aot_view_reuse=1 v87_tiny_leaf_reverted=1 aot_register_residency=1 aot_register_residency_units=230 aot_gpr_resident_slots=6 aot_fpr_resident_slots=4 aot_gpr_resident_occurrences=914095 aot_fpr_resident_occurrences=146813 aot_resident_region_weight=6 resident_regions=1 resident_region_targets=83 resident_region_sites=11171 resident_region_files=220 resident_region_sync_out_removed=11171 resident_region_sync_in_removed=11171 resident_region_resident_args=53234 resident_region_ctx_args=26183 resident_region_scheduler_guard=1 resident_region_scheduler_fallback_sites=11171"
|
||||
<< " tier2_direct_fastmem=1 tier2_direct_mem_sites=1969 tier2_deep_telemetry_default=0 geometry_fusion_rollback=1"
|
||||
<< " entity_leaf_inline=1 entity_leaf_scheduler_accounting=1 entity_leaf_resume_pc_fix=1"
|
||||
<< " ge_async_default=0 parallel_vertex_decode_default=0"
|
||||
<< " v5_vfpu_fast_quarantined=1 native_vfpu_088b1780_v4=1"
|
||||
<< " dx12_execute_indirect_default=0 indirect_buffer_mb=4"
|
||||
<< " ge_async_quarantined=1 parallel_vertex_decode_quarantined=1 legacy_perf_env_ignored=1"
|
||||
<< " amd_uma_compat=1 uma_msaa_guard=1 packed0115_amd_stride=12\n\n";
|
||||
<< " amd_uma_compat=1 uma_msaa_guard=1 packed0115_amd_stride=12"
|
||||
<< " pipe_shadow_failsafe=1 material_shadow_scalar_probe=1"
|
||||
<< " draw_distance_common_world=1 draw_distance_fog_scale=1\n\n";
|
||||
if (s.flush_every_line) s.file.flush();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
SimulateHDR — upstream attribution and licence
|
||||
==============================================
|
||||
|
||||
The shaders in this directory are a port of SimulateHDR, the bloom and tone
|
||||
mapping post-process of ProperShaders (an advanced graphics mod for GTA San
|
||||
Andreas PC, DirectX 9 / Shader Model 3.0).
|
||||
|
||||
SimulateHDR is itself a fork of "Blooming HDR" by Jose Negrete, also known as
|
||||
BlueSkyDefender:
|
||||
|
||||
https://github.com/BlueSkyDefender/Depth3D
|
||||
|
||||
and is distributed under the Creative Commons Attribution-ShareAlike 4.0
|
||||
International licence (CC BY-SA 4.0):
|
||||
|
||||
https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
CHANGES WERE MADE. This port is a derivative work and is redistributed under
|
||||
the same CC BY-SA 4.0 terms.
|
||||
|
||||
|
||||
What was changed in this port
|
||||
-----------------------------
|
||||
|
||||
- Translated from HLSL ps_3_0 (.fx / .fxh effect files) to GLSL 450 compiled to
|
||||
SPIR-V for Vulkan.
|
||||
- The DirectX 9 effect framework is gone. Uniforms that arrived through
|
||||
ID3DXEffect::SetFloat/SetVectorArray are Vulkan push constants; textures bound
|
||||
by name are descriptor set bindings.
|
||||
- The fullscreen quad with a vertex buffer became a vertex-buffer-less
|
||||
fullscreen triangle derived from gl_VertexIndex.
|
||||
- The tone mapper is a uniform branch on a push constant instead of four
|
||||
compile-time technique specialisations (T#E#L#D#). ps_3_0 did not reward
|
||||
runtime branching; a desktop GPU running a branch that is uniform across the
|
||||
draw does.
|
||||
- HLSL mul(M, v) row-vector products were rewritten as GLSL column-major matrix
|
||||
products with the ACES matrices entered as columns.
|
||||
- Eye adaptation (AUTOEXP) is not ported: it needs a frame-average luminance
|
||||
read back to the host, which is the readback this port avoids by design.
|
||||
- The colour grading LUT (LUTMODE) is not ported: it needs PNG lookup tables.
|
||||
- The debug heat map (DEBUG) is not ported.
|
||||
|
||||
The three above collapse to their "off" branch, which is exactly what the
|
||||
upstream T#E0L0D0 technique variant compiled to.
|
||||
|
||||
|
||||
Due diligence carried over from the upstream headers
|
||||
----------------------------------------------------
|
||||
|
||||
Timothy Lottes tone mapper https://www.shadertoy.com/view/XljBRK
|
||||
ACES Cinematic fit Krzysztof Narkowicz and Stephen Hill, via MJP's
|
||||
BakingLab
|
||||
https://github.com/TheRealMJP/BakingLab
|
||||
Uncharted 2 tone mapper John Hable
|
||||
Eye adaptation Padraic Hennessy, MJP and David Neubelt,
|
||||
ported by prod80
|
||||
Bloom rework inspired by Adyss' bloom
|
||||
@@ -1,35 +0,0 @@
|
||||
#version 450
|
||||
//---------------------------------------------------------------------------//
|
||||
// SimulateHDR - separable blur, shared by all six blur passes.
|
||||
//
|
||||
// Ported from PS_BloomBlur in SimulateHDR_Bloom.fxh. See
|
||||
// shaders/hdr/LICENSE_SIMULATEHDR.txt (CC BY-SA 4.0). Changes were made.
|
||||
//
|
||||
// The kernel is uniform over the frame, so the host solves it once and hands
|
||||
// over four taps per side with the UV offset already scaled for this octave and
|
||||
// direction and the weight already normalised. Adjacent taps of the original
|
||||
// fourteen are merged into a single bilinear fetch at their weighted centroid,
|
||||
// preserving reach and total weight at eight fetches instead of fourteen.
|
||||
//
|
||||
// One shader serves every octave: a different image bound to u_input and a
|
||||
// different tap set is the whole difference between the six passes.
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D u_input;
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
vec4 taps[4]; // xy = UV offset, z = normalised weight
|
||||
} pc;
|
||||
|
||||
layout(location = 0) in vec2 v_uv;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
void main() {
|
||||
vec4 blur = vec4(0.0);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
const vec2 offset = pc.taps[i].xy;
|
||||
blur += (texture(u_input, v_uv + offset) +
|
||||
texture(u_input, v_uv - offset)) * pc.taps[i].z;
|
||||
}
|
||||
o_color = blur;
|
||||
}
|
||||
Binary file not shown.
@@ -1,35 +0,0 @@
|
||||
#version 450
|
||||
//---------------------------------------------------------------------------//
|
||||
// SimulateHDR - octave combine.
|
||||
//
|
||||
// Ported from PS_BloomCombine in SimulateHDR_Bloom.fxh. See
|
||||
// shaders/hdr/LICENSE_SIMULATEHDR.txt (CC BY-SA 4.0). Changes were made.
|
||||
//
|
||||
// Both the horizontal-only and the fully blurred target of each octave go into
|
||||
// the sum -- the horizontal ones are what give the bloom its streak, so
|
||||
// dropping them would change the look.
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D u_h_a;
|
||||
layout(set = 0, binding = 1) uniform sampler2D u_v_a;
|
||||
layout(set = 0, binding = 2) uniform sampler2D u_h_b;
|
||||
layout(set = 0, binding = 3) uniform sampler2D u_v_b;
|
||||
layout(set = 0, binding = 4) uniform sampler2D u_h_c;
|
||||
layout(set = 0, binding = 5) uniform sampler2D u_v_c;
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
float mix_scale; // intensity * 10 / 6 on the host side
|
||||
} pc;
|
||||
|
||||
layout(location = 0) in vec2 v_uv;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
void main() {
|
||||
vec3 bloom = texture(u_h_a, v_uv).rgb;
|
||||
bloom += texture(u_v_a, v_uv).rgb;
|
||||
bloom += texture(u_h_b, v_uv).rgb;
|
||||
bloom += texture(u_v_b, v_uv).rgb;
|
||||
bloom += texture(u_h_c, v_uv).rgb;
|
||||
bloom += texture(u_v_c, v_uv).rgb;
|
||||
o_color = vec4(bloom * pc.mix_scale, 0.0);
|
||||
}
|
||||
Binary file not shown.
@@ -1,147 +0,0 @@
|
||||
#version 450
|
||||
//---------------------------------------------------------------------------//
|
||||
// SimulateHDR - final full-screen composite.
|
||||
//
|
||||
// Ported from HDR_Composite in SimulateHDR_Final.fxh and the two operators in
|
||||
// SimulateHDR_Tonemap.fxh. See shaders/hdr/LICENSE_SIMULATEHDR.txt
|
||||
// (CC BY-SA 4.0). Changes were made.
|
||||
//
|
||||
// Deliberate differences from the DX9 original:
|
||||
// - The tone mapper is a uniform branch instead of four compile-time
|
||||
// specialisations. ps_3_0 did not reward runtime branching; a desktop GPU
|
||||
// running a push-constant branch that is uniform across the draw does.
|
||||
// - Eye adaptation and the colour grading LUT are not ported. AUTOEXP needed a
|
||||
// frame-average luminance read back to the host, which is the readback this
|
||||
// port avoids on purpose; LUTMODE needed PNG tables. Both collapse to their
|
||||
// "off" branch here, exactly as the T#E0L0D0 variant did.
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D u_scene;
|
||||
layout(set = 0, binding = 1) uniform sampler2D u_bloom;
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
vec4 timothy_curve; // (contrast, b, c, unused)
|
||||
vec4 timothy_cross; // (saturation/crossSat, crossSat, white point, unused)
|
||||
vec2 screen_size;
|
||||
float dither_amount;
|
||||
float bloom_opacity;
|
||||
float hdr_power;
|
||||
float exposure_bias;
|
||||
float gamma_in;
|
||||
float gamma_out;
|
||||
float saturate_amount;
|
||||
float contrast;
|
||||
float inv_white_point;
|
||||
int tonemap; // 0 = Timothy Lottes, 1 = ACES
|
||||
} pc;
|
||||
|
||||
layout(location = 0) in vec2 v_uv;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
float luma(vec3 c) { return dot(c, vec3(0.2126, 0.7152, 0.0722)); } // Rec. 709
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
// Interleaved gradient noise, three decorrelated channels off one dot product.
|
||||
//---------------------------------------------------------------------------//
|
||||
vec3 dither_noise(vec2 pixel_pos) {
|
||||
const float t = pixel_pos.x * 0.06711056 + pixel_pos.y * 0.00583715;
|
||||
return fract(52.9829189 * fract(t + vec3(0.0, 0.3183099, 0.6366198)));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
// Timothy Lottes. The shoulder term is fixed at 1.0, which collapses ColTone's
|
||||
// pow(z, shoulder) to z, so the curve is one pow plus a reciprocal.
|
||||
//---------------------------------------------------------------------------//
|
||||
vec3 timothy_tonemap(vec3 color, float exposure) {
|
||||
color *= exposure;
|
||||
|
||||
float peak = max(1e-6, max(color.r, max(color.g, color.b)));
|
||||
vec3 ratio = color / peak;
|
||||
|
||||
const float z = pow(peak, pc.timothy_curve.x);
|
||||
peak = z / (z * pc.timothy_curve.y + pc.timothy_curve.z);
|
||||
|
||||
// Channel crosstalk, wrapped in the saturation transform. The crosstalk
|
||||
// amount is pow(peak, 4), which is two multiplies rather than a real pow.
|
||||
ratio = pow(abs(ratio), vec3(pc.timothy_cross.x));
|
||||
const float peak2 = peak * peak;
|
||||
ratio = mix(ratio, vec3(pc.timothy_cross.z), peak2 * peak2);
|
||||
ratio = pow(abs(ratio), vec3(pc.timothy_cross.y));
|
||||
|
||||
return peak * ratio;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
// ACES fitted, after Stephen Hill / Krzysztof Narkowicz via MJP's BakingLab.
|
||||
//
|
||||
// HLSL mul(M, v) is a row-vector-times-matrix product; GLSL mat3 is column
|
||||
// major, so the same maths is written here as v * M with the rows entered as
|
||||
// columns. Transposing one and not the other is the classic way to port this
|
||||
// wrong and get a colour cast.
|
||||
//---------------------------------------------------------------------------//
|
||||
const mat3 kAcesInput = mat3(
|
||||
0.59719, 0.07600, 0.02840,
|
||||
0.35458, 0.90834, 0.13383,
|
||||
0.04823, 0.01566, 0.83777);
|
||||
|
||||
const mat3 kAcesOutput = mat3(
|
||||
1.60475, -0.10208, -0.00327,
|
||||
-0.53108, 1.10813, -0.07276,
|
||||
-0.07367, -0.00605, 1.07602);
|
||||
|
||||
vec3 rrt_and_odt_fit(vec3 v) {
|
||||
const vec3 a = v * (v + 0.0245786) - 0.000090537;
|
||||
const vec3 b = v * (0.983729 * v + 0.4329510) + 0.238081;
|
||||
return a / b;
|
||||
}
|
||||
|
||||
vec3 aces_tonemap(vec3 color, float exposure) {
|
||||
color *= exposure + 0.5; // the fit expects exposure pre-adjusted this way
|
||||
color = kAcesInput * color;
|
||||
color = rrt_and_odt_fit(color);
|
||||
color = kAcesOutput * color;
|
||||
return color * pc.inv_white_point;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 bloom = texture(u_bloom, v_uv).rgb;
|
||||
|
||||
const vec3 noise = dither_noise(v_uv * pc.screen_size);
|
||||
bloom = clamp(bloom + noise * smoothstep(0.0, 0.1, bloom) * pc.dither_amount,
|
||||
0.0, 1.0);
|
||||
bloom *= pc.bloom_opacity;
|
||||
|
||||
vec3 color = texture(u_scene, v_uv).rgb;
|
||||
|
||||
if (pc.tonemap == 1)
|
||||
color = mix(vec3(luma(color)), color, pc.saturate_amount);
|
||||
|
||||
// De-gamma into linear before anything else touches the colour.
|
||||
color = pow(abs(color), vec3(pc.gamma_in));
|
||||
|
||||
// Bloom goes in before the inverse tone map, otherwise the high range it is
|
||||
// supposed to feed has already been clipped away.
|
||||
color = max(vec3(0.0), color + bloom);
|
||||
|
||||
// Inverse tone map (Timothy Lottes fast reversible). The floor on the
|
||||
// denominator is not paranoia: a blown highlight is exactly 1.0 and
|
||||
// pow(1.0, g) is exactly 1.0, so the denominator hits zero wherever bloom
|
||||
// equals hdr_power. That gives INF, then INF/INF = NaN inside the ACES fit,
|
||||
// and a NaN lands in an 8-bit target as black -- dark patches in the
|
||||
// brightest part of a bloom. Clamping scales every channel by the same
|
||||
// factor, so hue is untouched.
|
||||
const float hdr_scale = (1.0 + max(pc.hdr_power, 0.001)) -
|
||||
max(color.r, max(color.g, color.b));
|
||||
color *= 1.0 / max(hdr_scale, 0.001);
|
||||
|
||||
color = (pc.tonemap == 0) ? timothy_tonemap(color, pc.exposure_bias)
|
||||
: aces_tonemap(color, pc.exposure_bias);
|
||||
|
||||
// gamma_out is 1/2.2, or 1.0 when the gamma conversion is switched off.
|
||||
color = pow(abs(color), vec3(pc.gamma_out));
|
||||
|
||||
if (pc.tonemap == 1)
|
||||
color = (color - 0.5) * pc.contrast + 0.5;
|
||||
|
||||
o_color = vec4(color, 1.0);
|
||||
}
|
||||
Binary file not shown.
@@ -1,39 +0,0 @@
|
||||
#version 450
|
||||
//---------------------------------------------------------------------------//
|
||||
// SimulateHDR - bright pass.
|
||||
//
|
||||
// Ported from PS_BloomExtract in SimulateHDR_Bloom.fxh. See
|
||||
// shaders/hdr/LICENSE_SIMULATEHDR.txt (CC BY-SA 4.0). Changes were made.
|
||||
//
|
||||
// Runs at quarter resolution straight off the scene copy; the bilinear fetch of
|
||||
// a full resolution source at reduced UVs is already a box filter, so no
|
||||
// explicit downsample is needed.
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D u_scene;
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
float sensitivity;
|
||||
float threshold;
|
||||
float saturation; // min(10, Saturation * 10) on the host side
|
||||
} pc;
|
||||
|
||||
layout(location = 0) in vec2 v_uv;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
float luma(vec3 c) { return dot(c, vec3(0.2126, 0.7152, 0.0722)); } // Rec. 709
|
||||
|
||||
void main() {
|
||||
vec3 c = texture(u_scene, v_uv).rgb;
|
||||
const float l = luma(c);
|
||||
|
||||
// Sensitivity curve, then divide out the luma so the threshold below is the
|
||||
// only thing deciding how bright a pixel ends up.
|
||||
c = pow(abs(c), vec3(pc.sensitivity)) / max(l, 0.001);
|
||||
|
||||
const float bright = max(0.0, l - pc.threshold);
|
||||
c *= bright;
|
||||
c = mix(vec3(bright), c, pc.saturation);
|
||||
|
||||
o_color = vec4(clamp(c, 0.0, 1.0), 0.0);
|
||||
}
|
||||
Binary file not shown.
@@ -1,17 +0,0 @@
|
||||
#version 450
|
||||
//---------------------------------------------------------------------------//
|
||||
// SimulateHDR - fullscreen triangle, shared by every pass.
|
||||
//
|
||||
// Ported to Vulkan/GLSL for VCSNative from ProperShaders' SimulateHDR, itself a
|
||||
// fork of "Blooming HDR" by Jose Negrete (BlueSkyDefender), CC BY-SA 4.0.
|
||||
// See shaders/hdr/LICENSE_SIMULATEHDR.txt. Changes were made.
|
||||
//
|
||||
// No vertex buffer: three vertices covering the screen, derived from the index.
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
layout(location = 0) out vec2 v_uv;
|
||||
|
||||
void main() {
|
||||
v_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
gl_Position = vec4(v_uv * 2.0 - 1.0, 0.0, 1.0);
|
||||
}
|
||||
Binary file not shown.
@@ -36,6 +36,7 @@ if "host/savedata_dialog.cpp" in (profile / "CMakeLists.txt").read_text(encoding
|
||||
require(generated / "generated_units.hpp", '#include "vcs_draw_distance_patch.hpp"',
|
||||
"generated draw-distance state header")
|
||||
checks = [
|
||||
("generated_unit_0133.cpp", "g_draw_distance_runtime_telemetry.far_clip_set_hits", "world far-clip setter"),
|
||||
("generated_unit_0136.cpp", "g_draw_distance_runtime_scales.entity", "entity local label"),
|
||||
("generated_unit_0113.cpp", "g_draw_distance_runtime_scales.npcs", "NPC local label"),
|
||||
("generated_unit_0208.cpp", "g_draw_distance_runtime_scales.vehicles", "vehicle local label"),
|
||||
@@ -43,10 +44,13 @@ checks = [
|
||||
for filename, needle, label in checks:
|
||||
require(generated / filename, needle, label)
|
||||
codegen = tools / "vcs_codegen_main.cpp"
|
||||
for pc in ("0x08A24128u", "0x089CB38Cu", "0x08B45AC0u"):
|
||||
for pc in ("0x08A1AD6Cu", "0x08A24128u", "0x08AEC918u", "0x089CB38Cu", "0x08B45AB8u", "0x08B45AC0u"):
|
||||
require(codegen, pc, f"future codegen preserves {pc}")
|
||||
require(host / "vcs_profile.cpp", "draw_distance_vblank_tick(rt, ctx.gpr[28], display_vblank_index);",
|
||||
"world draw-distance vblank maintenance")
|
||||
require(host / "vcs_draw_distance_patch.cpp",
|
||||
"std::max({g_config.world, g_config.vehicles, g_config.npcs})",
|
||||
"world multiplier participates in common camera/entity LOD gate")
|
||||
|
||||
dx12 = host / "ge_gpu_backend_dx12.cpp"
|
||||
require(dx12, "Dx12BlendPlan dx12_blend_plan", "DX12 generalized PSP blend mapper")
|
||||
@@ -54,11 +58,25 @@ require(dx12, "D3D12_BLEND_BLEND_FACTOR", "DX12 FIX blend constant")
|
||||
require(dx12, "D3D12_BLEND_INV_BLEND_FACTOR", "DX12 complementary FIX blend")
|
||||
require(dx12, "plan.src = D3D12_BLEND_SRC_ALPHA;", "DX12 safe translucent fallback")
|
||||
require(dx12, "PSPRECOMP_DX12_BLEND_DIAG", "DX12 unsupported-blend diagnostic")
|
||||
require(dx12, "g_draw_distance_runtime_scales.world", "DX12 world fog follows DrawDistance.World")
|
||||
require(dx12, "hw.fog_end * fog_distance_scale", "DX12 fog end is extended with draw distance")
|
||||
require(dx12, "hw.fog_slope / fog_distance_scale", "DX12 fog slope preserves scaled curve")
|
||||
require(dx12, "compile_pipe(pipe, false", "ProperShaders shadow-free material-pipe retry")
|
||||
require(dx12, "pipe compiled fallback:", "ProperShaders pipe recovery runtime marker")
|
||||
require(dx12, "constexpr UINT pipe_flags = D3DCOMPILE_OPTIMIZATION_LEVEL3;",
|
||||
"optional material pipes do not promote FXC warnings to fatal errors")
|
||||
private_shaders = host / "propershaders/private/PrivateShaders.cpp"
|
||||
require(private_shaders, "bool material_shadows", "ProperShaders separable material-shadow variant")
|
||||
require(private_shaders, "shadow_enabled ? proper_shaders_material_shadow_hlsl() : nullptr",
|
||||
"ProperShaders shadow-free fallback excludes receiver HLSL")
|
||||
for filename in ("BuildingPipe.cpp", "SkinPipe.cpp", "VehiclePipe.cpp"):
|
||||
pipe = host / "propershaders/private" / filename
|
||||
require(pipe, "#if PROPER_SHADOW_ENABLED", f"{filename} guards shadow hooks")
|
||||
|
||||
ini = (profile / "config/VCSNative.ini").read_text(encoding="utf-8", errors="replace")
|
||||
dd = ini.split("[DrawDistance]", 1)[1].split("[", 1)[0]
|
||||
if "Enabled=false" not in dd or "World=1.50" not in dd:
|
||||
errors.append("DrawDistance config must remain opt-in with 1.50x values prefilled")
|
||||
if "Enabled=true" not in dd or "Objects=2.00" not in dd or "Vehicles=2.00" not in dd or "NPCs=2.00" not in dd:
|
||||
errors.append("DrawDistance test profile must enable 2.00x objects/vehicles/NPCs")
|
||||
|
||||
if errors:
|
||||
print("CORRECTNESS 0.1 SOURCE AUDIT: FAIL")
|
||||
@@ -70,5 +88,7 @@ print("CORRECTNESS 0.1 SOURCE AUDIT: PASS")
|
||||
print(" - audio release/timing guards present")
|
||||
print(" - savedata LIST UI is firmware-style HLE rendered in the PSP framebuffer")
|
||||
print(" - draw-distance local AOT labels + regeneration hooks present")
|
||||
print(" - world distance participates in the common camera/entity LOD multiplier")
|
||||
print(" - ProperShaders material pipes survive a shadow-receiver compile failure")
|
||||
print(" - DX12 unsafe opaque blend fallback removed")
|
||||
print(" - draw distance remains opt-in for baseline FPS comparison")
|
||||
print(" - draw distance test profile enables 2x objects/vehicles/NPCs")
|
||||
|
||||
@@ -24,7 +24,7 @@ for token in (
|
||||
'resident_region_sync_in_removed=11171','resident_region_resident_args=53234',
|
||||
'resident_region_ctx_args=26183','resident_region_scheduler_guard=1',
|
||||
'resident_region_scheduler_fallback_sites=11171','aot_resident_region_weight=6',
|
||||
'aot_gpr_resident_occurrences=914095','aot_fpr_resident_occurrences=146809',
|
||||
'aot_gpr_resident_occurrences=914095','aot_fpr_resident_occurrences=146813',
|
||||
'radio_atrac_identity_guard=1','save_exitdelete_semantics=1','ge_async_default=0',
|
||||
'parallel_vertex_decode_default=0'):
|
||||
need(token in log,'metadata '+token)
|
||||
|
||||
@@ -20,7 +20,7 @@ for token in (
|
||||
'aot_register_residency=1','aot_register_residency_units=230',
|
||||
'aot_gpr_resident_slots=6','aot_fpr_resident_slots=4',
|
||||
('aot_gpr_resident_occurrences=914095' if is_v810 else 'aot_gpr_resident_occurrences=876226'),
|
||||
('aot_fpr_resident_occurrences=146809' if is_v810 else 'aot_fpr_resident_occurrences=145774'),
|
||||
('aot_fpr_resident_occurrences=146813' if is_v810 else 'aot_fpr_resident_occurrences=145774'),
|
||||
'trusted_chain=1','outer_aot_view_reuse=1','radio_atrac_identity_guard=1',
|
||||
'ge_async_default=0','parallel_vertex_decode_default=0'):
|
||||
need(token in log,'metadata '+token)
|
||||
@@ -38,8 +38,8 @@ need('PSPRECOMP_AOT_REGCACHE_BEGIN' in tool and 'AOT_REGCACHE_SYNC_OUT' in tool
|
||||
need('vcs' not in tool.lower() and '0x088' not in tool and '0x089' not in tool and '0x08a' not in tool.lower(),'generic optimizer has no VCS/address coupling')
|
||||
need(manifest['files']==234,'manifest corpus contains 234 units')
|
||||
if is_v810:
|
||||
need(manifest['gpr_occurrences']==914095 and manifest['gpr_total']==1266110 and manifest.get('resident_weight')==6,'V8.10 manifest GPR coverage/region weight exact')
|
||||
need(manifest['fpr_occurrences']==146809 and manifest['fpr_total']==198361,'V8.10 manifest FPR coverage exact')
|
||||
need(manifest['gpr_occurrences']==914095 and manifest['gpr_total']==1266111 and manifest.get('resident_weight')==6,'V8.10 manifest GPR coverage/region weight exact')
|
||||
need(manifest['fpr_occurrences']==146813 and manifest['fpr_total']==198365,'V8.10 manifest FPR coverage exact')
|
||||
else:
|
||||
need(manifest['gpr_occurrences']==876226 and manifest['gpr_total']==1188249,'manifest GPR coverage exact')
|
||||
need(manifest['fpr_occurrences']==145774 and manifest['fpr_total']==196805,'manifest FPR coverage exact')
|
||||
|
||||
@@ -172,7 +172,36 @@ int main() {
|
||||
"SAVE_REPRO must be disabled by default");
|
||||
{
|
||||
std::ofstream proper(root / "ProperShaders.ini", std::ios::trunc);
|
||||
proper << "[VolumetricClouds]\n"
|
||||
proper << "[ProperShaders]\n"
|
||||
<< "Enabled=true\n"
|
||||
<< "[BuildingPipe]\n"
|
||||
<< "Enabled=true\n"
|
||||
<< "[SkinPipe]\n"
|
||||
<< "Enabled=false\n"
|
||||
<< "[VehiclePipe]\n"
|
||||
<< "Enabled=true\n"
|
||||
<< "PaletteClassifier=false\n"
|
||||
<< "[RealtimeShadows]\n"
|
||||
<< "Enabled=true\n"
|
||||
<< "MapResolution=3072\n"
|
||||
<< "WorldRadius=220\n"
|
||||
<< "DepthRange=600\n"
|
||||
<< "MapBias=0.002\n"
|
||||
<< "PcfRadius=2\n"
|
||||
<< "UseCloudSunDirection=false\n"
|
||||
<< "LightDirectionX=0.2\n"
|
||||
<< "LightDirectionY=-0.4\n"
|
||||
<< "LightDirectionZ=0.9\n"
|
||||
<< "Strength=0.55\n"
|
||||
<< "DebugMode=6\n"
|
||||
<< "ContactShadows=false\n"
|
||||
<< "ContactStrength=0.31\n"
|
||||
<< "Steps=18\n"
|
||||
<< "MaxDistancePixels=64\n"
|
||||
<< "Thickness=0.003\n"
|
||||
<< "LightScreenX=-0.4\n"
|
||||
<< "LightScreenY=0.8\n"
|
||||
<< "[VolumetricClouds]\n"
|
||||
<< "Enabled=true\n"
|
||||
<< "DownscaleDiv=4\n"
|
||||
<< "Layers=3\n"
|
||||
@@ -192,7 +221,31 @@ int main() {
|
||||
"DirectX12 sync-recovery must force legacy GE async off");
|
||||
require(parallel_decode_default != nullptr && std::string(parallel_decode_default) == "0",
|
||||
"DirectX12 stable recovery must force parallel vertex decode off");
|
||||
const auto &clouds = vcs::vcs_configuration().volumetric_clouds;
|
||||
const auto &proper = vcs::vcs_configuration().proper_shaders;
|
||||
require(proper.enabled && proper.building_pipe.enabled && !proper.skin_pipe.enabled &&
|
||||
proper.vehicle_pipe.enabled && !proper.vehicle_pipe.palette_classifier,
|
||||
"ProperShaders material-pipe controls were not parsed");
|
||||
require(proper.realtime_shadows.enabled &&
|
||||
proper.realtime_shadows.map_resolution == 3072u &&
|
||||
std::abs(proper.realtime_shadows.world_radius - 220.0f) < 0.0001f &&
|
||||
std::abs(proper.realtime_shadows.depth_range - 600.0f) < 0.0001f &&
|
||||
std::abs(proper.realtime_shadows.map_bias - 0.002f) < 0.0001f &&
|
||||
proper.realtime_shadows.pcf_radius == 2u &&
|
||||
!proper.realtime_shadows.use_cloud_sun_direction &&
|
||||
std::abs(proper.realtime_shadows.light_direction_x - 0.2f) < 0.0001f &&
|
||||
std::abs(proper.realtime_shadows.light_direction_y + 0.4f) < 0.0001f &&
|
||||
std::abs(proper.realtime_shadows.light_direction_z - 0.9f) < 0.0001f &&
|
||||
std::abs(proper.realtime_shadows.strength - 0.55f) < 0.0001f &&
|
||||
proper.realtime_shadows.debug_mode == 6u &&
|
||||
!proper.realtime_shadows.contact_shadows &&
|
||||
std::abs(proper.realtime_shadows.contact_strength - 0.31f) < 0.0001f &&
|
||||
proper.realtime_shadows.steps == 18u &&
|
||||
std::abs(proper.realtime_shadows.max_distance_pixels - 64.0f) < 0.0001f &&
|
||||
std::abs(proper.realtime_shadows.thickness - 0.003f) < 0.0001f &&
|
||||
std::abs(proper.realtime_shadows.light_screen_x + 0.4f) < 0.0001f &&
|
||||
std::abs(proper.realtime_shadows.light_screen_y - 0.8f) < 0.0001f,
|
||||
"ProperShaders realtime-shadow controls were not parsed");
|
||||
const auto &clouds = proper.volumetric_clouds;
|
||||
require(clouds.enabled, "ProperShaders.ini VolumetricClouds.Enabled was not parsed");
|
||||
require(clouds.downscale_div == 4u && clouds.layers == 3u &&
|
||||
clouds.shadow_steps == 6u,
|
||||
|
||||
@@ -1000,22 +1000,40 @@ std::string emit_function_source(const GeneratedFunctionInput &function,
|
||||
break;
|
||||
}
|
||||
|
||||
// VCS draw-distance local-label patches. These addresses are valid
|
||||
// AOT entries, but normal gameplay reaches them through local gotos,
|
||||
// which bypasses Runtime::register_function replacements. Keep the
|
||||
// exact original path at scale 1.0 and only short-circuit when the
|
||||
// user explicitly enables extended draw distance.
|
||||
// VCS world far-clip extender. 0x08A1AD6C is the actual
|
||||
// CDraw::SetFarClipZ-style store into gp+7796. Multiply the value
|
||||
// immediately before the guest store so every camera mode observes
|
||||
// the configured world distance without vblank double-scaling.
|
||||
if (pc == 0x08A1AD6Cu) {
|
||||
body << " if (vcs::g_draw_distance_runtime_scales.world > 1.0f) {\n"
|
||||
<< " ++vcs::g_draw_distance_runtime_telemetry.far_clip_set_hits;\n"
|
||||
<< " ctx.fpr[12] *= vcs::g_draw_distance_runtime_scales.world;\n"
|
||||
<< " }\n";
|
||||
}
|
||||
|
||||
// VCS actor LOD extender. The established PSP VCS WidescreenFix
|
||||
// replaces the call at the 0x08A24128 site: it writes s0+0x7A0 from
|
||||
// s0+0x7A8 * multiplier and returns multiplier in f0. Reproduce that
|
||||
// exact semantic before the original call; 1.0 keeps stock behavior.
|
||||
if (pc == 0x08A24128u) {
|
||||
body << " if (vcs::g_draw_distance_runtime_scales.entity > 1.0f) {\n"
|
||||
<< " const float dd_base = std::bit_cast<float>(aot_mem.aot_load32(ctx.gpr[16] + static_cast<std::uint32_t>(1960)));\n"
|
||||
<< " ++vcs::g_draw_distance_runtime_telemetry.actor_lod_hits;\n"
|
||||
<< " const float dd_scale = vcs::g_draw_distance_runtime_scales.entity;\n"
|
||||
<< " aot_mem.aot_store32(ctx.gpr[16] + static_cast<std::uint32_t>(1952), std::bit_cast<std::uint32_t>(dd_base * dd_scale));\n"
|
||||
<< " const float dd_base = std::bit_cast<float>(aot_mem.aot_direct_load32(aot_gpr_16 + static_cast<std::uint32_t>(1960)));\n"
|
||||
<< " aot_mem.aot_direct_store32(aot_gpr_16 + static_cast<std::uint32_t>(1952), std::bit_cast<std::uint32_t>(dd_base * dd_scale));\n"
|
||||
<< " ctx.fpr[0] = dd_scale;\n"
|
||||
<< " goto L_08A24138;\n"
|
||||
<< " }\n";
|
||||
}
|
||||
// The model-info pointer table has just finished its initializer at
|
||||
// this local label. Patch world/timed-object LOD fields here, while
|
||||
// the guest GP and table are authoritative, instead of guessing at vblank.
|
||||
if (pc == 0x08AEC918u) {
|
||||
body << " vcs::draw_distance_world_table_ready(rt, ctx.gpr[28]);\n";
|
||||
}
|
||||
if (pc == 0x089CB38Cu) {
|
||||
body << " if (vcs::g_draw_distance_runtime_scales.npcs > 1.0f) {\n"
|
||||
<< " ++vcs::g_draw_distance_runtime_telemetry.npc_constant_hits;\n"
|
||||
<< " const float dd_scale = vcs::g_draw_distance_runtime_scales.npcs;\n"
|
||||
<< " ctx.gpr[19] = ctx.gpr[29] + static_cast<std::uint32_t>(64);\n"
|
||||
<< " ctx.gpr[30] = ctx.gpr[29] + static_cast<std::uint32_t>(16);\n"
|
||||
@@ -1031,8 +1049,19 @@ std::string emit_function_source(const GeneratedFunctionInput &function,
|
||||
<< " goto L_089CB3C8;\n"
|
||||
<< " }\n";
|
||||
}
|
||||
// The common vehicle path branches unconditionally from AB8 to AC8
|
||||
// after its delay-slot multiply, so patching only AC0 misses most cars.
|
||||
// Scale f12 immediately before that branch; the original delay-slot
|
||||
// multiply still runs and preserves the game's dynamic term.
|
||||
if (pc == 0x08B45AB8u) {
|
||||
body << " if (vcs::g_draw_distance_runtime_scales.vehicles > 1.0f) {\n"
|
||||
<< " ++vcs::g_draw_distance_runtime_telemetry.vehicle_dynamic_hits;\n"
|
||||
<< " ctx.fpr[12] *= vcs::g_draw_distance_runtime_scales.vehicles;\n"
|
||||
<< " }\n";
|
||||
}
|
||||
if (pc == 0x08B45AC0u) {
|
||||
body << " if (vcs::g_draw_distance_runtime_scales.vehicles > 1.0f) {\n"
|
||||
<< " ++vcs::g_draw_distance_runtime_telemetry.vehicle_fallback_hits;\n"
|
||||
<< " ctx.fpr[12] = 60.0f * vcs::g_draw_distance_runtime_scales.vehicles;\n"
|
||||
<< " goto L_08B45AC8;\n"
|
||||
<< " }\n";
|
||||
|
||||
Reference in New Issue
Block a user