mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-10-21 13:54:55 -04:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 66632f156f | |||
| 3cb375eced | |||
| e9f1fdd77c | |||
| ad95c5c7da | |||
| dfe32f61e1 | |||
| e3f5e3a3ec | |||
| 0321842569 | |||
| 35b552782f | |||
| 2f30417d61 |
@@ -4,3 +4,10 @@
|
||||
# Patch files must stay LF: git apply matches context bytes against LF upstream sources
|
||||
*.patch -text
|
||||
translator/tests/Translator.Tests/TestAssets/**/*.bin binary
|
||||
|
||||
# Region tables reproduced by tools/region/
|
||||
projects/mkwii-ntsc-*/MAP.txt linguist-generated=true
|
||||
projects/mkwii-ntsc-*/region_port.json linguist-generated=true
|
||||
projects/mkwii-ntsc-j/data_addresses.txt linguist-generated=true
|
||||
runtime/include/guest_abi/guest_address_table.inc linguist-generated=true
|
||||
runtime/include/guest_function_imports.inc linguist-generated=true
|
||||
|
||||
@@ -77,6 +77,7 @@ jobs:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Test macOS app dependency packaging
|
||||
shell: bash
|
||||
@@ -101,6 +102,7 @@ jobs:
|
||||
mkw_nand_settings_tests \
|
||||
mkw_sc_serial_tests \
|
||||
mkw_input_expr_tests \
|
||||
mkw_bluetooth_controller_tests \
|
||||
mkw_macos_native_compile \
|
||||
mkw_macos_context_abi_tests \
|
||||
mkw_macos_host_context_tests \
|
||||
|
||||
@@ -44,6 +44,7 @@ jobs:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-dotnet@v6
|
||||
with:
|
||||
@@ -79,6 +80,7 @@ jobs:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-dotnet@v6
|
||||
with:
|
||||
@@ -102,6 +104,7 @@ jobs:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-dotnet@v6
|
||||
with:
|
||||
@@ -235,6 +238,7 @@ jobs:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
# Wheel Wizard runs the downloaded setup with --version and refuses it when the reported
|
||||
# version differs from the release tag, so a tag that was pushed without bumping the pinned
|
||||
|
||||
@@ -16,6 +16,7 @@ jobs:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-dotnet@v6
|
||||
with:
|
||||
|
||||
+3
-1
@@ -66,7 +66,9 @@ project.lock.json
|
||||
/.vs/
|
||||
/.vscode/
|
||||
/.idea/
|
||||
/tools/
|
||||
/tools/*
|
||||
!/tools/region/
|
||||
__pycache__/
|
||||
/TEMP/
|
||||
/tmp/
|
||||
/test_output/
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[submodule "aurora-main"]
|
||||
path = aurora-main
|
||||
url = https://github.com/patchzyy/aurora-wiicompiled.git
|
||||
branch = main
|
||||
@@ -23,12 +23,23 @@ $publish = Join-Path $workRoot 'publish'
|
||||
$payloadRoot = Join-Path $workRoot 'payload'
|
||||
$setupProject = Join-Path $PSScriptRoot 'WiiCompiled.Setup.Windows\WiiCompiled.Setup.Windows.csproj'
|
||||
$translatorProject = Join-Path $repoRoot 'translator\src\Translator.Cli\Translator.Cli.csproj'
|
||||
$projectFile = Join-Path $repoRoot 'projects\mkwii\recomp.yml'
|
||||
|
||||
# Everything Mario-Kart-specific in the manifest below is read from the project file rather than
|
||||
# restated here, and Test-PinnedFacts.ps1 checks the copies that cannot read it (the C++ entry
|
||||
# address, the C# endpoint constant, the lists this script and the installed host both carry).
|
||||
$pins = Get-MkwProjectPins $projectFile
|
||||
# Every supported release is one projects/<name>/recomp.yml. Everything Mario-Kart-specific in the
|
||||
# manifest below is read from those files rather than restated here, and Test-PinnedFacts.ps1
|
||||
# checks the copies that cannot read them (the C++ entry address, the C# Retro-WFC table, the
|
||||
# lists this script and the installed host both carry).
|
||||
$releaseProjects = @(Get-ChildItem -LiteralPath (Join-Path $repoRoot 'projects') -Directory |
|
||||
Where-Object { Test-Path -LiteralPath (Join-Path $_.FullName 'recomp.yml') -PathType Leaf } |
|
||||
Sort-Object Name)
|
||||
if ($releaseProjects.Count -eq 0) { throw 'No translation project defines a supported release.' }
|
||||
$supportedReleases = @(foreach ($releaseProject in $releaseProjects) {
|
||||
$pins = Get-MkwProjectPins (Join-Path $releaseProject.FullName 'recomp.yml')
|
||||
[ordered]@{ GameId = $pins.GameId; DolSha256 = $pins.DolSha256; RelSha256 = $pins.RelSha256 }
|
||||
})
|
||||
foreach ($key in @('GameId', 'DolSha256')) {
|
||||
$duplicates = @($supportedReleases | Group-Object { $_[$key] } | Where-Object Count -gt 1)
|
||||
if ($duplicates.Count -gt 0) { throw "Two translation projects pin the same $($key): $($duplicates[0].Name)." }
|
||||
}
|
||||
# The audit reports by throwing, which aborts this run; nothing native has been invoked yet, so
|
||||
# there is no exit code to inspect.
|
||||
& (Join-Path $PSScriptRoot 'Test-PinnedFacts.ps1') -RepositoryRoot $repoRoot
|
||||
@@ -73,7 +84,16 @@ function Resolve-VcRuntimeDirectory([string]$RequestedPath) {
|
||||
function Copy-Directory([string]$Source, [string]$Destination) {
|
||||
Assert-Directory $Source "Source directory"
|
||||
[IO.Directory]::CreateDirectory($Destination) | Out-Null
|
||||
Copy-Item -Path (Join-Path $Source '*') -Destination $Destination -Recurse -Force
|
||||
# Source payloads are materialized trees, independent of Git checkout metadata.
|
||||
foreach ($entry in Get-ChildItem -LiteralPath $Source -Force) {
|
||||
if ($entry.Name -eq '.git') { continue }
|
||||
$target = Join-Path $Destination $entry.Name
|
||||
if ($entry.PSIsContainer) {
|
||||
Copy-Directory $entry.FullName $target
|
||||
} else {
|
||||
Copy-Item -LiteralPath $entry.FullName -Destination $target -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
function Compress-Zip([string]$Source, [string]$Destination, [string[]]$Entries) {
|
||||
$tar = Join-Path $env:SystemRoot 'System32\tar.exe'
|
||||
@@ -234,7 +254,9 @@ if (Test-Path -LiteralPath $runtimeDeveloperBuild) {
|
||||
}
|
||||
$auroraExtern = Join-Path $workspace 'aurora-main\extern'
|
||||
Get-ChildItem -LiteralPath $auroraExtern -Directory -Force | Remove-Item -Recurse -Force
|
||||
Copy-Directory (Join-Path $repoRoot 'projects\mkwii') (Join-Path $workspace 'projects\mkwii')
|
||||
foreach ($releaseProject in $releaseProjects) {
|
||||
Copy-Directory $releaseProject.FullName (Join-Path $workspace "projects\$($releaseProject.Name)")
|
||||
}
|
||||
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'LocalBuild.ps1') -Destination (Join-Path $workspace 'LocalBuild.ps1')
|
||||
# LocalBuild.ps1 dot-sources the canonical configure flags from this sibling.
|
||||
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'NativeBuildFlags.ps1') -Destination (Join-Path $workspace 'NativeBuildFlags.ps1')
|
||||
@@ -317,22 +339,20 @@ foreach ($required in @('ToolkitFingerprint','TranslationFingerprint','NativeToo
|
||||
$productVersion = ((& $setupHost --version) -join '').Trim()
|
||||
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($productVersion)) { throw 'The setup host did not report its version.' }
|
||||
|
||||
# Schema 3 replaced schema 2's single Expected* release fields with SupportedReleases.
|
||||
$manifest = [ordered]@{
|
||||
SchemaVersion = 2
|
||||
SchemaVersion = 3
|
||||
ProductVersion = $productVersion
|
||||
ExpectedGameId = $pins.GameId
|
||||
ExpectedDolSha256 = $pins.DolSha256
|
||||
ExpectedRelSha256 = $pins.RelSha256
|
||||
SupportedReleases = $supportedReleases
|
||||
ToolkitReleaseTag = if ($ToolkitReleaseTag) { $ToolkitReleaseTag } else { '' }
|
||||
BuildModel = 'local-translation-and-compilation'
|
||||
RetroWfcPayloadUri = $pins.RetroWfcPayloadUri
|
||||
ToolkitFingerprint = $identities.ToolkitFingerprint
|
||||
ToolkitPackageFingerprint = $identities.ToolkitPackageFingerprint
|
||||
RuntimeAssetsFingerprint = $identities.RuntimeAssetsFingerprint
|
||||
TranslationFingerprint = $identities.TranslationFingerprint
|
||||
NativeToolchainFingerprint = $identities.NativeToolchainFingerprint
|
||||
}
|
||||
$manifest | ConvertTo-Json | Set-Content (Join-Path $payloadRoot 'payload-manifest.json') -Encoding UTF8
|
||||
$manifest | ConvertTo-Json -Depth 4 | Set-Content (Join-Path $payloadRoot 'payload-manifest.json') -Encoding UTF8
|
||||
|
||||
Write-Host '[4/6] Enforcing the copyright and generated-code boundary...'
|
||||
# Both audits are PowerShell scripts that throw directly on failure (Test-PayloadBoundary.ps1
|
||||
|
||||
+16
-12
@@ -166,7 +166,6 @@ $toolchainBin = Join-Path $toolchain 'llvm-mingw\bin'
|
||||
$cc = Join-Path $toolchainBin 'x86_64-w64-mingw32-clang.exe'
|
||||
$cxx = Join-Path $toolchainBin 'x86_64-w64-mingw32-clang++.exe'
|
||||
$windres = Join-Path $toolchainBin 'x86_64-w64-mingw32-windres.exe'
|
||||
$project = Join-Path $Workspace 'projects\mkwii\recomp.yml'
|
||||
$assets = Join-Path $Workspace 'Assets'
|
||||
$generated = Join-Path $Workspace 'generated'
|
||||
$functions = Join-Path $generated 'functions'
|
||||
@@ -183,14 +182,18 @@ $retroRoot = if ([string]::IsNullOrWhiteSpace($RetroRewindPackageDirectory)) {
|
||||
|
||||
foreach ($required in @(
|
||||
@($translator, 'Bundled translator'), @($cmake, 'Bundled CMake'), @($ninja, 'Bundled Ninja'),
|
||||
@($cc, 'Bundled C compiler'), @($cxx, 'Bundled C++ compiler'), @($windres, 'Bundled resource compiler'), @($project, 'Translation project'),
|
||||
@($cc, 'Bundled C compiler'), @($cxx, 'Bundled C++ compiler'), @($windres, 'Bundled resource compiler'),
|
||||
@((Join-Path $assets 'main.dol'), 'Extracted main.dol'), @((Join-Path $assets 'StaticR.rel'), 'Extracted StaticR.rel')
|
||||
)) { Assert-File $required[0] $required[1] }
|
||||
|
||||
# Everything Mario-Kart-specific this script needs is read from the project file rather than
|
||||
# restated here: the translation entry point below, and (through the retro-rewind profile the
|
||||
# translator loads itself) the module guest/link bases the mod translation uses.
|
||||
$pins = Get-MkwProjectPins $project
|
||||
# translator loads itself) the module guest/link bases the mod translation uses. The project is
|
||||
# the one pinned to the extracted main.dol, which decides the region.
|
||||
$selectedProject = Resolve-MkwProjectForAssets $Workspace $assets
|
||||
$project = $selectedProject.Path
|
||||
$pins = $selectedProject.Pins
|
||||
$retroWfcPayloadFile = "binary\payload.$(($pins.RetroWfcPayloadUri -split 'g=')[-1]).bin"
|
||||
|
||||
# Three independent knobs: $translatorThreads (the translator's own worker threads; peak memory is
|
||||
# one heap that barely moves with thread count, so clamping it only slows translation), $translatedJobs
|
||||
@@ -243,7 +246,8 @@ try {
|
||||
# outputs plus --prune-stale mean Ninja only recompiles shards whose bytes actually moved.
|
||||
$reuseBase = $false
|
||||
if (-not $ForceCleanBuild -and -not [string]::IsNullOrWhiteSpace($TranslationFingerprint) -and
|
||||
(Get-RecordedFingerprint $translationProvenance 'TranslationFingerprint') -eq $TranslationFingerprint) {
|
||||
(Get-RecordedFingerprint $translationProvenance 'TranslationFingerprint') -eq $TranslationFingerprint -and
|
||||
(Get-RecordedFingerprint $translationProvenance 'DolSha256') -eq $pins.DolSha256) {
|
||||
$artifacts = @($baseMetadata, $baseManifest, (Join-Path $generated 'base_translation_sources.bin'),
|
||||
(Join-Path $generated 'base_translation_mod_awareness.json'))
|
||||
$reuseBase = -not ($artifacts | Where-Object { -not (Test-Path -LiteralPath $_ -PathType Leaf) })
|
||||
@@ -312,11 +316,11 @@ try {
|
||||
|
||||
Invoke-Checked $translator @(
|
||||
'emit-base-manifest', '--project', $project, '--out', $baseManifestDir,
|
||||
'--functions-dir', $functions, '--translation-output-metadata', $baseMetadata, '--region', 'P'
|
||||
'--functions-dir', $functions, '--translation-output-metadata', $baseMetadata, '--region', $pins.Region
|
||||
) 'Creating the local base translation manifest' -StepId 'emit-base-manifest'
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($TranslationFingerprint)) {
|
||||
[ordered]@{ SchemaVersion = 1; TranslationFingerprint = $TranslationFingerprint } |
|
||||
[ordered]@{ SchemaVersion = 1; TranslationFingerprint = $TranslationFingerprint; DolSha256 = $pins.DolSha256 } |
|
||||
ConvertTo-Json | Set-Content -LiteralPath $translationProvenance -Encoding UTF8
|
||||
}
|
||||
}
|
||||
@@ -329,14 +333,14 @@ try {
|
||||
'translate-mod', '--project', $project, '--profile', 'retro-rewind',
|
||||
'--base-manifest', $baseManifest, '--base-translation-output-metadata', $baseMetadata,
|
||||
'--code-pul', $codePul, '--mod-root', $retroRoot, '--mod-name', 'Retro Rewind',
|
||||
'--region', 'P', '--out', $retroOut, '--prefer-cached-inputs', '--emit-cpp',
|
||||
'--region', $pins.Region, '--out', $retroOut, '--prefer-cached-inputs', '--emit-cpp',
|
||||
'--threads', $translatorThreads
|
||||
)
|
||||
if ($SkipRetroWfcPayload) {
|
||||
$translateModArguments += '--skip-retro-wfc'
|
||||
} elseif (-not [string]::IsNullOrWhiteSpace($RetroWfcOfflineDirectory)) {
|
||||
$offlineRoot = [IO.Path]::GetFullPath($RetroWfcOfflineDirectory)
|
||||
$offlinePayload = Join-Path $offlineRoot 'binary\payload.RMCPD00.bin'
|
||||
$offlinePayload = Join-Path $offlineRoot $retroWfcPayloadFile
|
||||
Assert-File $offlinePayload 'Offline Retro-WFC shared payload'
|
||||
$translateModArguments += @('--retro-wfc-payload', $offlinePayload)
|
||||
} else {
|
||||
@@ -423,7 +427,7 @@ try {
|
||||
$exe = Join-Path $build "$Target.exe"
|
||||
Assert-File $exe 'Locally compiled game executable'
|
||||
Copy-Item -LiteralPath $exe -Destination (Join-Path $Destination "$Target.exe")
|
||||
foreach ($name in @('dxcompiler.dll','dxil.dll','libc++.dll','libpng16.dll','libunwind.dll','libz.dll','SDL3.dll','sqlite3.dll','webgpu_dawn.dll','z.dll','noshaders.zip','dsp_coef.bin','initial_pipeline_cache.db')) {
|
||||
foreach ($name in @('dxcompiler.dll','dxil.dll','libc++.dll','libpng16.dll','libunwind.dll','libz.dll','libzlib1.dll','SDL3.dll','sqlite3.dll','webgpu_dawn.dll','z.dll','noshaders.zip','dsp_coef.bin','initial_pipeline_cache.db')) {
|
||||
$file = Join-Path $build $name
|
||||
if (Test-Path -LiteralPath $file -PathType Leaf) { Copy-Item -LiteralPath $file -Destination $Destination }
|
||||
}
|
||||
@@ -447,8 +451,8 @@ try {
|
||||
RelSha256 = $relSha
|
||||
CodePulSha256 = if ($isRetro) { Get-MkwFileSha256 (Join-Path $retroRoot 'Binaries\Code.pul') } else { $null }
|
||||
RetroWfcPayloadMode = if (-not $isRetro) { $null } elseif ($SkipRetroWfcPayload) { 'skipped' } else { $RetroWfcPayloadOrigin }
|
||||
RetroWfcPayloadSha256 = if ($isRetro -and -not $SkipRetroWfcPayload) { Get-MkwFileSha256 (Join-Path $RetroWfcOfflineDirectory 'binary\payload.RMCPD00.bin') } else { $null }
|
||||
RetroWfcPayloadLength = if ($isRetro -and -not $SkipRetroWfcPayload) { (Get-Item -LiteralPath (Join-Path $RetroWfcOfflineDirectory 'binary\payload.RMCPD00.bin')).Length } else { $null }
|
||||
RetroWfcPayloadSha256 = if ($isRetro -and -not $SkipRetroWfcPayload) { Get-MkwFileSha256 (Join-Path $RetroWfcOfflineDirectory $retroWfcPayloadFile) } else { $null }
|
||||
RetroWfcPayloadLength = if ($isRetro -and -not $SkipRetroWfcPayload) { (Get-Item -LiteralPath (Join-Path $RetroWfcOfflineDirectory $retroWfcPayloadFile)).Length } else { $null }
|
||||
Compiler = "llvm-mingw clang-22 sha256:$compilerSha"
|
||||
}
|
||||
$provenance | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $Destination 'local-build.json') -Encoding UTF8
|
||||
|
||||
@@ -93,7 +93,7 @@ function Get-MkwBuildSafePath([string]$Path, [string]$Kind, [string]$MarkerFile)
|
||||
|
||||
function Get-MkwProjectPins([string]$ProjectFile) {
|
||||
<#
|
||||
The Mario Kart Wii facts pinned by projects/mkwii/recomp.yml (game identity, clean input
|
||||
The Mario Kart Wii facts pinned by a projects/*/recomp.yml (game identity, clean input
|
||||
digests, translation entry point, Retro-WFC endpoint), read from one place instead of being
|
||||
restated; Test-PinnedFacts.ps1 checks the copies that can't read YAML (C++ header, C#
|
||||
constants) against these values. Parsing is literal, not a YAML dependency, since the file is
|
||||
@@ -101,7 +101,7 @@ function Get-MkwProjectPins([string]$ProjectFile) {
|
||||
#>
|
||||
Assert-File $ProjectFile 'Translation project file'
|
||||
$pins = [ordered]@{
|
||||
GameId = ''; DolSha256 = ''; RelSha256 = ''; EntryPoint = ''; RetroWfcPayloadUri = ''
|
||||
GameId = ''; Region = ''; DolSha256 = ''; RelSha256 = ''; EntryPoint = ''; RetroWfcPayloadUri = ''
|
||||
}
|
||||
$section = ''
|
||||
$inputKey = ''
|
||||
@@ -112,6 +112,8 @@ function Get-MkwProjectPins([string]$ProjectFile) {
|
||||
if ($section -eq 'inputs' -and $line -match '^\s{2}([A-Za-z0-9_]+):\s*$') { $inputKey = $Matches[1]; continue }
|
||||
if ($section -eq 'project' -and $line -match '^\s*game_id:\s*(\S+)\s*$') {
|
||||
$pins.GameId = $Matches[1]
|
||||
} elseif ($section -eq 'project' -and $line -match '^\s*region:\s*(\S+)\s*$') {
|
||||
$pins.Region = $Matches[1]
|
||||
} elseif ($section -eq 'inputs' -and $line -match '^\s*sha256:\s*([0-9a-fA-F]{64})\s*$') {
|
||||
if ($inputKey -eq 'dol') { $pins.DolSha256 = $Matches[1].ToLowerInvariant() }
|
||||
elseif ($inputKey -eq 'rel') { $pins.RelSha256 = $Matches[1].ToLowerInvariant() }
|
||||
@@ -130,6 +132,30 @@ function Get-MkwProjectPins([string]$ProjectFile) {
|
||||
return $pins
|
||||
}
|
||||
|
||||
function Resolve-MkwProjectForAssets([string]$Workspace, [string]$AssetsDirectory) {
|
||||
<#
|
||||
The translation project pinned to the main.dol in AssetsDirectory, after checking that
|
||||
StaticR.rel and any extracted disc data belong to the same release.
|
||||
#>
|
||||
$dolSha = Get-MkwFileSha256 (Join-Path $AssetsDirectory 'main.dol')
|
||||
foreach ($file in Get-ChildItem -LiteralPath (Join-Path $Workspace 'projects') -Filter 'recomp.yml' -Recurse -File) {
|
||||
$pins = Get-MkwProjectPins $file.FullName
|
||||
if ($pins.DolSha256 -ne $dolSha) { continue }
|
||||
if ((Get-MkwFileSha256 (Join-Path $AssetsDirectory 'StaticR.rel')) -ne $pins.RelSha256) {
|
||||
throw "StaticR.rel does not match the clean $($pins.GameId) release of main.dol."
|
||||
}
|
||||
$bootBin = Join-Path $AssetsDirectory 'DATA\sys\boot.bin'
|
||||
if (Test-Path -LiteralPath $bootBin -PathType Leaf) {
|
||||
$discId = [Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($bootBin), 0, 6)
|
||||
if ($discId -ne $pins.GameId) {
|
||||
throw "The extracted game data is $discId but main.dol is $($pins.GameId); extract the game again."
|
||||
}
|
||||
}
|
||||
return [pscustomobject]@{ Path = $file.FullName; Pins = $pins }
|
||||
}
|
||||
throw "main.dol (sha256 $dolSha) is not a supported clean Mario Kart Wii release."
|
||||
}
|
||||
|
||||
function Invoke-Checked([string]$FilePath, [string[]]$Arguments, [string]$Description,
|
||||
[string]$LogPrefix = 'MKWCBUILD', [string]$StepId = '', [bool]$WaitForProcessTree = $true) {
|
||||
<#
|
||||
@@ -153,8 +179,15 @@ function Invoke-Checked([string]$FilePath, [string[]]$Arguments, [string]$Descri
|
||||
-NoNewWindow -Wait -PassThru
|
||||
$exitCode = $process.ExitCode
|
||||
} else {
|
||||
& $FilePath @Arguments
|
||||
$exitCode = $LASTEXITCODE
|
||||
# Tools report progress on stderr (CMake message()); only the exit code decides failure.
|
||||
$previousPreference = $ErrorActionPreference
|
||||
$ErrorActionPreference = 'Continue'
|
||||
try {
|
||||
& $FilePath @Arguments
|
||||
$exitCode = $LASTEXITCODE
|
||||
} finally {
|
||||
$ErrorActionPreference = $previousPreference
|
||||
}
|
||||
}
|
||||
$global:LASTEXITCODE = $exitCode
|
||||
if ($exitCode -ne 0) { throw "$Description failed with exit code $exitCode." }
|
||||
|
||||
@@ -21,16 +21,21 @@ $auroraExtern = Join-Path $repoRoot 'aurora-main\extern\CMakeLists.txt'
|
||||
$auroraDawn = Join-Path $repoRoot 'aurora-main\cmake\AuroraDawnProvider.cmake'
|
||||
$auroraLibUsb = Join-Path $repoRoot 'aurora-main\cmake\AuroraLibUSB.cmake'
|
||||
$auroraSdl = Join-Path $repoRoot 'aurora-main\cmake\AuroraSDL3Provider.cmake'
|
||||
$auroraVersions = Join-Path $repoRoot 'aurora-main\cmake\AuroraDependencyVersions.cmake'
|
||||
$auroraImgui = Join-Path $repoRoot 'aurora-main\cmake\AuroraDearImguiProvider.cmake'
|
||||
if (-not (Test-Path -LiteralPath $auroraCMake -PathType Leaf)) {
|
||||
throw 'Aurora sources are missing. Run git submodule update --init --recursive from the repository root first.'
|
||||
}
|
||||
|
||||
# Name = directory under the destination; FetchContent maps it back through
|
||||
# FETCHCONTENT_SOURCE_DIR_<UPPERCASE NAME> (NativeBuildFlags.ps1), so the names are the declared
|
||||
# FetchContent names, not the upstream project names.
|
||||
$packages = @(
|
||||
[pscustomobject]@{
|
||||
Name = 'SDL'; File = 'SDL3-3.4.4.tar.gz'
|
||||
Uris = @('https://github.com/libsdl-org/SDL/releases/download/release-3.4.4/SDL3-3.4.4.tar.gz')
|
||||
Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_SDL3_VERSION "3.4.4"' },
|
||||
@{ File = $auroraSdl; Text = 'releases/download/release-${AURORA_SDL3_VERSION}/SDL3-${AURORA_SDL3_VERSION}.tar.gz' })
|
||||
Name = 'SDL'; File = 'SDL3-3.4.10.tar.gz'
|
||||
Uris = @('https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-3.4.10.tar.gz')
|
||||
Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_SDL3_REF "refs/tags/release-3.4.10"' },
|
||||
@{ File = $auroraSdl; Text = 'URL "https://github.com/libsdl-org/SDL/archive/${AURORA_SDL3_REF}.tar.gz"' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'abseil-cpp'; File = 'abseil-cpp-20240722.0.tar.gz'
|
||||
@@ -38,15 +43,15 @@ $packages = @(
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'dawn_prebuilt'; File = 'dawn-v20260603.191052-windows-amd64.tar.gz'
|
||||
Uris = @('https://github.com/theofficialgman/dawn-build/releases/download/v20260603.191052/dawn-windows-amd64.tar.gz')
|
||||
Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_DAWN_VERSION "v20260603.191052"' },
|
||||
@{ File = $auroraDawn; Text = 'SHA256=13be9cff8b9b179c42dcd16aeabb6effcc8f0dfdcc14463eda2a5caeda225142' })
|
||||
Name = 'dawn_prebuilt'; File = 'dawn-v20260807.225922-windows-amd64.tar.gz'
|
||||
Uris = @('https://github.com/encounter/dawn/releases/download/v20260807.225922/dawn-windows-amd64.tar.gz')
|
||||
Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_DAWN_VERSION "v20260807.225922"' },
|
||||
@{ File = $auroraDawn; Text = 'SHA256=42a7a295c87b2e8a36312e2f84a5823aac63325e8e1d271bc7ced6f83bfb075f' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'fmt'; File = 'fmt-11.1.4.tar.gz'
|
||||
Uris = @('https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz' })
|
||||
Name = 'fmt'; File = 'fmt-12.1.0.tar.gz'
|
||||
Uris = @('https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.tar.gz')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.tar.gz' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'freetype'; File = 'freetype-2.14.3.tar.gz'
|
||||
@@ -58,12 +63,12 @@ $packages = @(
|
||||
[pscustomobject]@{
|
||||
Name = 'imgui'; File = 'imgui-1.91.9b-docking.tar.gz'
|
||||
Uris = @('https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz' })
|
||||
Pins = @(@{ File = $auroraImgui; Text = 'https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'libusb'; File = 'libusb-1.0.30.tar.bz2'
|
||||
Uris = @('https://github.com/libusb/libusb/releases/download/v1.0.30/libusb-1.0.30.tar.bz2')
|
||||
Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_LIBUSB_VERSION "1.0.30"' },
|
||||
Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_LIBUSB_VERSION "1.0.30"' },
|
||||
@{ File = $auroraLibUsb; Text = 'releases/download/v${AURORA_LIBUSB_VERSION}/libusb-${AURORA_LIBUSB_VERSION}.tar.bz2' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
@@ -77,9 +82,9 @@ $packages = @(
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://sqlite.org/2026/sqlite-amalgamation-3510300.zip' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'tracy'; File = 'tracy-a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz'
|
||||
Uris = @('https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz' })
|
||||
Name = 'tracy'; File = 'tracy-0.14.1.zip'
|
||||
Uris = @('https://github.com/wolfpld/tracy/archive/refs/tags/v0.14.1.zip')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/wolfpld/tracy/archive/refs/tags/v0.14.1.zip' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'xxhash'; File = 'xxHash-0.8.4.tar.gz'
|
||||
@@ -87,9 +92,9 @@ $packages = @(
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'zlib'; File = 'zlib-1.3.2.tar.gz'
|
||||
Uris = @('https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz' })
|
||||
Name = 'zlib'; File = 'zlib-ng-2.3.3.tar.gz'
|
||||
Uris = @('https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.3.3.tar.gz')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.3.3.tar.gz' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'zstd'; File = 'zstd-1.5.7.tar.gz'
|
||||
@@ -168,8 +173,12 @@ function Expand-Package([string]$Archive, [string]$Target) {
|
||||
foreach ($package in $packages) {
|
||||
Assert-Pinned $package
|
||||
$target = Join-Path $Destination $package.Name
|
||||
if (Test-Path -LiteralPath $target -PathType Container) { continue }
|
||||
# Records which archive a tree came from, so a pin change replaces a stale tree.
|
||||
$stamp = $target + '.source'
|
||||
$current = (Test-Path -LiteralPath $stamp -PathType Leaf) -and ([IO.File]::ReadAllText($stamp) -eq $package.File)
|
||||
if ($current -and (Test-Path -LiteralPath $target -PathType Container)) { continue }
|
||||
Expand-Package (Get-Archive $package) $target
|
||||
[IO.File]::WriteAllText($stamp, $package.File)
|
||||
Write-Host "Prepared $($package.Name)"
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ fingerprint_tree() {
|
||||
local root=$1; shift
|
||||
root=$(normalize "$root")
|
||||
[[ -d "$root" ]] || return 0
|
||||
local find_args=("$root")
|
||||
local find_args=("$root" -name .git -prune -o)
|
||||
local ex
|
||||
for ex in "$@"; do find_args+=(-path "$root/$ex" -prune -o); done
|
||||
find_args+=(-type f -print)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Fails the release build when a fact duplicated across the repo stops agreeing with the copy
|
||||
# that owns it (recomp.yml). Scripts read pinned facts through Get-MkwProjectPins, but three
|
||||
# consumers can't read YAML (the C++ runtime header, the C# constants, shell scripts, and hand-written lists on
|
||||
# both sides of the C#/PowerShell boundary), so those are checked here instead.
|
||||
# that owns it (each projects/*/recomp.yml). Scripts read pinned facts through Get-MkwProjectPins
|
||||
# or build-cache.sh's mkw_project_pin, but some consumers can't read YAML (the C++ runtime header,
|
||||
# the C# Retro-WFC table, and hand-written lists on both sides of the C#/PowerShell boundary), so
|
||||
# those are checked here instead.
|
||||
[CmdletBinding()]
|
||||
param([string]$RepositoryRoot)
|
||||
|
||||
@@ -46,32 +47,36 @@ function Compare-Set([string[]]$Expected, [string[]]$Actual, [string]$ExpectedNa
|
||||
if ($extra.Count -gt 0) { Add-Failure "$ActualName has entries $ExpectedName does not: $($extra -join ', ')." }
|
||||
}
|
||||
|
||||
$pins = Get-MkwProjectPins (Join-Path $repoRoot 'projects\mkwii\recomp.yml')
|
||||
# Every supported release is one projects/<name>/recomp.yml, the same set Build-Installer.ps1 ships.
|
||||
$releases = @(Get-ChildItem -LiteralPath (Join-Path $repoRoot 'projects') -Directory | Sort-Object Name |
|
||||
ForEach-Object { Join-Path $_.FullName 'recomp.yml' } | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } |
|
||||
ForEach-Object { $pins = Get-MkwProjectPins $_; $pins.Project = $_; [pscustomobject]$pins })
|
||||
if ($releases.Count -eq 0) { throw 'No projects/*/recomp.yml was found; update Test-PinnedFacts.ps1.' }
|
||||
|
||||
# --- The Retro-WFC endpoint: recomp.yml owns it; the installer host pins the same string so a
|
||||
# --- redirected or rewritten endpoint cannot be fetched from. The literal lives in
|
||||
# --- WiiCompiled.Setup.Common (shared with WiiCompiled.Setup.Linux) - InputValidation.cs only
|
||||
# --- re-exports it as `= RetroWfcPayload.CurrentRetroWfcPayloadUri;`, no literal to capture there.
|
||||
# --- The Retro-WFC endpoints: each recomp.yml owns its release's; the host derives the same URL
|
||||
# --- from its game table so a redirected or rewritten endpoint cannot be fetched from.
|
||||
$retroWfcPayload = Read-SourceFile (Join-Path $common 'RetroWfcPayload.cs') 'RetroWfcPayload.cs'
|
||||
$hostUri = Get-CapturedValue $retroWfcPayload 'CurrentRetroWfcPayloadUri\s*=\s*"([^"]+)"' `
|
||||
'The host Retro-WFC endpoint constant'
|
||||
if ($hostUri -cne $pins.RetroWfcPayloadUri) {
|
||||
Add-Failure "InputValidation.CurrentRetroWfcPayloadUri is '$hostUri' but recomp.yml pins '$($pins.RetroWfcPayloadUri)'."
|
||||
$payloadGames = @{}
|
||||
foreach ($entry in [regex]::Matches((Get-CapturedValue $retroWfcPayload `
|
||||
'(?s)PayloadGames\s*=\s*new\([^)]*\)\s*\{(.*?)\};' 'The host Retro-WFC game table'),
|
||||
'\["([^"]+)"\]\s*=\s*"([^"]+)"')) {
|
||||
$payloadGames[$entry.Groups[1].Value] = $entry.Groups[2].Value
|
||||
}
|
||||
$macosSetup = Read-SourceFile (Join-Path $launcher 'macos\setup.command') 'macOS setup.command'
|
||||
$macosUri = Get-CapturedValue $macosSetup "'([^']*/api/wfc/payload\?g=RMCPD00)'" `
|
||||
'The macOS Retro-WFC endpoint'
|
||||
if ($macosUri -cne $pins.RetroWfcPayloadUri) {
|
||||
Add-Failure "macOS setup.command downloads '$macosUri' but recomp.yml pins '$($pins.RetroWfcPayloadUri)'."
|
||||
$uriTemplate = Get-CapturedValue $retroWfcPayload 'PayloadUri\(string gameId\)\s*=>\s*\$"([^"]+)"' `
|
||||
'The host Retro-WFC endpoint template'
|
||||
Compare-Set ([string[]]@($releases.GameId)) ([string[]]@($payloadGames.Keys)) `
|
||||
'projects/*/recomp.yml' 'RetroWfcPayload.PayloadGames'
|
||||
foreach ($release in $releases) {
|
||||
if (-not $payloadGames.ContainsKey($release.GameId)) { continue }
|
||||
$hostUri = $uriTemplate.Replace('{PayloadGame(gameId)}', $payloadGames[$release.GameId])
|
||||
if ($hostUri -cne $release.RetroWfcPayloadUri) {
|
||||
Add-Failure "RetroWfcPayload.PayloadUri($($release.GameId)) is '$hostUri' but $($release.Project) pins '$($release.RetroWfcPayloadUri)'."
|
||||
}
|
||||
}
|
||||
|
||||
# --- The game identity: the manifest carries it, but the host also compiles a fallback for a
|
||||
# --- manifest that predates the field, and that fallback decides which disc is accepted.
|
||||
$models = Read-SourceFile (Join-Path $setup 'Models.cs') 'Models.cs'
|
||||
$hostGameId = Get-CapturedValue $models 'ExpectedGameId\s*\{\s*get;\s*set;\s*\}\s*=\s*"([^"]+)"' `
|
||||
'The host expected game id'
|
||||
if ($hostGameId -cne $pins.GameId) {
|
||||
Add-Failure "PayloadManifest.ExpectedGameId defaults to '$hostGameId' but recomp.yml pins '$($pins.GameId)'."
|
||||
foreach ($key in @('GameId', 'DolSha256')) {
|
||||
foreach ($duplicate in @($releases | Group-Object $key | Where-Object Count -gt 1)) {
|
||||
Add-Failure "Several projects pin the same $($key) $($duplicate.Name)."
|
||||
}
|
||||
}
|
||||
|
||||
# --- The translation entry point: the translator is told it by LocalBuild.ps1 (which reads
|
||||
@@ -79,8 +84,10 @@ if ($hostGameId -cne $pins.GameId) {
|
||||
$systemBridge = Read-SourceFile (Join-Path $repoRoot 'runtime\include\system_bridge.h') 'system_bridge.h'
|
||||
$runtimeEntry = (Get-CapturedValue $systemBridge 'kDefaultEntryAddress\s*=\s*(0[xX][0-9a-fA-F]+)' `
|
||||
'The runtime default entry address').ToLowerInvariant()
|
||||
if ($runtimeEntry -ne $pins.EntryPoint) {
|
||||
Add-Failure "system_bridge.h enters at $runtimeEntry but recomp.yml translates from $($pins.EntryPoint)."
|
||||
foreach ($release in $releases) {
|
||||
if ($runtimeEntry -ne $release.EntryPoint) {
|
||||
Add-Failure "system_bridge.h enters at $runtimeEntry but $($release.Project) translates from $($release.EntryPoint)."
|
||||
}
|
||||
}
|
||||
|
||||
# --- The pinned dependency set: Build-Installer.ps1 stages it, the installed host requires it.
|
||||
@@ -137,6 +144,6 @@ Compare-Set $knownSteps $emittedSteps 'BuildStepIds' 'the steps LocalBuild.ps1 e
|
||||
if ($failures.Count -gt 0) {
|
||||
throw "Pinned facts disagree between their copies:`n $($failures -join "`n ")"
|
||||
}
|
||||
Write-Host ("Pinned-fact audit passed: game {0}, entry {1}, endpoint {2}; dependency, runtime-asset, " -f
|
||||
$pins.GameId, $pins.EntryPoint, $pins.RetroWfcPayloadUri) -NoNewline
|
||||
Write-Host ("Pinned-fact audit passed: games {0}, entry {1}; Retro-WFC endpoint, dependency, runtime-asset, " -f
|
||||
($releases.GameId -join ', '), $runtimeEntry) -NoNewline
|
||||
Write-Host 'build-step, and build-script parameter contracts all agree.'
|
||||
|
||||
@@ -36,8 +36,17 @@ Write-Host "Synthetic recompilation workspace: $stage"
|
||||
|
||||
# Copy current sources, including uncommitted edits, but no ignored build output.
|
||||
# An isolated workspace preserves the developer's real generated/ directory.
|
||||
$sourceFiles = & git -C $repoRoot -c core.quotepath=false ls-files --cached --others --exclude-standard -- runtime aurora-main
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Could not enumerate runtime and Aurora sources.' }
|
||||
$auroraRoot = Join-Path $repoRoot 'aurora-main'
|
||||
if (-not (Test-Path -LiteralPath (Join-Path $auroraRoot '.git'))) {
|
||||
throw 'Aurora submodule is not initialized. Run git submodule update --init --recursive first.'
|
||||
}
|
||||
# The parent tracks Aurora as one gitlink; enumerate its repository separately.
|
||||
# Retain untracked source files so local development edits are still tested.
|
||||
$sourceFiles = @(& git -C $repoRoot -c core.quotepath=false ls-files --cached --others --exclude-standard -- runtime)
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Could not enumerate runtime sources.' }
|
||||
$auroraFiles = @(& git -C $auroraRoot -c core.quotepath=false ls-files --cached --others --exclude-standard)
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Could not enumerate Aurora sources.' }
|
||||
$sourceFiles += @($auroraFiles | ForEach-Object { "aurora-main/$_" })
|
||||
foreach ($relative in $sourceFiles | Sort-Object -Unique) {
|
||||
$destination = Join-Path $stage $relative
|
||||
[IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($destination)) | Out-Null
|
||||
@@ -45,13 +54,14 @@ foreach ($relative in $sourceFiles | Sort-Object -Unique) {
|
||||
}
|
||||
|
||||
# One synthetic text section: li r3,40; addi r3,r3,2; nop; blr.
|
||||
# Native HLE wrappers also call these eight guest symbols directly. Give each
|
||||
# Native HLE wrappers also call these guest symbols directly. Give each
|
||||
# its own generated blr function so the real product can link without game code.
|
||||
# Keep this list explicit: a new unresolved guest dependency must fail the test.
|
||||
[uint32]$entry = 0x80001000L
|
||||
[uint32[]]$guestCallbacks = @(
|
||||
0x8012B830L, 0x801A0620L, 0x801A1ED8L, 0x801A961CL,
|
||||
0x801AADE0L, 0x801D8D30L, 0x801D9E94L, 0x8055531CL
|
||||
0x801AADE0L, 0x801D8D30L, 0x801D9E94L, 0x8055531CL,
|
||||
0x80601C64L, 0x8061E348L, 0x8061E3B4L
|
||||
)
|
||||
$textSize = [int]($guestCallbacks[-1] - $entry + 4)
|
||||
$dataOffset = 0x100 + $textSize
|
||||
@@ -66,9 +76,9 @@ Write-BigEndian32 0x00 0x100 # text[0] file offset
|
||||
Write-BigEndian32 0x48 $entry # text[0] guest address
|
||||
Write-BigEndian32 0x90 $textSize # text[0] length (unreachable gaps are zero)
|
||||
Write-BigEndian32 0x1C $dataOffset # data[0] file offset
|
||||
Write-BigEndian32 0x64 0x80600000L # data[0] guest address
|
||||
Write-BigEndian32 0x64 0x80700000L # data[0] guest address
|
||||
Write-BigEndian32 0xAC 4 # data[0] length
|
||||
Write-BigEndian32 0xD8 0x80601000L # BSS address
|
||||
Write-BigEndian32 0xD8 0x80701000L # BSS address
|
||||
Write-BigEndian32 0xDC 32 # BSS length
|
||||
Write-BigEndian32 0xE0 $entry # entry point
|
||||
Write-BigEndian32 0x100 0x38600028 # li r3,40
|
||||
@@ -93,8 +103,8 @@ project:
|
||||
memory:
|
||||
base: 0x80000000
|
||||
size: 0x01800000
|
||||
sda_base: 0x80600000
|
||||
sda2_base: 0x80600000
|
||||
sda_base: 0x80700000
|
||||
sda2_base: 0x80700000
|
||||
inputs:
|
||||
dol:
|
||||
path: synthetic.dol
|
||||
|
||||
@@ -11,22 +11,39 @@ namespace WiiCompiled.Setup.Common;
|
||||
public sealed record RetroWfcPayloadSnapshot(string Directory, string Sha256, long ByteLength);
|
||||
|
||||
/// <summary>
|
||||
/// Downloads and verifies the Retro-WFC payload (a small, RSA-signed blob served from a single
|
||||
/// fixed endpoint). Shared by both installers - moved here from WiiCompiled.Setup.Windows's
|
||||
/// InputValidation.cs, which keeps every one of these method names as thin forwarding wrappers so
|
||||
/// its many existing call sites (ProductRepairService.cs, LocalBuildService.cs, Installation.cs,
|
||||
/// SelfTests.cs) needed no changes.
|
||||
/// Downloads and verifies the Retro-WFC payload (a small, RSA-signed blob served from one fixed
|
||||
/// endpoint per game release). Shared by both installers and the translator.
|
||||
/// </summary>
|
||||
public static class RetroWfcPayload
|
||||
{
|
||||
private const long MaximumRetroWfcPayloadBytes = 16L * 1024 * 1024;
|
||||
// The payload is tens of kilobytes from a single fixed endpoint 30s is good.
|
||||
// The payload is tens of kilobytes from a fixed regional endpoint; allow 30 seconds.
|
||||
private static readonly TimeSpan RetroWfcDownloadTimeout = TimeSpan.FromSeconds(30);
|
||||
private static readonly TimeSpan RetroWfcRetryDelay = TimeSpan.FromSeconds(1);
|
||||
|
||||
public const string CurrentRetroWfcPayloadUri = "https://rwfc.net/api/wfc/payload?g=RMCPD00";
|
||||
private static readonly string RetroWfcOfflinePayloadFile =
|
||||
Path.Combine("binary", "payload.RMCPD00.bin");
|
||||
/// <summary>
|
||||
/// Base game id to Retro-WFC payload game. Test-PinnedFacts.ps1 checks this table against the
|
||||
/// retro_wfc_payload every projects/*/recomp.yml pins.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, string> PayloadGames = new(StringComparer.Ordinal)
|
||||
{
|
||||
["RMCP01"] = "RMCPD00",
|
||||
["RMCE01"] = "RMCED00",
|
||||
["RMCJ01"] = "RMCJD00",
|
||||
};
|
||||
|
||||
public static IReadOnlyCollection<string> SupportedGameIds => PayloadGames.Keys;
|
||||
|
||||
public static string PayloadGame(string gameId) =>
|
||||
PayloadGames.TryGetValue(gameId, out var payloadGame)
|
||||
? payloadGame
|
||||
: throw new InvalidDataException($"Unsupported Retro-WFC base game '{gameId}'.");
|
||||
|
||||
public static string PayloadRelativePath(string gameId) =>
|
||||
Path.Combine("binary", $"payload.{PayloadGame(gameId)}.bin");
|
||||
|
||||
public static string PayloadUri(string gameId) =>
|
||||
$"https://rwfc.net/api/wfc/payload?g={PayloadGame(gameId)}";
|
||||
|
||||
/// <summary>Retro-WFC production payload signing key (PROD PayloadPublicKey). Verifies
|
||||
/// the payload past the 0x110 header; on-console stage1 pins the same key, so
|
||||
@@ -45,47 +62,48 @@ public static class RetroWfcPayload
|
||||
private const int RetroWfcPayloadSignatureOffset = 0x10;
|
||||
private const int RetroWfcPayloadMinimumBytes = 0x130;
|
||||
|
||||
public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory,
|
||||
public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory, string gameId,
|
||||
RSAParameters? signingKey = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(stagedDirectory))
|
||||
throw new InvalidDataException("The staged Retro-WFC payload directory is missing.");
|
||||
|
||||
var root = Path.GetFullPath(stagedDirectory);
|
||||
var payload = Path.Combine(root, RetroWfcOfflinePayloadFile);
|
||||
var relativePath = PayloadRelativePath(gameId);
|
||||
var payload = Path.Combine(root, relativePath);
|
||||
try
|
||||
{
|
||||
if ((File.GetAttributes(payload) & FileAttributes.Directory) != 0)
|
||||
throw new InvalidDataException(
|
||||
"The staged Retro-WFC payload directory does not contain binary\\payload.RMCPD00.bin.");
|
||||
$"The staged Retro-WFC payload directory does not contain {relativePath}.");
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
throw new InvalidDataException(
|
||||
"The staged Retro-WFC payload directory does not contain binary\\payload.RMCPD00.bin.");
|
||||
$"The staged Retro-WFC payload directory does not contain {relativePath}.");
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
throw new InvalidDataException(
|
||||
"The staged Retro-WFC payload directory does not contain binary\\payload.RMCPD00.bin.");
|
||||
$"The staged Retro-WFC payload directory does not contain {relativePath}.");
|
||||
}
|
||||
ValidateRetroWfcPayloadFile(payload, signingKey);
|
||||
ValidateRetroWfcPayloadFile(payload, PayloadGame(gameId), signingKey);
|
||||
return root;
|
||||
}
|
||||
|
||||
public static string ResolveRetroWfcPayloadFile(string stagedDirectory,
|
||||
public static string ResolveRetroWfcPayloadFile(string stagedDirectory, string gameId,
|
||||
RSAParameters? signingKey = null) =>
|
||||
Path.Combine(ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, signingKey),
|
||||
RetroWfcOfflinePayloadFile);
|
||||
Path.Combine(ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, gameId, signingKey),
|
||||
PayloadRelativePath(gameId));
|
||||
|
||||
public static string ComputeRetroWfcPayloadSha256(string stagedDirectory,
|
||||
public static string ComputeRetroWfcPayloadSha256(string stagedDirectory, string gameId,
|
||||
RSAParameters? signingKey = null) =>
|
||||
Sha256File(ResolveRetroWfcPayloadFile(stagedDirectory, signingKey));
|
||||
Sha256File(ResolveRetroWfcPayloadFile(stagedDirectory, gameId, signingKey));
|
||||
|
||||
public static void ValidateRetroWfcPayloadUri(string uriText)
|
||||
{
|
||||
if (!string.Equals(uriText, CurrentRetroWfcPayloadUri, StringComparison.Ordinal))
|
||||
throw new InvalidDataException("The installer does not define the fixed Retro-WFC payload endpoint.");
|
||||
if (!PayloadGames.Keys.Any(gameId => string.Equals(uriText, PayloadUri(gameId), StringComparison.Ordinal)))
|
||||
throw new InvalidDataException("The installer does not define this fixed Retro-WFC payload endpoint.");
|
||||
}
|
||||
|
||||
public static async Task<RetroWfcPayloadSnapshot> DownloadRetroWfcPayloadAsync(string uriText,
|
||||
@@ -96,7 +114,8 @@ public static class RetroWfcPayload
|
||||
var uri = new Uri(uriText, UriKind.Absolute);
|
||||
|
||||
var root = Path.GetFullPath(destinationDirectory);
|
||||
var destination = Path.Combine(root, RetroWfcOfflinePayloadFile);
|
||||
var payloadGame = uri.Query[3..]; // ValidateRetroWfcPayloadUri accepts only the exact ?g= form.
|
||||
var destination = Path.Combine(root, "binary", $"payload.{payloadGame}.bin");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destination)!);
|
||||
using var handler = new HttpClientHandler { AllowAutoRedirect = false };
|
||||
using var client = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
|
||||
@@ -154,7 +173,7 @@ public static class RetroWfcPayload
|
||||
}
|
||||
actualSha256 = Convert.ToHexString(hash.GetHashAndReset()).ToLowerInvariant();
|
||||
}
|
||||
ValidateRetroWfcPayloadFile(temporary);
|
||||
ValidateRetroWfcPayloadFile(temporary, uri.Query[3..]);
|
||||
File.Move(temporary, destination, overwrite: true);
|
||||
return new RetroWfcPayloadSnapshot(root, actualSha256, total);
|
||||
}
|
||||
@@ -181,7 +200,8 @@ public static class RetroWfcPayload
|
||||
request.StatusCode is { } status && (int)status >= 500;
|
||||
}
|
||||
|
||||
private static void ValidateRetroWfcPayloadFile(string payload, RSAParameters? signingKey = null)
|
||||
private static void ValidateRetroWfcPayloadFile(string payload, string expectedGame,
|
||||
RSAParameters? signingKey = null)
|
||||
{
|
||||
byte[] image;
|
||||
using (var stream = File.OpenRead(payload))
|
||||
@@ -201,6 +221,10 @@ public static class RetroWfcPayload
|
||||
throw new InvalidDataException(
|
||||
$"The Retro-WFC payload declares {declaredSize} bytes but contains {image.Length}.");
|
||||
|
||||
if (image.Length < 0x144 ||
|
||||
System.Text.Encoding.ASCII.GetString(image, 0x138, 12).TrimEnd('\0') != expectedGame)
|
||||
throw new InvalidDataException($"The Retro-WFC payload is not for {expectedGame}.");
|
||||
|
||||
using var rsa = RSA.Create();
|
||||
rsa.ImportParameters(signingKey ?? new RSAParameters
|
||||
{
|
||||
|
||||
@@ -11,29 +11,30 @@ namespace WiiCompiled.Setup.Linux;
|
||||
/// </summary>
|
||||
internal static class DiscTool
|
||||
{
|
||||
public static async Task ValidateAndExtractAsync(
|
||||
string isoPath, ProjectManifest manifest, string assetsDirectory, string workspace,
|
||||
/// <summary>Validates and extracts the disc, returning the supported release it is.</summary>
|
||||
public static async Task<ProjectManifest> ValidateAndExtractAsync(
|
||||
string isoPath, IReadOnlyList<ProjectManifest> releases, string assetsDirectory, string workspace,
|
||||
string? nodToolBin, IInstallReporter reporter, CancellationToken cancellationToken)
|
||||
{
|
||||
if (IsAlreadyExtracted(manifest, assetsDirectory))
|
||||
{
|
||||
reporter.Progress(InstallStages.ExtractDisc, "Reusing the verified extracted disc", 6);
|
||||
return;
|
||||
}
|
||||
|
||||
var nodTool = nodToolBin ?? await NodToolProvider.ResolveAsync(workspace, cancellationToken);
|
||||
|
||||
// `nodtool info` only decodes the disc/partition headers (milliseconds); `nodtool extract`
|
||||
// copies the whole data partition to disk (tens of seconds for a custom-track-heavy MKWii
|
||||
// ISO). Checking the game ID first, before extracting, means a wrong disc fails fast -
|
||||
// matching the original dolphin-tool `header` step this replaces.
|
||||
// ISO). The game ID picks the release, so a wrong disc fails fast and an existing
|
||||
// extraction is only reused for the same release.
|
||||
reporter.Progress(InstallStages.ExtractDisc, "Reading the disc header", 2);
|
||||
var info = NodToolInfoParser.Parse(await RunInfoAsync(nodTool, isoPath, cancellationToken));
|
||||
if (!string.Equals(info.GameId, manifest.GameId, StringComparison.Ordinal))
|
||||
var manifest = releases.FirstOrDefault(release =>
|
||||
string.Equals(info.GameId, release.GameId, StringComparison.Ordinal))
|
||||
?? throw new InvalidOperationException(
|
||||
$"This disc is '{info.GameId}', which is not a supported Mario Kart Wii release " +
|
||||
$"({ProjectManifest.Describe(releases)}). " +
|
||||
"Only your own legally-owned copy of a supported game/region can be used.");
|
||||
|
||||
if (IsAlreadyExtracted(manifest, assetsDirectory))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"This disc is '{info.GameId}', not the expected '{manifest.GameId}' (Mario Kart Wii, region {manifest.Region}). " +
|
||||
"Only your own legally-owned copy of that exact game/region can be used.");
|
||||
reporter.Progress(InstallStages.ExtractDisc, "Reusing the verified extracted disc", 6);
|
||||
return manifest;
|
||||
}
|
||||
|
||||
// Extracted straight into Assets/DATA (kept, not a scratch dir) - the runtime reads course/
|
||||
@@ -71,6 +72,22 @@ internal static class DiscTool
|
||||
File.Copy(relPath, Path.Combine(assetsDirectory, "StaticR.rel"), overwrite: true);
|
||||
File.WriteAllText(Path.Combine(assetsDirectory, ExtractionMarker), ExtractionRecord(dolSha, dataDir));
|
||||
reporter.Progress(InstallStages.ExtractDisc, "Disc validated and extracted", 6);
|
||||
return manifest;
|
||||
}
|
||||
|
||||
/// <summary>The release already extracted into Assets, chosen by its main.dol like local-build.sh.</summary>
|
||||
public static ProjectManifest SelectExtracted(IReadOnlyList<ProjectManifest> releases, string assetsDirectory)
|
||||
{
|
||||
var dolSha = Sha256Of(Path.Combine(assetsDirectory, "main.dol"));
|
||||
var manifest = releases.FirstOrDefault(release => string.Equals(dolSha, release.DolSha256, StringComparison.Ordinal))
|
||||
?? throw new InvalidOperationException(
|
||||
$"Assets/main.dol (sha256 {dolSha}) is not a supported clean Mario Kart Wii release " +
|
||||
$"({ProjectManifest.Describe(releases)}).");
|
||||
var relSha = Sha256Of(Path.Combine(assetsDirectory, "StaticR.rel"));
|
||||
if (!string.Equals(relSha, manifest.RelSha256, StringComparison.Ordinal))
|
||||
throw new InvalidOperationException(
|
||||
$"Assets/StaticR.rel does not match the clean {manifest.GameId} release of Assets/main.dol.");
|
||||
return manifest;
|
||||
}
|
||||
|
||||
private static async Task<string> RunInfoAsync(string nodTool, string isoPath, CancellationToken cancellationToken)
|
||||
@@ -97,7 +114,7 @@ internal static class DiscTool
|
||||
|
||||
private const string ExtractionMarker = ".disc-extracted";
|
||||
|
||||
// Only one disc revision is accepted, so a completed, verified extraction is identical to a fresh one.
|
||||
// Each release has one accepted revision, so a completed, verified extraction is identical to a fresh one.
|
||||
private static bool IsAlreadyExtracted(ProjectManifest manifest, string assetsDirectory)
|
||||
{
|
||||
var marker = Path.Combine(assetsDirectory, ExtractionMarker);
|
||||
|
||||
@@ -95,13 +95,14 @@ internal static class Program
|
||||
if (installsRetro) retroDir = RetroRewindSource.ResolveRetroRewind6(retroDir!);
|
||||
|
||||
var workspace = flags.GetValueOrDefault("workspace") ?? WorkspaceLocator.FindFrom(AppContext.BaseDirectory);
|
||||
var manifest = ProjectManifest.Load(Path.Combine(workspace, "projects", "mkwii", "recomp.yml"));
|
||||
var releases = ProjectManifest.LoadAll(workspace);
|
||||
var assetsDir = Path.Combine(workspace, "Assets");
|
||||
|
||||
reporter.Progress(InstallStages.Validate, "Checking prerequisites", 1);
|
||||
ProjectManifest release;
|
||||
if (flags.TryGetValue("game", out var isoPath) && !string.IsNullOrEmpty(isoPath))
|
||||
{
|
||||
await DiscTool.ValidateAndExtractAsync(isoPath, manifest, assetsDir, workspace,
|
||||
release = await DiscTool.ValidateAndExtractAsync(isoPath, releases, assetsDir, workspace,
|
||||
flags.GetValueOrDefault("disc-tool-bin"), reporter, token);
|
||||
}
|
||||
else
|
||||
@@ -114,6 +115,7 @@ internal static class Program
|
||||
"No --game ISO was given and Assets/main.dol + Assets/StaticR.rel are not already present. " +
|
||||
"Either pass --game <path-to-iso>, or extract them yourself first (see translator/README.md).");
|
||||
}
|
||||
release = DiscTool.SelectExtracted(releases, assetsDir);
|
||||
}
|
||||
|
||||
var state = JsonState.TryRead<InstallState>(StatePath) ?? new InstallState { Workspace = workspace };
|
||||
@@ -133,10 +135,10 @@ internal static class Program
|
||||
try
|
||||
{
|
||||
// A valid signature authenticates a payload, but does not prove it is the latest
|
||||
// signed revision. Always ask the fixed endpoint for the current snapshot; the
|
||||
// downloader verifies it before atomically replacing the cache.
|
||||
// signed revision. Always ask the release's fixed endpoint for the current snapshot;
|
||||
// the downloader verifies it before atomically replacing the cache.
|
||||
await RetroWfcPayload.DownloadRetroWfcPayloadAsync(
|
||||
RetroWfcPayload.CurrentRetroWfcPayloadUri, cacheDir, token);
|
||||
RetroWfcPayload.PayloadUri(release.GameId), cacheDir, token);
|
||||
}
|
||||
catch (Exception downloadFailure) when (!token.IsCancellationRequested &&
|
||||
downloadFailure is HttpRequestException or TimeoutException
|
||||
@@ -147,7 +149,7 @@ internal static class Program
|
||||
// that must remain a hard failure instead of hiding possible endpoint tampering.
|
||||
try
|
||||
{
|
||||
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(cacheDir);
|
||||
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(cacheDir, gameId: release.GameId);
|
||||
}
|
||||
catch (Exception cacheFailure) when (cacheFailure is IOException or
|
||||
UnauthorizedAccessException or InvalidDataException)
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text.RegularExpressions;
|
||||
namespace WiiCompiled.Setup.Linux;
|
||||
|
||||
/// <summary>
|
||||
/// The handful of facts this tool needs out of projects/mkwii/recomp.yml. Parsed literally line by
|
||||
/// The handful of facts this tool needs out of a projects/*/recomp.yml. Parsed literally line by
|
||||
/// line - the same approach Launcher/NativeBuildFlags.ps1's Get-MkwProjectPins and
|
||||
/// Launcher/local-build.sh already use - rather than pulling in a YAML library, since the manifest
|
||||
/// is machine-written with a fixed shape.
|
||||
@@ -67,4 +67,21 @@ internal sealed class ProjectManifest
|
||||
|
||||
return new ProjectManifest { GameId = gameId, Region = region, DolSha256 = dolSha, RelSha256 = relSha };
|
||||
}
|
||||
|
||||
/// <summary>Every supported release: one per projects/*/recomp.yml, as local-build.sh selects them.</summary>
|
||||
public static IReadOnlyList<ProjectManifest> LoadAll(string workspace)
|
||||
{
|
||||
var projects = Directory.EnumerateDirectories(Path.Combine(workspace, "projects"))
|
||||
.Select(directory => Path.Combine(directory, "recomp.yml"))
|
||||
.Where(File.Exists)
|
||||
.Order(StringComparer.Ordinal)
|
||||
.Select(Load)
|
||||
.ToList();
|
||||
if (projects.Count == 0)
|
||||
throw new InvalidOperationException($"No projects/*/recomp.yml was found under {workspace}.");
|
||||
return projects;
|
||||
}
|
||||
|
||||
public static string Describe(IEnumerable<ProjectManifest> projects) =>
|
||||
string.Join(", ", projects.Select(project => $"{project.GameId} (region {project.Region})"));
|
||||
}
|
||||
|
||||
@@ -64,9 +64,7 @@ internal static class ConsoleCommands
|
||||
{
|
||||
using var payload = PayloadArchive.OpenCurrent();
|
||||
var manifest = payload.ReadManifest();
|
||||
var tool = Path.Combine(temp, "nodtool.exe");
|
||||
payload.ExtractEntry(InstalledLayout.ToolkitEntryPrefix + "nodtool.exe", tool);
|
||||
payload.ExtractDirectory(InstalledLayout.ToolkitEntryPrefix + "Redist", temp);
|
||||
var tool = payload.ExtractDiscTool(temp);
|
||||
reporter?.Progress(InstallStages.Validate, "Checking the Wii disc image...", 10);
|
||||
var header = InputValidation.ReadDiscHeaderAsync(tool, command.GamePath!).GetAwaiter().GetResult();
|
||||
InputValidation.EnsureCompatibleDisc(header, manifest);
|
||||
|
||||
@@ -54,33 +54,29 @@ internal static class InputValidation
|
||||
}
|
||||
: "Unknown";
|
||||
|
||||
public static void EnsureCompatibleDisc(DiscHeader header, PayloadManifest manifest)
|
||||
{
|
||||
if (!header.GameId.Equals(manifest.ExpectedGameId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidDataException(
|
||||
$"This build supports Mario Kart Wii PAL ({manifest.ExpectedGameId}). " +
|
||||
$"The selected image is {header.GameId} ({header.InternalName}, {header.Region}).");
|
||||
}
|
||||
}
|
||||
/// <summary>The supported release this disc is, or a clear rejection naming every supported one.</summary>
|
||||
public static GameRelease EnsureCompatibleDisc(DiscHeader header, PayloadManifest manifest) =>
|
||||
manifest.SupportedReleases.FirstOrDefault(release =>
|
||||
release.GameId.Equals(header.GameId, StringComparison.OrdinalIgnoreCase))
|
||||
?? throw new InvalidDataException(
|
||||
"This build supports Mario Kart Wii " +
|
||||
string.Join(", ", manifest.SupportedReleases.Select(release =>
|
||||
$"{RegionFromGameId(release.GameId)} ({release.GameId})")) +
|
||||
$". The selected image is {header.GameId} ({header.InternalName}, {header.Region}).");
|
||||
|
||||
// Thin forwarding wrappers: the actual download/RSA-verification logic lives in
|
||||
// WiiCompiled.Setup.Common.RetroWfcPayload (shared with WiiCompiled.Setup.Linux) so there's one
|
||||
// copy of it, not two. Kept under these names so every existing call site here
|
||||
// (ProductRepairService.cs, LocalBuildService.cs, Installation.cs, SelfTests.cs) is unchanged.
|
||||
public const string CurrentRetroWfcPayloadUri = RetroWfcPayload.CurrentRetroWfcPayloadUri;
|
||||
|
||||
public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory,
|
||||
// Forwarding wrappers over WiiCompiled.Setup.Common.RetroWfcPayload that require the game id,
|
||||
// so no caller here can silently fall back to one region's payload.
|
||||
public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory, string gameId,
|
||||
RSAParameters? signingKey = null) =>
|
||||
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, signingKey);
|
||||
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, gameId, signingKey);
|
||||
|
||||
public static string ResolveRetroWfcPayloadFile(string stagedDirectory,
|
||||
public static string ResolveRetroWfcPayloadFile(string stagedDirectory, string gameId,
|
||||
RSAParameters? signingKey = null) =>
|
||||
RetroWfcPayload.ResolveRetroWfcPayloadFile(stagedDirectory, signingKey);
|
||||
RetroWfcPayload.ResolveRetroWfcPayloadFile(stagedDirectory, gameId, signingKey);
|
||||
|
||||
public static string ComputeRetroWfcPayloadSha256(string stagedDirectory,
|
||||
public static string ComputeRetroWfcPayloadSha256(string stagedDirectory, string gameId,
|
||||
RSAParameters? signingKey = null) =>
|
||||
RetroWfcPayload.ComputeRetroWfcPayloadSha256(stagedDirectory, signingKey);
|
||||
RetroWfcPayload.ComputeRetroWfcPayloadSha256(stagedDirectory, gameId, signingKey);
|
||||
|
||||
public static void ValidateRetroWfcPayloadUri(string uriText) =>
|
||||
RetroWfcPayload.ValidateRetroWfcPayloadUri(uriText);
|
||||
|
||||
@@ -131,6 +131,8 @@ internal sealed class Installation
|
||||
Workspace + "LocalBuild.ps1",
|
||||
Workspace + "NativeBuildFlags.ps1",
|
||||
Workspace + @"projects\mkwii\recomp.yml",
|
||||
Workspace + @"projects\mkwii-ntsc-u\recomp.yml",
|
||||
Workspace + @"projects\mkwii-ntsc-j\recomp.yml",
|
||||
Workspace + @"runtime\CMakeLists.txt",
|
||||
Workspace + @"runtime\assets\dsp\dsp_coef.bin"
|
||||
];
|
||||
@@ -168,6 +170,26 @@ internal sealed class Installation
|
||||
|
||||
public InstallState? ReadInstallState() => JsonState.TryRead<InstallState>(InstallStatePath);
|
||||
|
||||
/// <summary>The game id of the installed disc, which selects its region's Retro-WFC payload.</summary>
|
||||
public string ReadGameId()
|
||||
{
|
||||
try { return ReadDiscGameId(GameDataDirectory); }
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new InvalidDataException(
|
||||
"The installed game data has no readable disc header. Apply setup again with the disc image.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The six-character game id in an extracted disc's <c>sys/boot.bin</c>.</summary>
|
||||
internal static string ReadDiscGameId(string dataRoot)
|
||||
{
|
||||
using var stream = File.OpenRead(Path.Combine(dataRoot, "sys", "boot.bin"));
|
||||
var id = new byte[6];
|
||||
stream.ReadExactly(id);
|
||||
return System.Text.Encoding.ASCII.GetString(id);
|
||||
}
|
||||
|
||||
internal ToolkitState? ReadToolkitState() => JsonState.TryRead<ToolkitState>(ToolkitStatePath);
|
||||
|
||||
/// <summary>
|
||||
@@ -396,7 +418,7 @@ internal sealed class Installation
|
||||
|
||||
try
|
||||
{
|
||||
var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload);
|
||||
var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload, ReadGameId());
|
||||
if (!InputValidation.Sha256File(payload).Equals(fingerprint.RetroWfcPayloadSha256,
|
||||
StringComparison.OrdinalIgnoreCase) ||
|
||||
new FileInfo(payload).Length != fingerprint.RetroWfcPayloadLength)
|
||||
@@ -581,7 +603,7 @@ internal sealed class Installation
|
||||
{
|
||||
try
|
||||
{
|
||||
var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload);
|
||||
var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload, ReadGameId());
|
||||
return new FileInfo(payload).Length == snapshot.ByteLength &&
|
||||
InputValidation.Sha256File(payload).Equals(snapshot.Sha256, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,28 @@ internal sealed class InstallerEngine
|
||||
var toolkit = InstalledLayout.Toolkit(staging);
|
||||
var workspace = InstalledLayout.Workspace(staging);
|
||||
|
||||
// The disc decides which release's inputs everything below expects, so it is identified
|
||||
// before any reuse decision or toolkit extraction.
|
||||
_reporter.Progress(InstallStages.Validate, "Checking the Wii disc image...", 1);
|
||||
var nodTool = payload.ExtractDiscTool(Path.Combine(staging, "disc-tool"));
|
||||
var header = await InputValidation.ReadDiscHeaderAsync(nodTool, options.GamePath,
|
||||
cancellationToken);
|
||||
var release = InputValidation.EnsureCompatibleDisc(header, manifest);
|
||||
var canonicalRetroRoot = options.RetroDirectoryPath is null
|
||||
? null
|
||||
: RetroRewindSource.ResolveRetroRewind6(options.RetroDirectoryPath);
|
||||
ValidateRetroOptions(canonicalRetroRoot, options.RetroWfcPayloadMode);
|
||||
|
||||
var retroCompileInputs = canonicalRetroRoot is null
|
||||
? null
|
||||
: SnapshotRetroRewindCompileInputs(canonicalRetroRoot,
|
||||
Path.Combine(staging, "compile-inputs"), cancellationToken);
|
||||
if (options.Portable)
|
||||
{
|
||||
var portableRoot = PortableRoot.Create(parent);
|
||||
_reporter.Diagnostic($"Installing as a portable installation under {portableRoot}.");
|
||||
}
|
||||
|
||||
var candidateToolkitFingerprint = manifest.ToolkitFingerprint;
|
||||
var candidateToolkitPackageFingerprint = manifest.ToolkitPackageFingerprint;
|
||||
var candidateRuntimeAssetsFingerprint = manifest.RuntimeAssetsFingerprint;
|
||||
@@ -49,7 +71,7 @@ internal sealed class InstallerEngine
|
||||
var installedToolkitPackageFingerprint = existing.IsPresent
|
||||
? existing.ResolveToolkitPackageFingerprint()
|
||||
: "";
|
||||
var reusableGameAssets = FindReusableGameAssets(existing, manifest);
|
||||
var reusableGameAssets = FindReusableGameAssets(existing, release);
|
||||
|
||||
var sameToolkit = existing.IsPresent && reusableGameAssets is not null &&
|
||||
installedToolkitFingerprint.Equals(candidateToolkitFingerprint,
|
||||
@@ -68,7 +90,7 @@ internal sealed class InstallerEngine
|
||||
var extractWorkspace = !sameToolkit || !runtimeAssetsCurrent;
|
||||
|
||||
_reporter.Progress(InstallStages.ExtractToolkit,
|
||||
"Inspecting the release's local recompilation toolkit...", 1);
|
||||
"Inspecting the release's local recompilation toolkit...", 4);
|
||||
if (extractToolkit) payload.ExtractDirectory(InstalledLayout.ToolkitDirectoryName, toolkit);
|
||||
if (extractWorkspace)
|
||||
{
|
||||
@@ -82,30 +104,10 @@ internal sealed class InstallerEngine
|
||||
payload.ExtractEntry(InstalledLayout.PayloadManifestFileName,
|
||||
Path.Combine(staging, InstalledLayout.PayloadManifestFileName));
|
||||
|
||||
var nodTool = extractToolkit ? Path.Combine(toolkit, "nodtool.exe") : installedNodTool;
|
||||
_reporter.Progress(InstallStages.Validate, "Checking the Wii disc image...", 2);
|
||||
var header = await InputValidation.ReadDiscHeaderAsync(nodTool, options.GamePath,
|
||||
cancellationToken);
|
||||
InputValidation.EnsureCompatibleDisc(header, manifest);
|
||||
var canonicalRetroRoot = options.RetroDirectoryPath is null
|
||||
? null
|
||||
: RetroRewindSource.ResolveRetroRewind6(options.RetroDirectoryPath);
|
||||
ValidateRetroOptions(canonicalRetroRoot, options.RetroWfcPayloadMode, manifest);
|
||||
|
||||
var retroCompileInputs = canonicalRetroRoot is null
|
||||
? null
|
||||
: SnapshotRetroRewindCompileInputs(canonicalRetroRoot,
|
||||
Path.Combine(staging, "compile-inputs"), cancellationToken);
|
||||
if (options.Portable)
|
||||
{
|
||||
var portableRoot = PortableRoot.Create(parent);
|
||||
_reporter.Diagnostic($"Installing as a portable installation under {portableRoot}.");
|
||||
}
|
||||
|
||||
if (sameToolkit)
|
||||
{
|
||||
var desiredInputDrift = ProductRepairService.FindDesiredInputDrift(existing,
|
||||
candidateToolkitFingerprint, manifest.ExpectedDolSha256, manifest.ExpectedRelSha256);
|
||||
candidateToolkitFingerprint, release.DolSha256, release.RelSha256);
|
||||
if (desiredInputDrift.Retro && retroCompileInputs is null)
|
||||
throw new InvalidOperationException(
|
||||
"This release changes the clean game inputs used by the installed Retro Rewind product. " +
|
||||
@@ -113,7 +115,7 @@ internal sealed class InstallerEngine
|
||||
|
||||
var reconciliation = await ReconcileSameToolkitAsync(existing, retroCompileInputs,
|
||||
canonicalRetroRoot, options.RetroWfcPayloadMode, Path.Combine(staging, "repair"),
|
||||
manifest.ExpectedDolSha256, manifest.ExpectedRelSha256, cancellationToken);
|
||||
release.DolSha256, release.RelSha256, cancellationToken);
|
||||
var remainingCancellation = reconciliation.PublicationCommitted
|
||||
? CancellationToken.None
|
||||
: cancellationToken;
|
||||
@@ -125,11 +127,10 @@ internal sealed class InstallerEngine
|
||||
|
||||
remainingCancellation.ThrowIfCancellationRequested();
|
||||
EnsureReconciliationCurrent(existing, candidateToolkitFingerprint, retroCompileInputs,
|
||||
manifest.ExpectedDolSha256, manifest.ExpectedRelSha256,
|
||||
reconciliation.CachedRetroWfcPayloadMatches);
|
||||
release.DolSha256, release.RelSha256, reconciliation.CachedRetroWfcPayloadMatches);
|
||||
|
||||
var updatedState = BuildInstallState(existing.ReadInstallState(), installDirectory, manifest,
|
||||
retroCompileInputs, canonicalRetroRoot, options.RetroWfcPayloadMode);
|
||||
release, retroCompileInputs, canonicalRetroRoot, options.RetroWfcPayloadMode);
|
||||
PrepareMetadata(staging, manifest, updatedState);
|
||||
remainingCancellation.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -159,11 +160,11 @@ internal sealed class InstallerEngine
|
||||
if (reusableGameAssets is null)
|
||||
{
|
||||
await ExtractGameAssetsAsync(nodTool, options.GamePath,
|
||||
Path.Combine(staging, "GameAssets"), manifest, cancellationToken);
|
||||
Path.Combine(staging, "GameAssets"), release, cancellationToken);
|
||||
}
|
||||
|
||||
await PublishToolkitAndReconcileProductsAsync(existing, staging, workspace, manifest,
|
||||
previousState, options, canonicalRetroRoot, retroCompileInputs,
|
||||
release, previousState, options, canonicalRetroRoot, retroCompileInputs,
|
||||
publishGameAssets: reusableGameAssets is null, createShortcuts: firstInstall,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
@@ -187,7 +188,7 @@ internal sealed class InstallerEngine
|
||||
["generated", "build", "native-build", "Assets", "PulsarPacks"];
|
||||
|
||||
private async Task PublishToolkitAndReconcileProductsAsync(Installation existing, string staging,
|
||||
string stagedWorkspace, PayloadManifest manifest, InstallState? previousState,
|
||||
string stagedWorkspace, PayloadManifest manifest, GameRelease release, InstallState? previousState,
|
||||
InstallOptions options, string? canonicalRetroRoot,
|
||||
RetroRewindCompileInputs? retroCompileInputs,
|
||||
bool publishGameAssets, bool createShortcuts, CancellationToken cancellationToken)
|
||||
@@ -206,7 +207,7 @@ internal sealed class InstallerEngine
|
||||
}
|
||||
|
||||
|
||||
var state = BuildInstallState(previousState, installDirectory, manifest,
|
||||
var state = BuildInstallState(previousState, installDirectory, manifest, release,
|
||||
compileInputs: null, canonicalRetroRoot, options.RetroWfcPayloadMode);
|
||||
PrepareMetadata(staging, manifest, state);
|
||||
|
||||
@@ -226,10 +227,9 @@ internal sealed class InstallerEngine
|
||||
|
||||
var reconciliation = await ReconcileSameToolkitAsync(existing, retroCompileInputs,
|
||||
canonicalRetroRoot, options.RetroWfcPayloadMode, repairScratch: null,
|
||||
manifest.ExpectedDolSha256, manifest.ExpectedRelSha256, cancellationToken);
|
||||
release.DolSha256, release.RelSha256, cancellationToken);
|
||||
EnsureReconciliationCurrent(existing, manifest.ToolkitFingerprint, retroCompileInputs,
|
||||
manifest.ExpectedDolSha256, manifest.ExpectedRelSha256,
|
||||
reconciliation.CachedRetroWfcPayloadMatches);
|
||||
release.DolSha256, release.RelSha256, reconciliation.CachedRetroWfcPayloadMatches);
|
||||
}
|
||||
|
||||
private Task<ProductRepairService.ReconciliationResult> ReconcileSameToolkitAsync(Installation existing,
|
||||
@@ -354,7 +354,8 @@ internal sealed class InstallerEngine
|
||||
}
|
||||
|
||||
private static InstallState BuildInstallState(InstallState? previousState, string installDirectory,
|
||||
PayloadManifest manifest, RetroRewindCompileInputs? compileInputs, string? canonicalRetroRoot,
|
||||
PayloadManifest manifest, GameRelease release, RetroRewindCompileInputs? compileInputs,
|
||||
string? canonicalRetroRoot,
|
||||
RetroWfcPayloadMode payloadMode,
|
||||
RetroWfcPayloadSnapshot? retroWfcPayloadSnapshot = null)
|
||||
{
|
||||
@@ -368,8 +369,8 @@ internal sealed class InstallerEngine
|
||||
InstalledUtc = previousState?.InstalledUtc ?? DateTime.UtcNow,
|
||||
RetroRewindInstalled = previousState?.RetroRewindInstalled ?? false,
|
||||
ToolkitReleaseTag = manifest.ToolkitReleaseTag,
|
||||
DolSha256 = manifest.ExpectedDolSha256,
|
||||
RelSha256 = manifest.ExpectedRelSha256,
|
||||
DolSha256 = release.DolSha256,
|
||||
RelSha256 = release.RelSha256,
|
||||
RetroRewindCodePulSha256 = previousState?.RetroRewindCodePulSha256 ?? "",
|
||||
RetroRewindCompileInputsSha256 = previousState?.RetroRewindCompileInputsSha256 ?? "",
|
||||
RetroWfcPayloadMode = previousState?.RetroWfcPayloadMode ?? "",
|
||||
@@ -444,8 +445,7 @@ internal sealed class InstallerEngine
|
||||
Path.Combine(InstalledLayout.Workspace(installDirectory), "runtime", "assets")));
|
||||
}
|
||||
|
||||
private static void ValidateRetroOptions(string? canonicalRetroRoot, RetroWfcPayloadMode mode,
|
||||
PayloadManifest manifest)
|
||||
private static void ValidateRetroOptions(string? canonicalRetroRoot, RetroWfcPayloadMode mode)
|
||||
{
|
||||
if (canonicalRetroRoot is null && mode != RetroWfcPayloadMode.NotApplicable)
|
||||
throw new InvalidOperationException(
|
||||
@@ -453,11 +453,9 @@ internal sealed class InstallerEngine
|
||||
if (canonicalRetroRoot is not null && mode == RetroWfcPayloadMode.NotApplicable)
|
||||
throw new InvalidOperationException(
|
||||
"Download the Retro-WFC payload, or explicitly skip the optional payload.");
|
||||
if (canonicalRetroRoot is not null && mode == RetroWfcPayloadMode.Online)
|
||||
InputValidation.ValidateRetroWfcPayloadUri(manifest.RetroWfcPayloadUri);
|
||||
}
|
||||
|
||||
private string? FindReusableGameAssets(Installation existing, PayloadManifest manifest)
|
||||
private string? FindReusableGameAssets(Installation existing, GameRelease release)
|
||||
{
|
||||
var dataRoot = existing.GameDataDirectory;
|
||||
// No fst.bin simply means nothing was extracted here before; anything past that gate is an
|
||||
@@ -466,7 +464,7 @@ internal sealed class InstallerEngine
|
||||
if (!File.Exists(Path.Combine(dataRoot, "sys", "fst.bin"))) return null;
|
||||
try
|
||||
{
|
||||
ValidateExtractedGame(dataRoot, manifest);
|
||||
ValidateExtractedGame(dataRoot, release);
|
||||
return dataRoot;
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or InvalidDataException)
|
||||
@@ -478,7 +476,7 @@ internal sealed class InstallerEngine
|
||||
}
|
||||
|
||||
private async Task ExtractGameAssetsAsync(string nodTool, string gamePath, string destination,
|
||||
PayloadManifest manifest, CancellationToken cancellationToken)
|
||||
GameRelease release, CancellationToken cancellationToken)
|
||||
{
|
||||
_reporter.Progress(InstallStages.ExtractDisc,
|
||||
"Extracting the game disc. This is the longest preparation step...", 6);
|
||||
@@ -493,15 +491,16 @@ internal sealed class InstallerEngine
|
||||
cancellationToken);
|
||||
if (extraction.ExitCode != 0)
|
||||
throw new InvalidDataException("Game extraction failed. " + extraction.CombinedOutput.Trim());
|
||||
ValidateExtractedGame(dataRoot, manifest);
|
||||
ValidateExtractedGame(dataRoot, release);
|
||||
}
|
||||
|
||||
private static void ValidateExtractedGame(string dataRoot, PayloadManifest manifest)
|
||||
internal static void ValidateExtractedGame(string dataRoot, GameRelease release)
|
||||
{
|
||||
var dol = Path.Combine(dataRoot, "sys", "main.dol");
|
||||
var rel = Path.Combine(dataRoot, "files", "rel", "StaticR.rel");
|
||||
var fst = Path.Combine(dataRoot, "sys", "fst.bin");
|
||||
var missing = new[] { dol, rel, fst }.Where(path => !File.Exists(path))
|
||||
var boot = Path.Combine(dataRoot, "sys", "boot.bin");
|
||||
var missing = new[] { dol, rel, fst, boot }.Where(path => !File.Exists(path))
|
||||
.Select(path => Path.GetRelativePath(dataRoot, path)).ToList();
|
||||
if (missing.Count > 0)
|
||||
throw new InvalidDataException(
|
||||
@@ -509,10 +508,13 @@ internal sealed class InstallerEngine
|
||||
string.Join(", ", missing) + ".");
|
||||
|
||||
var mismatches = new List<string>();
|
||||
var discGameId = Installation.ReadDiscGameId(dataRoot);
|
||||
if (!discGameId.Equals(release.GameId, StringComparison.Ordinal))
|
||||
mismatches.Add($"sys/boot.bin names {discGameId}");
|
||||
foreach (var (name, path, expected) in new[]
|
||||
{
|
||||
("main.dol", dol, manifest.ExpectedDolSha256),
|
||||
("StaticR.rel", rel, manifest.ExpectedRelSha256)
|
||||
("main.dol", dol, release.DolSha256),
|
||||
("StaticR.rel", rel, release.RelSha256)
|
||||
})
|
||||
{
|
||||
var actual = InputValidation.Sha256File(path);
|
||||
@@ -523,7 +525,7 @@ internal sealed class InstallerEngine
|
||||
|
||||
if (mismatches.Count > 0)
|
||||
throw new InvalidDataException(
|
||||
"The disc is RMCP01 but its game code does not match the supported clean PAL revision: " +
|
||||
$"The disc is {release.GameId} but its game data does not match the supported clean revision: " +
|
||||
string.Join("; ", mismatches) + ". " +
|
||||
"Patched or otherwise modified game code cannot be installed safely.");
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ internal sealed class LocalBuildService
|
||||
/// </summary>
|
||||
public async Task BuildAsync(string installStaging, BuildProfile profile, string outputDirectory,
|
||||
RetroWfcPayloadMode retroWfcPayloadMode, string? retroWfcOfflinePayloadDirectory,
|
||||
CancellationToken cancellationToken, ToolkitFingerprintComponents? toolkitComponents = null,
|
||||
string? retroWfcGameId, CancellationToken cancellationToken,
|
||||
ToolkitFingerprintComponents? toolkitComponents = null,
|
||||
bool forceCleanBuild = false, BuildProgressWindow? progress = null,
|
||||
string? retroRewindPackageDirectory = null, string? baseOutputDirectory = null)
|
||||
{
|
||||
@@ -45,8 +46,9 @@ internal sealed class LocalBuildService
|
||||
retroRewindPackageDirectory = RetroRewindSource.ResolveRetroRewind6(
|
||||
retroRewindPackageDirectory);
|
||||
if (retroWfcPayloadMode == RetroWfcPayloadMode.Online)
|
||||
retroWfcOfflinePayloadDirectory =
|
||||
InputValidation.ValidateStagedRetroWfcPayloadDirectory(retroWfcOfflinePayloadDirectory!);
|
||||
retroWfcOfflinePayloadDirectory = InputValidation.ValidateStagedRetroWfcPayloadDirectory(
|
||||
retroWfcOfflinePayloadDirectory!,
|
||||
retroWfcGameId ?? throw new ArgumentException("The Retro-WFC payload needs its game id."));
|
||||
|
||||
var arguments = new List<string>
|
||||
{
|
||||
|
||||
@@ -33,16 +33,23 @@ internal sealed class InstallOptions
|
||||
public bool HasRetroRewind => RetroDirectoryPath is not null;
|
||||
}
|
||||
|
||||
/// <summary>A clean retail release the payload installs, as pinned by its projects/*/recomp.yml.</summary>
|
||||
internal sealed class GameRelease
|
||||
{
|
||||
public string GameId { get; set; } = "";
|
||||
public string DolSha256 { get; set; } = "";
|
||||
public string RelSha256 { get; set; } = "";
|
||||
}
|
||||
|
||||
internal sealed class PayloadManifest
|
||||
{
|
||||
public const int CurrentSchemaVersion = 3;
|
||||
|
||||
public int SchemaVersion { get; set; }
|
||||
public string ProductVersion { get; set; } = "";
|
||||
public string ExpectedGameId { get; set; } = "RMCP01";
|
||||
public string ExpectedDolSha256 { get; set; } = "";
|
||||
public string ExpectedRelSha256 { get; set; } = "";
|
||||
public List<GameRelease> SupportedReleases { get; set; } = [];
|
||||
public string ToolkitReleaseTag { get; set; } = "";
|
||||
public string BuildModel { get; set; } = "";
|
||||
public string RetroWfcPayloadUri { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Content identities computed once at release-build time (<c>Build-Installer.ps1 --emit-payload-identities</c>)
|
||||
|
||||
@@ -54,10 +54,21 @@ internal sealed class PayloadArchive : IDisposable
|
||||
var entry = FindEntry(InstalledLayout.PayloadManifestFileName)
|
||||
?? throw new InvalidDataException("The payload manifest is missing.");
|
||||
using var stream = entry.Open();
|
||||
return ParseManifest(stream);
|
||||
}
|
||||
|
||||
internal static PayloadManifest ParseManifest(Stream stream)
|
||||
{
|
||||
var manifest = JsonSerializer.Deserialize<PayloadManifest>(stream,
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true })
|
||||
?? throw new InvalidDataException("The payload manifest is invalid.");
|
||||
if (manifest.SchemaVersion != 2)
|
||||
ValidateManifest(manifest);
|
||||
return manifest;
|
||||
}
|
||||
|
||||
internal static void ValidateManifest(PayloadManifest manifest)
|
||||
{
|
||||
if (manifest.SchemaVersion != PayloadManifest.CurrentSchemaVersion)
|
||||
throw new InvalidDataException($"Unsupported payload schema {manifest.SchemaVersion}.");
|
||||
// The payload identities are the release-computed replacement for hashing the whole
|
||||
// toolkit on the user's machine; a payload without them was packaged incorrectly.
|
||||
@@ -65,8 +76,30 @@ internal sealed class PayloadArchive : IDisposable
|
||||
string.IsNullOrWhiteSpace(manifest.ToolkitPackageFingerprint) ||
|
||||
string.IsNullOrWhiteSpace(manifest.RuntimeAssetsFingerprint))
|
||||
throw new InvalidDataException("The payload manifest is missing its content identities.");
|
||||
InputValidation.ValidateRetroWfcPayloadUri(manifest.RetroWfcPayloadUri);
|
||||
return manifest;
|
||||
if (manifest.SupportedReleases is not { Count: > 0 })
|
||||
throw new InvalidDataException("The payload manifest names no supported game release.");
|
||||
foreach (var release in manifest.SupportedReleases)
|
||||
{
|
||||
if (!RetroWfcPayload.SupportedGameIds.Contains(release.GameId) ||
|
||||
!IsSha256(release.DolSha256) || !IsSha256(release.RelSha256))
|
||||
throw new InvalidDataException(
|
||||
$"The payload manifest describes an unsupported or incomplete release '{release.GameId}'.");
|
||||
}
|
||||
if (manifest.SupportedReleases.DistinctBy(release => release.GameId).Count() !=
|
||||
manifest.SupportedReleases.Count)
|
||||
throw new InvalidDataException("The payload manifest lists a game release twice.");
|
||||
}
|
||||
|
||||
private static bool IsSha256(string value) =>
|
||||
value.Length == 64 && value.All(char.IsAsciiHexDigit);
|
||||
|
||||
/// <summary>Extracts nodtool and the runtime DLLs it loads; returns the nodtool path.</summary>
|
||||
public string ExtractDiscTool(string directory)
|
||||
{
|
||||
var tool = Path.Combine(directory, "nodtool.exe");
|
||||
ExtractEntry(InstalledLayout.ToolkitEntryPrefix + "nodtool.exe", tool);
|
||||
ExtractDirectory(InstalledLayout.ToolkitEntryPrefix + "Redist", directory);
|
||||
return tool;
|
||||
}
|
||||
|
||||
public void ExtractEntry(string entryName, string destination)
|
||||
|
||||
@@ -99,7 +99,11 @@ internal sealed class ProductRepairService
|
||||
Directory.CreateDirectory(scratchRoot);
|
||||
|
||||
RetroWfcPayloadSnapshot? payloadSnapshot = null;
|
||||
if (requestedPayloadMode == RetroWfcPayloadMode.Online)
|
||||
// The installed disc's region decides which Retro-WFC payload the product embeds.
|
||||
var payloadGameId = requestedPayloadMode == RetroWfcPayloadMode.Online
|
||||
? _installation.ReadGameId()
|
||||
: null;
|
||||
if (payloadGameId is not null)
|
||||
{
|
||||
_reporter.Progress(InstallStages.PrepareRetro,
|
||||
"Downloading the current shared Retro-WFC payload snapshot...", 3);
|
||||
@@ -107,12 +111,12 @@ internal sealed class ProductRepairService
|
||||
try
|
||||
{
|
||||
payloadSnapshot = await InputValidation.DownloadRetroWfcPayloadAsync(
|
||||
InputValidation.CurrentRetroWfcPayloadUri, payloadScratch, cancellationToken);
|
||||
RetroWfcPayload.PayloadUri(payloadGameId), payloadScratch, cancellationToken);
|
||||
}
|
||||
catch (Exception ex) when (!cancellationToken.IsCancellationRequested &&
|
||||
ex is HttpRequestException or TimeoutException or IOException)
|
||||
{
|
||||
payloadSnapshot = RecoverInstalledRetroWfcPayload(toolkitFingerprint,
|
||||
payloadSnapshot = RecoverInstalledRetroWfcPayload(toolkitFingerprint, payloadGameId,
|
||||
Path.Combine(scratchRoot, "retro-wfc-payload-recovered"), ex, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -236,7 +240,7 @@ internal sealed class ProductRepairService
|
||||
"Recompiling Mario Kart Wii and Retro Rewind with the installed toolkit...", 5);
|
||||
await BuildWithCleanRetryAsync(forceCleanBuild, clean =>
|
||||
builder.BuildAsync(_installation.Root, BuildProfile.Both, retroOutput,
|
||||
requestedPayloadMode, payloadSnapshot?.Directory, cancellationToken,
|
||||
requestedPayloadMode, payloadSnapshot?.Directory, payloadGameId, cancellationToken,
|
||||
toolkitComponents, clean,
|
||||
progress: new BuildProgressWindow(_reporter, InstallStages.BuildBase, 5, 92),
|
||||
retroRewindPackageDirectory: compileInputs.RetroRewindRoot,
|
||||
@@ -255,7 +259,7 @@ internal sealed class ProductRepairService
|
||||
"Recompiling Mario Kart Wii with the installed toolkit...", 5);
|
||||
await BuildWithCleanRetryAsync(forceCleanBuild, clean =>
|
||||
builder.BuildAsync(_installation.Root, BuildProfile.Base, baseOutput,
|
||||
RetroWfcPayloadMode.NotApplicable, null, cancellationToken,
|
||||
RetroWfcPayloadMode.NotApplicable, null, null, cancellationToken,
|
||||
toolkitComponents, clean,
|
||||
progress: new BuildProgressWindow(_reporter, InstallStages.BuildBase, 5, 92)));
|
||||
LocalBuildService.WriteFingerprint(baseOutput, BuildProfile.Base, toolkitFingerprint,
|
||||
@@ -270,7 +274,7 @@ internal sealed class ProductRepairService
|
||||
"Recompiling Retro Rewind for the canonical Code.pul...", 5);
|
||||
await BuildWithCleanRetryAsync(forceCleanBuild, clean =>
|
||||
builder.BuildAsync(_installation.Root, BuildProfile.RetroRewind, retroOutput,
|
||||
requestedPayloadMode, payloadSnapshot?.Directory, cancellationToken,
|
||||
requestedPayloadMode, payloadSnapshot?.Directory, payloadGameId, cancellationToken,
|
||||
toolkitComponents, clean,
|
||||
progress: new BuildProgressWindow(_reporter, InstallStages.BuildRetro, 5, 92),
|
||||
retroRewindPackageDirectory: compileInputs.RetroRewindRoot));
|
||||
@@ -310,7 +314,8 @@ internal sealed class ProductRepairService
|
||||
|
||||
|
||||
private RetroWfcPayloadSnapshot RecoverInstalledRetroWfcPayload(string toolkitFingerprint,
|
||||
string destinationDirectory, Exception downloadFailure, CancellationToken cancellationToken)
|
||||
string gameId, string destinationDirectory, Exception downloadFailure,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
InvalidOperationException Unavailable(string reason) => new(
|
||||
"The Retro-WFC payload service is unavailable" +
|
||||
@@ -334,7 +339,7 @@ internal sealed class ProductRepairService
|
||||
try
|
||||
{
|
||||
cachedFile = InputValidation.ResolveRetroWfcPayloadFile(
|
||||
_installation.WorkspaceRetroWfcPayload);
|
||||
_installation.WorkspaceRetroWfcPayload, gameId);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (new FileInfo(cachedFile).Length != fingerprint.RetroWfcPayloadLength ||
|
||||
!InputValidation.Sha256File(cachedFile).Equals(fingerprint.RetroWfcPayloadSha256,
|
||||
@@ -343,11 +348,11 @@ internal sealed class ProductRepairService
|
||||
throw Unavailable("the installed payload snapshot no longer matches its recorded identity.");
|
||||
}
|
||||
|
||||
var destination = Path.Combine(Path.GetFullPath(destinationDirectory), "binary",
|
||||
"payload.RMCPD00.bin");
|
||||
var destination = Path.Combine(Path.GetFullPath(destinationDirectory),
|
||||
RetroWfcPayload.PayloadRelativePath(gameId));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destination)!);
|
||||
File.Copy(cachedFile, destination, overwrite: true);
|
||||
var root = InputValidation.ValidateStagedRetroWfcPayloadDirectory(destinationDirectory);
|
||||
var root = InputValidation.ValidateStagedRetroWfcPayloadDirectory(destinationDirectory, gameId);
|
||||
_reporter.Diagnostic(
|
||||
"The Retro-WFC payload service is unavailable; reusing the installation's verified " +
|
||||
$"payload snapshot (sha256 {fingerprint.RetroWfcPayloadSha256[..12]}..., " +
|
||||
|
||||
@@ -28,19 +28,9 @@ internal static class SelfTests
|
||||
}
|
||||
finally { File.Delete(path); }
|
||||
}, failures);
|
||||
Test("Disc compatibility", () =>
|
||||
InputValidation.EnsureCompatibleDisc(new DiscHeader { GameId = "RMCP01" },
|
||||
new PayloadManifest { ExpectedGameId = "RMCP01" }), failures);
|
||||
Test("Disc rejection", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
InputValidation.EnsureCompatibleDisc(new DiscHeader { GameId = "RMCJ01" },
|
||||
new PayloadManifest { ExpectedGameId = "RMCP01" });
|
||||
throw new Exception("Wrong region was accepted.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
}, failures);
|
||||
Test("Disc compatibility", TestDiscCompatibility, failures);
|
||||
Test("Payload manifest releases", TestPayloadManifestReleases, failures);
|
||||
Test("Extracted game release validation", TestExtractedGameRelease, failures);
|
||||
Test("Payload timestamp normalization", TestPayloadTimestampNormalization, failures);
|
||||
Test("Workspace timestamp reconciliation", TestWorkspaceTimestampReconciliation, failures);
|
||||
Test("Toolkit accompanies the workspace", TestToolkitRefreshDecision, failures);
|
||||
@@ -77,6 +67,152 @@ internal static class SelfTests
|
||||
return failures.Count == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
private static PayloadManifest MultiReleaseManifest() => new()
|
||||
{
|
||||
SchemaVersion = PayloadManifest.CurrentSchemaVersion,
|
||||
ToolkitFingerprint = "toolkit", ToolkitPackageFingerprint = "package", RuntimeAssetsFingerprint = "assets",
|
||||
SupportedReleases =
|
||||
[
|
||||
new GameRelease { GameId = "RMCP01", DolSha256 = new string('1', 64), RelSha256 = new string('2', 64) },
|
||||
new GameRelease { GameId = "RMCE01", DolSha256 = new string('3', 64), RelSha256 = new string('4', 64) },
|
||||
new GameRelease { GameId = "RMCJ01", DolSha256 = new string('5', 64), RelSha256 = new string('6', 64) }
|
||||
]
|
||||
};
|
||||
|
||||
private static void TestDiscCompatibility()
|
||||
{
|
||||
var manifest = MultiReleaseManifest();
|
||||
foreach (var release in manifest.SupportedReleases)
|
||||
{
|
||||
var selected = InputValidation.EnsureCompatibleDisc(
|
||||
new DiscHeader { GameId = release.GameId.ToLowerInvariant() }, manifest);
|
||||
if (!ReferenceEquals(selected, release))
|
||||
throw new Exception($"{release.GameId} did not select its own release.");
|
||||
}
|
||||
|
||||
foreach (var unsupported in new[] { "RMCK01", "RMCP02", "RSBE01" })
|
||||
{
|
||||
try
|
||||
{
|
||||
InputValidation.EnsureCompatibleDisc(new DiscHeader { GameId = unsupported }, manifest);
|
||||
throw new Exception($"{unsupported} was accepted.");
|
||||
}
|
||||
catch (InvalidDataException ex) when (ex.Message.Contains("NTSC-U (RMCE01)", StringComparison.Ordinal) &&
|
||||
ex.Message.Contains(unsupported, StringComparison.Ordinal)) { }
|
||||
}
|
||||
}
|
||||
|
||||
private static void TestPayloadManifestReleases()
|
||||
{
|
||||
PayloadArchive.ValidateManifest(MultiReleaseManifest());
|
||||
|
||||
// The shape Build-Installer.ps1 writes (PowerShell's ConvertTo-Json of the ordered manifest).
|
||||
var dol = new string('a', 64);
|
||||
var rel = new string('b', 64);
|
||||
var json = $$"""
|
||||
{
|
||||
"SchemaVersion": 3,
|
||||
"ProductVersion": "1.0.0",
|
||||
"SupportedReleases": [
|
||||
{ "GameId": "RMCP01", "DolSha256": "{{dol}}", "RelSha256": "{{rel}}" },
|
||||
{ "GameId": "RMCE01", "DolSha256": "{{rel}}", "RelSha256": "{{dol}}" }
|
||||
],
|
||||
"ToolkitReleaseTag": "",
|
||||
"BuildModel": "local-translation-and-compilation",
|
||||
"ToolkitFingerprint": "toolkit",
|
||||
"ToolkitPackageFingerprint": "package",
|
||||
"RuntimeAssetsFingerprint": "assets",
|
||||
"TranslationFingerprint": "translation",
|
||||
"NativeToolchainFingerprint": "native"
|
||||
}
|
||||
""";
|
||||
using (var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json)))
|
||||
{
|
||||
var parsed = PayloadArchive.ParseManifest(stream);
|
||||
if (parsed.SupportedReleases.Count != 2 || parsed.SupportedReleases[1].GameId != "RMCE01" ||
|
||||
parsed.SupportedReleases[1].DolSha256 != rel)
|
||||
throw new Exception("The packaged release list was not read back exactly.");
|
||||
}
|
||||
|
||||
void Reject(string description, Action<PayloadManifest> corrupt)
|
||||
{
|
||||
var manifest = MultiReleaseManifest();
|
||||
corrupt(manifest);
|
||||
try
|
||||
{
|
||||
PayloadArchive.ValidateManifest(manifest);
|
||||
throw new Exception($"A manifest with {description} was accepted.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
}
|
||||
|
||||
Reject("the previous single-release schema", manifest => manifest.SchemaVersion = 2);
|
||||
Reject("no releases", manifest => manifest.SupportedReleases.Clear());
|
||||
Reject("an unsupported release", manifest => manifest.SupportedReleases[0].GameId = "RMCK01");
|
||||
Reject("a missing input digest", manifest => manifest.SupportedReleases[1].RelSha256 = "");
|
||||
Reject("a duplicated release", manifest =>
|
||||
manifest.SupportedReleases.Add(new GameRelease
|
||||
{
|
||||
GameId = "RMCE01", DolSha256 = new string('7', 64), RelSha256 = new string('8', 64)
|
||||
}));
|
||||
}
|
||||
|
||||
private static void TestExtractedGameRelease()
|
||||
{
|
||||
var root = Path.Combine(Path.GetTempPath(), "mkwc-release-" + Guid.NewGuid().ToString("N"));
|
||||
try
|
||||
{
|
||||
var data = Path.Combine(root, "GameAssets", "DATA");
|
||||
Directory.CreateDirectory(Path.Combine(data, "sys"));
|
||||
Directory.CreateDirectory(Path.Combine(data, "files", "rel"));
|
||||
File.WriteAllText(Path.Combine(data, "sys", "main.dol"), "ntsc-u dol");
|
||||
File.WriteAllText(Path.Combine(data, "sys", "fst.bin"), "fst");
|
||||
File.WriteAllText(Path.Combine(data, "files", "rel", "StaticR.rel"), "ntsc-u rel");
|
||||
File.WriteAllText(Path.Combine(data, "sys", "boot.bin"), "RMCE01" + new string('\0', 26));
|
||||
var release = new GameRelease
|
||||
{
|
||||
GameId = "RMCE01",
|
||||
DolSha256 = InputValidation.Sha256File(Path.Combine(data, "sys", "main.dol")),
|
||||
RelSha256 = InputValidation.Sha256File(Path.Combine(data, "files", "rel", "StaticR.rel"))
|
||||
};
|
||||
|
||||
InstallerEngine.ValidateExtractedGame(data, release);
|
||||
if (new Installation(root).ReadGameId() != "RMCE01")
|
||||
throw new Exception("The installed game id was not read from the extracted disc header.");
|
||||
|
||||
void Reject(string description, GameRelease expected)
|
||||
{
|
||||
try
|
||||
{
|
||||
InstallerEngine.ValidateExtractedGame(data, expected);
|
||||
throw new Exception($"{description} was accepted.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
}
|
||||
|
||||
Reject("Another release's digests", new GameRelease
|
||||
{
|
||||
GameId = "RMCE01", DolSha256 = new string('1', 64), RelSha256 = release.RelSha256
|
||||
});
|
||||
Reject("A disc header of another region", new GameRelease
|
||||
{
|
||||
GameId = "RMCJ01", DolSha256 = release.DolSha256, RelSha256 = release.RelSha256
|
||||
});
|
||||
File.Delete(Path.Combine(data, "sys", "boot.bin"));
|
||||
Reject("An extraction without a disc header", release);
|
||||
try
|
||||
{
|
||||
_ = new Installation(root).ReadGameId();
|
||||
throw new Exception("A missing disc header produced a game id.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(root)) Directory.Delete(root, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void TestAcceptedExtension(string extension)
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + extension);
|
||||
@@ -694,42 +830,91 @@ internal static class SelfTests
|
||||
|
||||
private static void TestRetroWfcPayloadSnapshotReconciliation()
|
||||
{
|
||||
// The endpoint is pinned in exactly one place; this test must not restate it.
|
||||
const string endpoint = InputValidation.CurrentRetroWfcPayloadUri;
|
||||
const string shaB = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
|
||||
var root = Path.Combine(Path.GetTempPath(), "mkwc-wfc-snapshot-" + Guid.NewGuid().ToString("N"));
|
||||
try
|
||||
{
|
||||
InputValidation.ValidateRetroWfcPayloadUri(endpoint);
|
||||
using var signingRsa = RSA.Create(2048);
|
||||
var signingKey = signingRsa.ExportParameters(includePrivateParameters: false);
|
||||
byte[] SignedPayload(string payloadGame)
|
||||
{
|
||||
var image = new byte[0x150];
|
||||
"WWFC/Payload"u8.CopyTo(image);
|
||||
BinaryPrimitives.WriteUInt32BigEndian(image.AsSpan(0x0C), (uint)image.Length);
|
||||
System.Text.Encoding.ASCII.GetBytes(payloadGame).CopyTo(image, 0x138);
|
||||
image[^1] = 0x5A;
|
||||
signingRsa.SignData(image.AsSpan(0x110), HashAlgorithmName.SHA256,
|
||||
RSASignaturePadding.Pkcs1).CopyTo(image.AsSpan(0x10));
|
||||
return image;
|
||||
}
|
||||
|
||||
// Every supported release has its own endpoint and staged file, and a payload staged for
|
||||
// one region never validates as another region's.
|
||||
var endpoints = new HashSet<string>(StringComparer.Ordinal);
|
||||
foreach (var gameId in RetroWfcPayload.SupportedGameIds)
|
||||
{
|
||||
var endpoint = RetroWfcPayload.PayloadUri(gameId);
|
||||
InputValidation.ValidateRetroWfcPayloadUri(endpoint);
|
||||
if (!endpoints.Add(endpoint))
|
||||
throw new Exception($"{gameId} shares another release's Retro-WFC endpoint.");
|
||||
try
|
||||
{
|
||||
InputValidation.ValidateRetroWfcPayloadUri(endpoint + "&extra=1");
|
||||
throw new Exception("A non-canonical Retro-WFC endpoint was accepted.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
|
||||
var regionalRoot = Path.Combine(root, "regional-" + gameId);
|
||||
var regionalPath = Path.Combine(regionalRoot, RetroWfcPayload.PayloadRelativePath(gameId));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(regionalPath)!);
|
||||
File.WriteAllBytes(regionalPath, SignedPayload(RetroWfcPayload.PayloadGame(gameId)));
|
||||
if (InputValidation.ResolveRetroWfcPayloadFile(regionalRoot, gameId, signingKey) != regionalPath)
|
||||
throw new Exception($"{gameId} did not resolve its own staged payload file.");
|
||||
foreach (var otherGameId in RetroWfcPayload.SupportedGameIds.Where(other => other != gameId))
|
||||
{
|
||||
var foreignRoot = Path.Combine(root, $"foreign-{gameId}-{otherGameId}");
|
||||
var foreignPath = Path.Combine(foreignRoot, RetroWfcPayload.PayloadRelativePath(otherGameId));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(foreignPath)!);
|
||||
File.WriteAllBytes(foreignPath, SignedPayload(RetroWfcPayload.PayloadGame(gameId)));
|
||||
try
|
||||
{
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(foreignRoot, otherGameId,
|
||||
signingKey);
|
||||
throw new Exception($"A {gameId} payload was accepted for {otherGameId}.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
try
|
||||
{
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(regionalRoot, otherGameId,
|
||||
signingKey);
|
||||
throw new Exception($"{otherGameId} accepted a directory staged only for {gameId}.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
InputValidation.ValidateRetroWfcPayloadUri(endpoint + "&extra=1");
|
||||
throw new Exception("A non-canonical Retro-WFC endpoint was accepted.");
|
||||
_ = RetroWfcPayload.PayloadUri("RMCK01");
|
||||
throw new Exception("An unsupported release has a Retro-WFC endpoint.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
|
||||
const string gameUnderTest = "RMCE01";
|
||||
var installation = new Installation(root);
|
||||
Directory.CreateDirectory(installation.RetroDirectory);
|
||||
var payloadRoot = Path.Combine(root, "download");
|
||||
var payloadPath = Path.Combine(payloadRoot, "binary", "payload.RMCPD00.bin");
|
||||
var payloadPath = Path.Combine(payloadRoot, RetroWfcPayload.PayloadRelativePath(gameUnderTest));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(payloadPath)!);
|
||||
using var signingRsa = RSA.Create(2048);
|
||||
var signingKey = signingRsa.ExportParameters(includePrivateParameters: false);
|
||||
var bytes = new byte[0x140];
|
||||
"WWFC/Payload"u8.CopyTo(bytes);
|
||||
BinaryPrimitives.WriteUInt32BigEndian(bytes.AsSpan(0x0C), (uint)bytes.Length);
|
||||
bytes[^1] = 0x5A;
|
||||
signingRsa.SignData(bytes.AsSpan(0x110), HashAlgorithmName.SHA256,
|
||||
RSASignaturePadding.Pkcs1).CopyTo(bytes.AsSpan(0x10));
|
||||
var bytes = SignedPayload(RetroWfcPayload.PayloadGame(gameUnderTest));
|
||||
File.WriteAllBytes(payloadPath, bytes);
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey);
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey);
|
||||
try
|
||||
{
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot);
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest);
|
||||
throw new Exception("A payload signed by a foreign key passed the pinned production key.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
var shaA = InputValidation.ComputeRetroWfcPayloadSha256(payloadRoot, signingKey);
|
||||
var shaA = InputValidation.ComputeRetroWfcPayloadSha256(payloadRoot, gameUnderTest, signingKey);
|
||||
var snapshot = new RetroWfcPayloadSnapshot(payloadRoot, shaA, bytes.Length);
|
||||
JsonState.Write(Path.Combine(installation.RetroDirectory, ProductFingerprint.FileName),
|
||||
new ProductFingerprint
|
||||
@@ -764,7 +949,7 @@ internal static class SelfTests
|
||||
File.WriteAllBytes(payloadPath, bytes);
|
||||
try
|
||||
{
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey);
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey);
|
||||
throw new Exception("A payload with a malformed declared length was accepted.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
@@ -774,7 +959,7 @@ internal static class SelfTests
|
||||
File.WriteAllBytes(payloadPath, bytes);
|
||||
try
|
||||
{
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey);
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey);
|
||||
throw new Exception("A payload with tampered signed content was accepted.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
@@ -784,7 +969,7 @@ internal static class SelfTests
|
||||
File.WriteAllBytes(payloadPath, bytes);
|
||||
try
|
||||
{
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey);
|
||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey);
|
||||
throw new Exception("A payload with a malformed header was accepted.");
|
||||
}
|
||||
catch (InvalidDataException) { }
|
||||
@@ -1261,7 +1446,8 @@ internal static class SelfTests
|
||||
Directory.CreateDirectory(Path.Combine(root, "Toolkit", "CMake", "bin"));
|
||||
Directory.CreateDirectory(Path.Combine(root, "Toolkit", "Ninja"));
|
||||
Directory.CreateDirectory(Path.Combine(root, "Toolkit", "llvm-mingw", "bin"));
|
||||
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "projects", "mkwii"));
|
||||
foreach (var project in new[] { "mkwii", "mkwii-ntsc-u", "mkwii-ntsc-j" })
|
||||
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "projects", project));
|
||||
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "runtime", "src"));
|
||||
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "runtime", "assets", "wii", "shared2",
|
||||
"wc24"));
|
||||
@@ -1288,7 +1474,8 @@ internal static class SelfTests
|
||||
File.WriteAllText(Path.Combine(root, "Toolkit", "nodtool.exe"), "tool");
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "LocalBuild.ps1"), "# build");
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "NativeBuildFlags.ps1"), "# flags");
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "projects", "mkwii", "recomp.yml"), "profiles: {}");
|
||||
foreach (var project in new[] { "mkwii", "mkwii-ntsc-u", "mkwii-ntsc-j" })
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "projects", project, "recomp.yml"), "profiles: {}");
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "runtime", "CMakeLists.txt"), "cmake_minimum_required(VERSION 3.20)");
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "runtime", "src", "main.cpp"), "int main();");
|
||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "runtime", "assets", "wii", "shared2", "wc24",
|
||||
|
||||
@@ -16,15 +16,15 @@ internal static class ToolkitFingerprint
|
||||
// v6/native-toolchain v2 forces one clean rebuild past a Ninja stale-object bug.
|
||||
// translation v2 added runtime/src, which the translator regex-scans for native overrides;
|
||||
// v3 replaced it with the native index extracted from it, whenever that index is current.
|
||||
private const string Version = "mkwc-toolkit-compile-v6";
|
||||
private const string TranslationVersion = "mkwc-toolkit-translation-v3";
|
||||
private const string Version = "mkwc-toolkit-compile-v7";
|
||||
private const string TranslationVersion = "mkwc-toolkit-translation-v4";
|
||||
private const string NativeToolchainVersion = "mkwc-toolkit-native-toolchain-v2";
|
||||
private const string PackageVersion = "mkwc-toolkit-package-v1";
|
||||
private const string RuntimeAssetsVersion = "mkwc-product-runtime-assets-v3";
|
||||
private const string RuntimeAssetsDescription = "The product runtime assets";
|
||||
|
||||
private static readonly string[] SourceExtensions =
|
||||
[".c", ".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".inl", ".s", ".asm",
|
||||
[".c", ".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".inl", ".inc", ".s", ".asm",
|
||||
".cmake", ".txt", ".yml", ".yaml", ".toml", ".json", ".ps1", ".in", ".def", ".patch"];
|
||||
|
||||
/// <summary>
|
||||
@@ -40,7 +40,11 @@ internal static class ToolkitFingerprint
|
||||
];
|
||||
|
||||
private static readonly string[] TranslationFiles =
|
||||
[InstalledLayout.WorkspaceEntryPrefix + "LocalBuild.ps1"];
|
||||
[
|
||||
InstalledLayout.WorkspaceEntryPrefix + "LocalBuild.ps1",
|
||||
// Maps the PAL-keyed native index to the installed release's addresses.
|
||||
InstalledLayout.WorkspaceEntryPrefix + "runtime/include/guest_abi/guest_address_table.inc"
|
||||
];
|
||||
|
||||
private const string NativeSourcePrefix = InstalledLayout.WorkspaceEntryPrefix + "runtime/src/";
|
||||
private const string NativeIndexEntry = InstalledLayout.WorkspaceEntryPrefix + "runtime/native-index.json";
|
||||
|
||||
@@ -169,6 +169,8 @@ echo "Staging the bundled workspace snapshot..."
|
||||
for dir in runtime aurora-main projects; do
|
||||
cp -r "$workspace/$dir" "$appdir/workspace/$dir"
|
||||
done
|
||||
# Ship source bytes, never submodule checkout pointers or embedded Git databases.
|
||||
find "$appdir/workspace" -name .git -prune -exec rm -rf {} +
|
||||
# Mirrors Build-Installer.ps1's own staging exclusions exactly: aurora-main/extern/CMakeLists.txt
|
||||
# is the real FetchContent driver and must ship, but any already-fetched dependency *subdirectory*
|
||||
# a developer's local checkout accumulated under extern/ is stale/large build output, not a
|
||||
|
||||
+65
-2
@@ -1,5 +1,6 @@
|
||||
# Shared incremental-build logic for the Unix setups (Linux AppImage and macOS), sourced by
|
||||
# local-build.sh, local-build-macos.command, the AppImage's AppRun and macos/setup.command.
|
||||
# Shared incremental-build and release-selection logic for the Unix setups (Linux AppImage and
|
||||
# macOS), sourced by local-build.sh, local-build-macos.command, macos/extract-disc.command, the
|
||||
# AppImage's AppRun and macos/setup.command.
|
||||
# Mirrors the Windows installer's translation/toolchain identities and timestamp preservation.
|
||||
# Must stay compatible with macOS's bash 3.2.
|
||||
|
||||
@@ -76,6 +77,7 @@ mkw_translation_identity() {
|
||||
printf 'rel %s\n' "$(mkw_digest_path "$workspace/Assets/StaticR.rel")"
|
||||
printf 'translator %s\n' "$(mkw_digest_path "$translator")"
|
||||
printf 'script %s\n' "$(mkw_digest_path "$script")"
|
||||
printf 'regions %s\n' "$(mkw_digest_path "$workspace/runtime/include/guest_abi/guest_address_table.inc")"
|
||||
mkw_digest_tree "$workspace" projects
|
||||
mkw_native_index_identity "$workspace"
|
||||
} | mkw_sha256
|
||||
@@ -99,6 +101,67 @@ mkw_toolchain_identity() {
|
||||
} | mkw_sha256
|
||||
}
|
||||
|
||||
# Prints one fact a projects/*/recomp.yml pins: game_id, region, dol, rel or retro_wfc_payload.
|
||||
# Literal line matching against the fixed shape, like NativeBuildFlags.ps1's Get-MkwProjectPins.
|
||||
# $1 = recomp.yml, $2 = fact.
|
||||
mkw_project_pin() {
|
||||
awk -v want="$2" '
|
||||
{ sub(/\r$/, ""); sub(/#.*/, "") }
|
||||
/^[A-Za-z0-9_]+:/ { section = $1; sub(/:.*/, "", section); input = ""; next }
|
||||
section == "inputs" && /^ [A-Za-z0-9_]+:[[:space:]]*$/ { input = $1; sub(/:$/, "", input); next }
|
||||
section == "project" && $1 == (want ":") { print $2; exit }
|
||||
section == "inputs" && input == want && $1 == "sha256:" { print tolower($2); exit }
|
||||
want == "retro_wfc_payload" && $1 == "retro_wfc_payload:" { print $2; exit }
|
||||
' "$1"
|
||||
}
|
||||
|
||||
# Prints the recomp.yml of the supported release whose game id is $2. $1 = workspace.
|
||||
mkw_project_for_game() {
|
||||
local project
|
||||
for project in "$1"/projects/*/recomp.yml; do
|
||||
if [[ -f "$project" && "$(mkw_project_pin "$project" game_id)" == "$2" ]]; then
|
||||
printf '%s\n' "$project"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Prints the recomp.yml pinned to $2/main.dol after checking StaticR.rel and any extracted disc
|
||||
# header against it, like NativeBuildFlags.ps1's Resolve-MkwProjectForAssets.
|
||||
# $1 = workspace, $2 = assets directory.
|
||||
mkw_resolve_project() {
|
||||
local project dol_sha game_id disc_id
|
||||
dol_sha=$(mkw_sha256 "$2/main.dol")
|
||||
for project in "$1"/projects/*/recomp.yml; do
|
||||
[[ -f "$project" && "$(mkw_project_pin "$project" dol)" == "$dol_sha" ]] || continue
|
||||
game_id=$(mkw_project_pin "$project" game_id)
|
||||
if [[ "$(mkw_sha256 "$2/StaticR.rel")" != "$(mkw_project_pin "$project" rel)" ]]; then
|
||||
printf 'StaticR.rel does not match the clean %s release of main.dol.\n' "$game_id" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ -f "$2/DATA/sys/boot.bin" ]]; then
|
||||
disc_id=$(head -c 6 "$2/DATA/sys/boot.bin")
|
||||
if [[ "$disc_id" != "$game_id" ]]; then
|
||||
printf 'The extracted game data is %s but main.dol is %s; extract the game again.\n' "$disc_id" "$game_id" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
printf '%s\n' "$project"
|
||||
return 0
|
||||
done
|
||||
printf 'main.dol (sha256 %s) is not a supported clean Mario Kart Wii release.\n' "$dol_sha" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# The offline file name the translator expects for a release's Retro-WFC payload. $1 = recomp.yml.
|
||||
mkw_retro_wfc_payload_file() {
|
||||
local uri
|
||||
uri=$(mkw_project_pin "$1" retro_wfc_payload)
|
||||
[[ -n "$uri" ]] || return 1
|
||||
printf 'binary/payload.%s.bin\n' "${uri##*g=}"
|
||||
}
|
||||
|
||||
# $1 = JSON file, $2 = key. Prints the recorded string value, or nothing.
|
||||
mkw_read_identity() {
|
||||
[[ -f "$1" ]] || return 0
|
||||
|
||||
@@ -19,9 +19,9 @@ Usage: local-build-macos.command --output-dir DIR [options]
|
||||
--profile {base|retro-rewind|both} Product to build (default: base)
|
||||
--output-dir DIR Output .app directory (required; Retro Rewind for both)
|
||||
--base-output-dir DIR Base .app directory (required with --profile both)
|
||||
--game IMAGE --nodtool PATH Extract and verify a clean PAL RMCP01 disc image first
|
||||
--game IMAGE --nodtool PATH Extract and verify a clean supported disc image first
|
||||
--retro-rewind-package-dir DIR RetroRewind6 directory (required for Retro Rewind)
|
||||
--retro-wfc-offline-dir DIR Directory containing binary/payload.RMCPD00.bin
|
||||
--retro-wfc-offline-dir DIR Directory containing the release's binary/payload.<game>.bin
|
||||
--skip-retro-wfc-payload Build Retro Rewind without the shared Retro-WFC payload
|
||||
--force-clean-build Delete local generated and current-architecture native build caches
|
||||
--parallel N Pin translation and build parallelism
|
||||
@@ -82,13 +82,15 @@ if (( builds_retro )); then
|
||||
fi
|
||||
for tool in "$cmake_bin" "$ninja_bin" clang clang++ shasum; do command -v "$tool" >/dev/null || fail "required tool not found: $tool"; done
|
||||
|
||||
project="$workspace/projects/mkwii/recomp.yml"; assets="$workspace/Assets"; generated="$workspace/generated"
|
||||
assets="$workspace/Assets"; generated="$workspace/generated"
|
||||
functions="$generated/functions"; metadata="$generated/base_translation_output.json"; manifest_dir="$workspace/build/base"
|
||||
manifest="$manifest_dir/mkwii_base_manifest.json"; shards="$generated/build_shards"
|
||||
native_build="$workspace/native-build-macos-$macos_arch"
|
||||
assert_file "$project" 'translation project'
|
||||
if [[ -n "$game" ]]; then "$script_dir/macos/extract-disc.command" --game "$game" --assets-dir "$assets" --nodtool "$nodtool"; fi
|
||||
if [[ -n "$game" ]]; then "$script_dir/macos/extract-disc.command" --workspace "$workspace" --game "$game" --assets-dir "$assets" --nodtool "$nodtool"; fi
|
||||
assert_file "$assets/main.dol" 'extracted main.dol'; assert_file "$assets/StaticR.rel" 'extracted StaticR.rel'
|
||||
# The translation project is the one pinned to the extracted main.dol, which decides the region.
|
||||
project=$(mkw_resolve_project "$workspace" "$assets") || fail 'the extracted game cannot be translated'
|
||||
region=$(mkw_project_pin "$project" region); [[ -n "$region" ]] || fail "could not find the region of $project"
|
||||
|
||||
if (( force_clean )); then
|
||||
step force-clean 'Discarding translation and native build caches'
|
||||
@@ -148,12 +150,12 @@ else
|
||||
step translate-base 'Translating the user-owned base game'
|
||||
translator translate-recursive "$entry_point" --project "$project" --outdir "$functions" --output-metadata "$metadata" --production-source-bundle "$generated/base_translation_sources.bin" --no-function-files --prune-stale --threads "$translator_threads"
|
||||
step emit-base-manifest 'Creating the local base translation manifest'
|
||||
translator emit-base-manifest --project "$project" --out "$manifest_dir" --functions-dir "$functions" --translation-output-metadata "$metadata" --region P
|
||||
translator emit-base-manifest --project "$project" --out "$manifest_dir" --functions-dir "$functions" --translation-output-metadata "$metadata" --region "$region"
|
||||
mkw_write_identity "$translation_provenance" TranslationFingerprint "$translation_fingerprint"
|
||||
fi
|
||||
if (( builds_retro )); then
|
||||
mod_out="$workspace/build/mods/retro_rewind_full_cpp"; args=(translate-mod --project "$project" --profile retro-rewind --base-manifest "$manifest" --base-translation-output-metadata "$metadata" --code-pul "$retro_root/Binaries/Code.pul" --mod-root "$retro_root" --mod-name 'Retro Rewind' --region P --out "$mod_out" --prefer-cached-inputs --emit-cpp --threads "$translator_threads")
|
||||
if (( skip_retro_wfc )); then args+=(--skip-retro-wfc); else offline_payload="$retro_wfc/binary/payload.RMCPD00.bin"; assert_file "$offline_payload" 'Offline Retro-WFC payload'; args+=(--retro-wfc-payload "$offline_payload"); fi
|
||||
mod_out="$workspace/build/mods/retro_rewind_full_cpp"; args=(translate-mod --project "$project" --profile retro-rewind --base-manifest "$manifest" --base-translation-output-metadata "$metadata" --code-pul "$retro_root/Binaries/Code.pul" --mod-root "$retro_root" --mod-name 'Retro Rewind' --region "$region" --out "$mod_out" --prefer-cached-inputs --emit-cpp --threads "$translator_threads")
|
||||
if (( skip_retro_wfc )); then args+=(--skip-retro-wfc); else payload_file=$(mkw_retro_wfc_payload_file "$project") || fail "$project pins no Retro-WFC payload"; offline_payload="$retro_wfc/$payload_file"; assert_file "$offline_payload" 'Offline Retro-WFC payload'; args+=(--retro-wfc-payload "$offline_payload"); fi
|
||||
step translate-mod 'Translating Retro Rewind'; translator "${args[@]}"
|
||||
fi
|
||||
step generate-data-init 'Generating local game data initialization'; translator generate-data-init --project "$project"
|
||||
|
||||
+34
-6
@@ -69,6 +69,7 @@ fuse_ld_override=""
|
||||
native_prebuilt_dir=""
|
||||
sysroot=""
|
||||
setup_version=""
|
||||
x86_cpu_profile=auto
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
@@ -95,6 +96,8 @@ Usage: local-build.sh --output-dir DIR [options]
|
||||
standard headers/startup files
|
||||
--setup-version VERSION Version recorded in the runtime log (default: <Version> in
|
||||
Launcher/Directory.Build.props when present)
|
||||
--x86-cpu-profile {auto|v2|v3} x86-64 instruction set to build for (default: auto, v3 when
|
||||
this machine supports it)
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -120,6 +123,7 @@ while [[ $# -gt 0 ]]; do
|
||||
--native-prebuilt-dir) native_prebuilt_dir=$2; shift 2 ;;
|
||||
--sysroot) sysroot=$2; shift 2 ;;
|
||||
--setup-version) setup_version=$2; shift 2 ;;
|
||||
--x86-cpu-profile) x86_cpu_profile=$2; shift 2 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) fail "unknown argument: $1" ;;
|
||||
esac
|
||||
@@ -135,6 +139,10 @@ case "$profile" in
|
||||
base|retro-rewind|both) ;;
|
||||
*) fail "--profile must be base, retro-rewind, or both" ;;
|
||||
esac
|
||||
case "$x86_cpu_profile" in
|
||||
auto|v2|v3) ;;
|
||||
*) fail "--x86-cpu-profile must be auto, v2, or v3" ;;
|
||||
esac
|
||||
|
||||
builds_retro=0
|
||||
[[ "$profile" == "retro-rewind" || "$profile" == "both" ]] && builds_retro=1
|
||||
@@ -184,7 +192,22 @@ if [[ -n "$native_prebuilt_dir" ]]; then
|
||||
assert_file "$native_prebuilt_dir/native_prebuilt.cmake" "Native prebuilt package"
|
||||
fi
|
||||
|
||||
project=$workspace/projects/mkwii/recomp.yml
|
||||
host_supports_x86_64_v3() {
|
||||
local macros macro
|
||||
macros=$("$cc_bin" -march=native -dM -E -x c /dev/null 2>/dev/null) || return 1
|
||||
for macro in __AVX__ __AVX2__ __BMI__ __BMI2__ __F16C__ __FMA__ __LZCNT__ __MOVBE__; do
|
||||
grep -q "^#define $macro " <<<"$macros" || return 1
|
||||
done
|
||||
}
|
||||
|
||||
if [[ "$x86_cpu_profile" == "auto" ]]; then
|
||||
x86_cpu_profile=v3
|
||||
if [[ "$(uname -m)" == "x86_64" ]] && ! host_supports_x86_64_v3; then
|
||||
x86_cpu_profile=v2
|
||||
echo "MKWCBUILD: This CPU does not support x86-64-v3; building for x86-64-v2"
|
||||
fi
|
||||
fi
|
||||
|
||||
assets=$workspace/Assets
|
||||
generated=$workspace/generated
|
||||
functions=$generated/functions
|
||||
@@ -197,9 +220,12 @@ translation_provenance=$generated/translation-provenance.json
|
||||
toolchain_provenance=$build/toolchain-provenance.json
|
||||
retro_root=${retro_rewind_package_dir:-$workspace/PulsarPacks/completed/RetroRewind/RetroRewind6}
|
||||
|
||||
assert_file "$project" "Translation project"
|
||||
assert_file "$assets/main.dol" "Extracted main.dol (see translator/README.md - owning the game is required)"
|
||||
assert_file "$assets/StaticR.rel" "Extracted StaticR.rel (see translator/README.md - owning the game is required)"
|
||||
# The translation project is the one pinned to the extracted main.dol, which decides the region.
|
||||
project=$(mkw_resolve_project "$workspace" "$assets") || fail "the extracted game cannot be translated"
|
||||
region=$(mkw_project_pin "$project" region)
|
||||
[[ -n "$region" ]] || fail "Could not find the region of $project"
|
||||
|
||||
# The AppImage bundles Clang, but Linux startup objects and the C/C++ link runtimes
|
||||
# still come from the host. Check them before the expensive translation so a missing
|
||||
@@ -338,7 +364,7 @@ else
|
||||
|
||||
log_step emit-base-manifest "Creating the local base translation manifest"
|
||||
translator emit-base-manifest --project "$project" --out "$base_manifest_dir" \
|
||||
--functions-dir "$functions" --translation-output-metadata "$base_metadata" --region P
|
||||
--functions-dir "$functions" --translation-output-metadata "$base_metadata" --region "$region"
|
||||
|
||||
mkw_write_identity "$translation_provenance" TranslationFingerprint "$translation_fingerprint"
|
||||
fi
|
||||
@@ -350,12 +376,13 @@ if (( builds_retro )); then
|
||||
translate_mod_args=(translate-mod --project "$project" --profile retro-rewind
|
||||
--base-manifest "$base_manifest" --base-translation-output-metadata "$base_metadata"
|
||||
--code-pul "$code_pul" --mod-root "$retro_root" --mod-name "Retro Rewind"
|
||||
--region P --out "$retro_out" --prefer-cached-inputs --emit-cpp
|
||||
--region "$region" --out "$retro_out" --prefer-cached-inputs --emit-cpp
|
||||
--threads "$translator_threads")
|
||||
if (( skip_retro_wfc_payload )); then
|
||||
translate_mod_args+=(--skip-retro-wfc)
|
||||
else
|
||||
offline_payload=$retro_wfc_offline_dir/binary/payload.RMCPD00.bin
|
||||
payload_file=$(mkw_retro_wfc_payload_file "$project") || fail "$project pins no Retro-WFC payload"
|
||||
offline_payload=$retro_wfc_offline_dir/$payload_file
|
||||
assert_file "$offline_payload" "Offline Retro-WFC shared payload"
|
||||
translate_mod_args+=(--retro-wfc-payload "$offline_payload")
|
||||
fi
|
||||
@@ -434,7 +461,8 @@ configure_args=(-S "$workspace/runtime" -B "$build" -G Ninja
|
||||
-DCMAKE_C_COMPILER="$cc_bin" -DCMAKE_CXX_COMPILER="$cxx_bin"
|
||||
-DCMAKE_MAKE_PROGRAM="$ninja_bin"
|
||||
-DMKW_TRANSLATED_COMPILE_JOBS="$translated_jobs"
|
||||
-DMKW_SETUP_VERSION="$setup_version")
|
||||
-DMKW_SETUP_VERSION="$setup_version"
|
||||
-DMKW_X86_CPU_PROFILE="$x86_cpu_profile")
|
||||
# CMAKE_C_COMPILER/CXX_COMPILER stay stable across AppImage runs on their own (they're exactly
|
||||
# what's passed via -D above, and AppRun points --cc/--cxx at a symlink it re-targets at the
|
||||
# current mount every launch - see build-appimage.sh). CMAKE_AR/RANLIB/LINKER/ASM_COMPILER do NOT
|
||||
|
||||
@@ -148,8 +148,12 @@ copy_clean "$script_dir/setup.command" "$resources/setup.command"; chmod +x "$re
|
||||
mkdir -p "$resources/workspace"
|
||||
for source in aurora-main projects runtime translator; do
|
||||
[[ -d "$workspace/$source" ]] || fail "required workspace directory is missing: $source"
|
||||
[[ "$source" != aurora-main || -f "$workspace/$source/CMakeLists.txt" ]] ||
|
||||
fail "aurora-main is empty; run git submodule update --init --recursive"
|
||||
copy_clean "$workspace/$source" "$resources/workspace/$source"
|
||||
done
|
||||
# Setup bundles contain materialized sources and must work without Git.
|
||||
find "$resources/workspace" -name .git -prune -exec rm -rf {} +
|
||||
# The translation identity (build-cache.sh) covers the runtime's native registrations through this
|
||||
# index, so it is extracted from exactly the packaged runtime sources.
|
||||
if [[ "$host_arch" == arm64 ]]; then host_translator=$translator_arm64; else host_translator=$translator_x86_64; fi
|
||||
|
||||
@@ -1,30 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
# Extract a user-owned Mario Kart Wii PAL (RMCP01) disc image for a local build.
|
||||
# Extract a user-owned Mario Kart Wii disc image of a supported release for a local build.
|
||||
# This script deliberately contains no game data and is intended for the macOS
|
||||
# setup application and for maintainers testing that setup path.
|
||||
set -euo pipefail
|
||||
|
||||
readonly EXPECTED_DOL_SHA256=80d18895b39c63bd80f457398bfcbb91b7d16ac116a41a88967e954080155b05
|
||||
readonly EXPECTED_REL_SHA256=16d9d146112541fefea701ecb5bc1a496f9d50e4a752fbb5b6778e7c6399f67d
|
||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
# shellcheck source=../build-cache.sh
|
||||
source "$script_dir/../build-cache.sh"
|
||||
|
||||
fail() { printf 'extract-disc.command: error: %s\n' "$*" >&2; exit 1; }
|
||||
sha256() { shasum -a 256 "$1" | awk '{ print $1 }'; }
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: extract-disc.command --game IMAGE --assets-dir DIR --nodtool PATH
|
||||
Usage: extract-disc.command --game IMAGE --assets-dir DIR --nodtool PATH [--workspace DIR]
|
||||
|
||||
Extracts a user-owned Mario Kart Wii PAL RMCP01 image into DIR. The final
|
||||
layout is DIR/main.dol, DIR/StaticR.rel, and DIR/DATA. Existing data is left
|
||||
untouched unless the complete new extraction passes both content hash checks.
|
||||
Extracts a user-owned Mario Kart Wii image into DIR. The image must be a release
|
||||
a projects/*/recomp.yml in the workspace (default: this script's repository)
|
||||
pins. The final layout is DIR/main.dol, DIR/StaticR.rel, and DIR/DATA. Existing
|
||||
data is left untouched unless the complete new extraction passes both content
|
||||
hash checks.
|
||||
EOF
|
||||
}
|
||||
|
||||
game=""
|
||||
assets_dir=""
|
||||
nodtool=""
|
||||
workspace=$(cd "$script_dir/../.." && pwd)
|
||||
while (($#)); do
|
||||
case "$1" in
|
||||
--workspace) workspace=${2:-}; shift 2 ;;
|
||||
--game) game=${2:-}; shift 2 ;;
|
||||
--assets-dir) assets_dir=${2:-}; shift 2 ;;
|
||||
--nodtool) nodtool=${2:-}; shift 2 ;;
|
||||
@@ -39,11 +44,21 @@ done
|
||||
|
||||
assets_dir=$(mkdir -p "$assets_dir" && cd "$assets_dir" && pwd)
|
||||
|
||||
# The disc's game ID selects the release, so an existing extraction is only reused for the same one.
|
||||
printf 'MKWCBUILD:STEP:validate-disc Checking the selected disc image\n'
|
||||
disc_info=$("$nodtool" info "$game") || fail 'nodtool could not read the disc image'
|
||||
game_id=$(awk '/^Game ID: / { print $3; exit }' <<<"$disc_info")
|
||||
[[ -n "$game_id" ]] || fail 'nodtool did not report the disc game ID'
|
||||
project=$(mkw_project_for_game "$workspace" "$game_id") || fail "disc $game_id is not a supported Mario Kart Wii release"
|
||||
expected_dol_sha256=$(mkw_project_pin "$project" dol)
|
||||
expected_rel_sha256=$(mkw_project_pin "$project" rel)
|
||||
[[ -n "$expected_dol_sha256" && -n "$expected_rel_sha256" ]] || fail "$project does not pin the clean $game_id digests"
|
||||
|
||||
# Sorted "<size> <path>" of every extracted file; recorded at extraction, compared on reuse.
|
||||
data_manifest() { (cd "$1" && find . -type f -print0 | LC_ALL=C sort -z | xargs -0 stat -f '%z %N'); }
|
||||
|
||||
if [[ -d "$assets_dir/DATA/files" && -f "$assets_dir/.data-manifest" && -f "$assets_dir/main.dol" && -f "$assets_dir/StaticR.rel" ]] && \
|
||||
[[ $(sha256 "$assets_dir/main.dol") == "$EXPECTED_DOL_SHA256" && $(sha256 "$assets_dir/StaticR.rel") == "$EXPECTED_REL_SHA256" ]] && \
|
||||
[[ $(sha256 "$assets_dir/main.dol") == "$expected_dol_sha256" && $(sha256 "$assets_dir/StaticR.rel") == "$expected_rel_sha256" ]] && \
|
||||
[[ "$(data_manifest "$assets_dir/DATA")" == "$(cat "$assets_dir/.data-manifest")" ]]; then
|
||||
printf 'MKWCBUILD:STEP:disc-ready Reusing the verified extracted game assets\n'
|
||||
exit 0
|
||||
@@ -52,8 +67,6 @@ scratch=$(mktemp -d "${TMPDIR:-/tmp}/wiicompiled-disc.XXXXXX")
|
||||
cleanup() { rm -rf "$scratch"; }
|
||||
trap cleanup EXIT
|
||||
|
||||
printf 'MKWCBUILD:STEP:validate-disc Checking the selected disc image\n'
|
||||
"$nodtool" info "$game" >/dev/null
|
||||
printf 'MKWCBUILD:STEP:extract-disc Extracting the user-owned disc image\n'
|
||||
"$nodtool" extract "$game" "$scratch/extracted"
|
||||
|
||||
@@ -63,8 +76,8 @@ rel=$(find "$scratch/extracted" -type f -path '*/files/rel/StaticR.rel' -print -
|
||||
[[ -n "$rel" ]] || fail 'nodtool extraction did not contain files/rel/StaticR.rel'
|
||||
dol_sha=$(sha256 "$dol")
|
||||
rel_sha=$(sha256 "$rel")
|
||||
[[ $dol_sha == "$EXPECTED_DOL_SHA256" ]] || fail "main.dol does not match the clean PAL RMCP01 image (expected $EXPECTED_DOL_SHA256, got $dol_sha)"
|
||||
[[ $rel_sha == "$EXPECTED_REL_SHA256" ]] || fail "StaticR.rel does not match the clean PAL RMCP01 image (expected $EXPECTED_REL_SHA256, got $rel_sha)"
|
||||
[[ $dol_sha == "$expected_dol_sha256" ]] || fail "main.dol does not match the clean $game_id image (expected $expected_dol_sha256, got $dol_sha)"
|
||||
[[ $rel_sha == "$expected_rel_sha256" ]] || fail "StaticR.rel does not match the clean $game_id image (expected $expected_rel_sha256, got $rel_sha)"
|
||||
|
||||
data_root=$(dirname "$(dirname "$dol")")
|
||||
[[ -d "$data_root/files" ]] || fail 'nodtool extraction did not contain the Wii files directory'
|
||||
@@ -92,4 +105,4 @@ mv "$stage/StaticR.rel" "$assets_dir/StaticR.rel"
|
||||
rmdir "$stage"
|
||||
rm -rf "$backup"
|
||||
|
||||
printf 'MKWCBUILD:STEP:disc-ready Verified and extracted clean PAL RMCP01 game assets\n'
|
||||
printf 'MKWCBUILD:STEP:disc-ready Verified and extracted clean %s game assets\n' "$game_id"
|
||||
|
||||
@@ -48,7 +48,7 @@ ninja_bin="$host_tools/ninja"
|
||||
|
||||
if [[ -z "$game" ]]; then
|
||||
game=$(/usr/bin/osascript <<'APPLESCRIPT'
|
||||
set selectedFile to choose file with prompt "Choose your clean Mario Kart Wii PAL (RMCP01) disc image"
|
||||
set selectedFile to choose file with prompt "Choose your clean Mario Kart Wii disc image"
|
||||
POSIX path of selectedFile
|
||||
APPLESCRIPT
|
||||
) || exit 0
|
||||
@@ -100,18 +100,28 @@ if (( needs_workspace_refresh )); then
|
||||
fi
|
||||
fi
|
||||
|
||||
# The extracted disc decides the release, and with it the region's Retro-WFC payload.
|
||||
# shellcheck source=../build-cache.sh
|
||||
source "$workspace/Launcher/build-cache.sh"
|
||||
"$workspace/Launcher/macos/extract-disc.command" --workspace "$workspace" --game "$game" \
|
||||
--assets-dir "$workspace/Assets" --nodtool "$nodtool"
|
||||
project=$(mkw_resolve_project "$workspace" "$workspace/Assets") || fail 'the extracted game cannot be built'
|
||||
|
||||
profile=base
|
||||
build_args=(--workspace "$workspace" --game "$game" --nodtool "$nodtool" --output-dir "$products")
|
||||
build_args=(--workspace "$workspace" --output-dir "$products")
|
||||
if [[ -n "$retro_dir" ]]; then
|
||||
profile=both
|
||||
# Online play needs the shared Retro-WFC payload. Keep it in the per-user
|
||||
# support directory rather than the packaged app or build workspace, then
|
||||
# verify its pinned signature before publishing it into the local cache.
|
||||
game_id=$(mkw_project_pin "$project" game_id)
|
||||
payload_uri=$(mkw_project_pin "$project" retro_wfc_payload)
|
||||
payload_file=$(mkw_retro_wfc_payload_file "$project") || fail "$project pins no Retro-WFC payload"
|
||||
retro_wfc_dir="$support_root/RetroWfcPayload"
|
||||
retro_wfc_payload="$retro_wfc_dir/binary/payload.RMCPD00.bin"
|
||||
retro_wfc_payload="$retro_wfc_dir/$payload_file"
|
||||
cached_payload_valid=0
|
||||
if [[ -f "$retro_wfc_payload" ]]; then
|
||||
if "$translator" validate-retro-wfc-payload --directory "$retro_wfc_dir"; then
|
||||
if "$translator" validate-retro-wfc-payload --directory "$retro_wfc_dir" --game-id "$game_id"; then
|
||||
cached_payload_valid=1
|
||||
else
|
||||
printf 'Discarding an invalid cached Retro-WFC payload...\n' >&2
|
||||
@@ -125,15 +135,14 @@ if [[ -n "$retro_dir" ]]; then
|
||||
printf 'Downloading the current Retro-WFC payload needed for online play...\n'
|
||||
mkdir -p "$retro_wfc_dir"
|
||||
payload_stage=$(mktemp -d "$retro_wfc_dir/.payload-download.XXXXXX")
|
||||
temporary_payload="$payload_stage/binary/payload.RMCPD00.bin"
|
||||
temporary_payload="$payload_stage/$payload_file"
|
||||
mkdir -p "$(dirname "$temporary_payload")"
|
||||
trap 'rm -rf "$payload_stage"' EXIT
|
||||
if /usr/bin/curl --fail --silent --show-error --connect-timeout 10 --max-time 30 \
|
||||
--retry 1 --output "$temporary_payload" \
|
||||
'https://rwfc.net/api/wfc/payload?g=RMCPD00'; then
|
||||
"$translator" validate-retro-wfc-payload --directory "$payload_stage" || \
|
||||
--retry 1 --output "$temporary_payload" "$payload_uri"; then
|
||||
"$translator" validate-retro-wfc-payload --directory "$payload_stage" --game-id "$game_id" || \
|
||||
fail 'downloaded Retro-WFC payload failed signature validation'
|
||||
mkdir -p "$retro_wfc_dir/binary"
|
||||
mkdir -p "$(dirname "$retro_wfc_payload")"
|
||||
mv "$temporary_payload" "$retro_wfc_payload"
|
||||
rmdir "$payload_stage/binary" "$payload_stage"
|
||||
trap - EXIT
|
||||
|
||||
Submodule
+1
Submodule aurora-main added at ff0b617a92
@@ -1,29 +0,0 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
ColumnLimit: 120
|
||||
UseTab: Never
|
||||
TabWidth: 2
|
||||
---
|
||||
Language: Cpp
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
IndentCaseLabels: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
Cpp11BracedListStyle: true
|
||||
NamespaceIndentation: None
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
SortIncludes: false
|
||||
AccessModifierOffset: -2
|
||||
ConstructorInitializerIndentWidth: 0
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
@@ -1,10 +0,0 @@
|
||||
.buildcache/
|
||||
.DS_Store
|
||||
.idea/
|
||||
.cache/
|
||||
.vscode/
|
||||
.vs/
|
||||
build/
|
||||
cmake-build-*/
|
||||
CMakeUserPresets.json
|
||||
out/
|
||||
@@ -1,93 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
project(aurora LANGUAGES C CXX)
|
||||
if (APPLE)
|
||||
enable_language(OBJC)
|
||||
enable_language(OBJCXX)
|
||||
endif()
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
option(AURORA_ENABLE_GX "Enable GX implementation and WebGPU renderer" ON)
|
||||
option(AURORA_ENABLE_DVD "Enable DVD implementation backed by nod" OFF) # TODO: need to fix tests
|
||||
option(AURORA_ENABLE_CARD "Enable CARD implementation based on kabufuda" ON)
|
||||
option(AURORA_CACHE_USE_ZSTD "Compress WebGPU cache entries with zstd" ON)
|
||||
|
||||
# Dependency versions
|
||||
set(AURORA_DAWN_VERSION "v20260603.191052" CACHE STRING "Dawn version tag (https://github.com/encounter/dawn-build/releases)")
|
||||
set(AURORA_SDL3_VERSION "3.4.4" CACHE STRING "SDL3 version tag (https://github.com/libsdl-org/SDL/releases)")
|
||||
set(AURORA_NOD_VERSION "v2.0.0-alpha.8" CACHE STRING "nod version tag (https://github.com/encounter/nod/releases)")
|
||||
set(AURORA_LIBUSB_VERSION "1.0.30" CACHE STRING "libusb version tag (https://github.com/libusb/libusb/releases)")
|
||||
|
||||
# Platform-specific defaults
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
# Cross-compiling: vendor everything, don't use system packages
|
||||
set(_default_provider "vendor")
|
||||
set(_default_linkage "static")
|
||||
else ()
|
||||
set(_default_provider "auto")
|
||||
if (WIN32)
|
||||
set(_default_linkage "shared")
|
||||
else ()
|
||||
set(_default_linkage "static")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# Dawn/WebGPU (if AURORA_ENABLE_GX)
|
||||
set(AURORA_DAWN_PROVIDER "${_default_provider}" CACHE STRING
|
||||
"How to provide Dawn: auto, vendor (build from source), system (find_package/imported), package (download prebuilt)")
|
||||
set_property(CACHE AURORA_DAWN_PROVIDER PROPERTY STRINGS auto vendor system package)
|
||||
set(AURORA_DAWN_LINKAGE "${_default_linkage}" CACHE STRING "Dawn linkage type preference")
|
||||
set_property(CACHE AURORA_DAWN_LINKAGE PROPERTY STRINGS shared static)
|
||||
|
||||
# SDL3
|
||||
set(AURORA_SDL3_PROVIDER "${_default_provider}" CACHE STRING
|
||||
"How to provide SDL3: auto, vendor (build from source), system (find_package/imported), or package (download prebuilt)")
|
||||
set_property(CACHE AURORA_SDL3_PROVIDER PROPERTY STRINGS auto vendor system package)
|
||||
set(AURORA_SDL3_LINKAGE "${_default_linkage}" CACHE STRING "SDL3 linkage type preference")
|
||||
set_property(CACHE AURORA_SDL3_LINKAGE PROPERTY STRINGS shared static)
|
||||
option(AURORA_SDL3_LIBUSB "Build the vendored SDL3 with libusb on Windows (official GameCube adapter support)" ON)
|
||||
|
||||
# nod (if AURORA_ENABLE_DVD)
|
||||
set(AURORA_NOD_PROVIDER "${_default_provider}" CACHE STRING
|
||||
"How to provide nod: auto, vendor (build from source), system (find_package/imported), package (download prebuilt)")
|
||||
set_property(CACHE AURORA_NOD_PROVIDER PROPERTY STRINGS auto vendor system package)
|
||||
set(AURORA_NOD_LINKAGE "${_default_linkage}" CACHE STRING "nod linkage type preference")
|
||||
set_property(CACHE AURORA_NOD_LINKAGE PROPERTY STRINGS shared static)
|
||||
|
||||
add_subdirectory(extern)
|
||||
|
||||
include(cmake/aurora_core.cmake)
|
||||
include(cmake/aurora_os.cmake)
|
||||
if (AURORA_ENABLE_GX)
|
||||
include(cmake/aurora_gx.cmake)
|
||||
include(cmake/aurora_gd.cmake)
|
||||
endif ()
|
||||
include(cmake/aurora_pad.cmake)
|
||||
include(cmake/aurora_ms.cmake)
|
||||
include(cmake/aurora_si.cmake)
|
||||
include(cmake/aurora_main.cmake)
|
||||
include(cmake/aurora_mtx.cmake)
|
||||
include(cmake/aurora_vi.cmake)
|
||||
if(AURORA_ENABLE_CARD)
|
||||
include(cmake/aurora_card.cmake)
|
||||
endif()
|
||||
if (AURORA_ENABLE_DVD)
|
||||
include(cmake/aurora_dvd.cmake)
|
||||
endif ()
|
||||
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
add_subdirectory(examples)
|
||||
endif ()
|
||||
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND NOT CMAKE_CROSSCOMPILING)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif ()
|
||||
|
||||
option(AURORA_BUILD_METALFX_PRESENTATION_TEST "Build the macOS MetalFX presentation test" OFF)
|
||||
if (AURORA_BUILD_METALFX_PRESENTATION_TEST AND APPLE AND AURORA_ENABLE_GX AND DAWN_ENABLE_METAL AND AURORA_METALFX_FRAMEWORK)
|
||||
add_executable(metalfx_presentation_test tests/metalfx_interop/presentation_test.cpp)
|
||||
target_include_directories(metalfx_presentation_test PRIVATE lib)
|
||||
target_link_libraries(metalfx_presentation_test PRIVATE aurora::core aurora::gx aurora::vi dawn::webgpu_dawn)
|
||||
endif ()
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2022 Luke Street
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,46 +0,0 @@
|
||||
<div align="center">
|
||||
<img src="assets/aurora.png" alt="Logo" width="640">
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
Aurora is a source-level GameCube & Wii compatibility layer intended for use with game decompilation projects.
|
||||
|
||||
Originally developed for use in [Metaforce](https://github.com/AxioDL/metaforce), a Metroid Prime reverse engineering project.
|
||||
It now powers several completed source ports, including [Dusklight](https://github.com/TwilitRealm/dusklight).
|
||||
|
||||
### Features
|
||||
|
||||
- Application layer using SDL3
|
||||
- Runs on Windows, Linux, macOS, iOS, tvOS, Android
|
||||
- GX compatibility layer
|
||||
- Graphics API support: D3D12, Vulkan, Metal
|
||||
- Highly accurate and performant GX implementation
|
||||
- Robust pipeline cache system with "transferable" cache support for releases
|
||||
- Dolphin-compatible texture pack support
|
||||
- Widescreen & resolution scaling support
|
||||
- Custom APIs for offscreen rendering
|
||||
- PAD compatibility layer
|
||||
- Utilizes `SDL_Gamepad` for wide controller support, including GameCube controller adapters
|
||||
- Automatically saves and loads controller bindings and port mappings
|
||||
- Gyro & mouse support
|
||||
- DVD compatibility layer
|
||||
- Utilizes [nod](https://github.com/encounter/nod) to support all GameCube/Wii disc image types, including RVZ
|
||||
- CARD compatibility layer
|
||||
- Full compatibility with Dolphin `.gci` and `.raw` for game saves
|
||||
- [Dear ImGui](https://github.com/ocornut/imgui) built-in for simple debug UIs
|
||||
|
||||
### Graphics
|
||||
|
||||
The GX compatibility layer is built on top of [WebGPU](https://www.w3.org/TR/webgpu/), a cross-platform graphics API
|
||||
abstraction layer. WebGPU allows targeting all major platforms simultaneously with minimal overhead. The WebGPU
|
||||
implementation used is Chromium's [Dawn](https://dawn.googlesource.com/dawn/).
|
||||
|
||||

|
||||
|
||||
### Building
|
||||
|
||||
See [docs/building.md](docs/building.md) for build instructions, CMake integration, and configuration options.
|
||||
|
||||
### License
|
||||
|
||||
Aurora is licensed under the [MIT License](LICENSE).
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB |
@@ -1,57 +0,0 @@
|
||||
include_guard(GLOBAL)
|
||||
|
||||
# aurora_copy_runtime_dlls(<executable_target> [<additional_targets>...])
|
||||
#
|
||||
# POST_BUILD command that copies all TARGET_RUNTIME_DLLS from the given targets
|
||||
# next to the executable, plus any extra DLLs that Dawn loads dynamically
|
||||
# (dxcompiler.dll, dxil.dll).
|
||||
function(aurora_copy_runtime_dlls target)
|
||||
if (NOT WIN32)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# Copy TARGET_RUNTIME_DLLS for each target
|
||||
foreach (_t IN ITEMS ${target} ${ARGN})
|
||||
add_custom_command(TARGET ${target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${_t}> $<TARGET_FILE_DIR:${target}>
|
||||
COMMAND_EXPAND_LISTS
|
||||
VERBATIM
|
||||
)
|
||||
endforeach ()
|
||||
|
||||
# Copy DXC DLLs that Dawn loads via LoadLibrary at runtime
|
||||
if (TARGET dawn::webgpu_dawn)
|
||||
get_target_property(_dawn_loc dawn::webgpu_dawn IMPORTED_LOCATION)
|
||||
if (NOT _dawn_loc)
|
||||
get_target_property(_dawn_loc dawn::webgpu_dawn IMPORTED_LOCATION_RELEASE)
|
||||
endif ()
|
||||
if (_dawn_loc)
|
||||
cmake_path(GET _dawn_loc PARENT_PATH _dawn_bin_dir)
|
||||
foreach (_dll IN ITEMS dxcompiler.dll dxil.dll)
|
||||
if (EXISTS "${_dawn_bin_dir}/${_dll}")
|
||||
add_custom_command(TARGET ${target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_dawn_bin_dir}/${_dll}" $<TARGET_FILE_DIR:${target}>
|
||||
VERBATIM
|
||||
)
|
||||
endif ()
|
||||
endforeach ()
|
||||
endif ()
|
||||
endif ()
|
||||
endfunction()
|
||||
|
||||
# aurora_install_runtime_dlls(<executable_target> <install_destination>)
|
||||
#
|
||||
# INSTALL rule that copies all DLLs already placed next to the built target
|
||||
# into the install destination.
|
||||
function(aurora_install_runtime_dlls target install_destination)
|
||||
if (NOT WIN32)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
install(CODE
|
||||
"file(GLOB _aurora_runtime_dlls \"$<TARGET_FILE_DIR:${target}>/*.dll\")\n\
|
||||
if(_aurora_runtime_dlls)\n\
|
||||
file(INSTALL DESTINATION \"${install_destination}\" TYPE FILE FILES \${_aurora_runtime_dlls})\n\
|
||||
endif()"
|
||||
)
|
||||
endfunction()
|
||||
@@ -1,280 +0,0 @@
|
||||
include_guard(GLOBAL)
|
||||
|
||||
# Resolve Dawn/WebGPU dependency based on AURORA_DAWN_PROVIDER and AURORA_DAWN_LINKAGE.
|
||||
#
|
||||
# After this module runs:
|
||||
# - dawn::webgpu_dawn target is available
|
||||
# - dawn::dawncpp_headers target is available (for tests)
|
||||
# - DAWN_ENABLE_* backend variables are set for the target platform
|
||||
# - AURORA_DAWN_IS_SHARED is set to TRUE/FALSE
|
||||
|
||||
# When using a non-vendored Dawn, we don't get DAWN_ENABLE_* from its build.
|
||||
# Infer from the target platform instead.
|
||||
function(_aurora_dawn_set_platform_backends)
|
||||
if (WIN32)
|
||||
set(DAWN_ENABLE_D3D12 ON CACHE INTERNAL "")
|
||||
# Disable D3D11 because this Aurora fork does not support it.
|
||||
set(DAWN_ENABLE_D3D11 OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_VULKAN ON CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_METAL OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_DESKTOP_GL OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_OPENGLES OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_NULL ON CACHE INTERNAL "")
|
||||
elseif (APPLE)
|
||||
set(DAWN_ENABLE_D3D12 OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_D3D11 OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_VULKAN OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_METAL ON CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_DESKTOP_GL OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_OPENGLES OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_NULL ON CACHE INTERNAL "")
|
||||
else () # Linux / other
|
||||
set(DAWN_ENABLE_D3D12 OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_D3D11 OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_VULKAN ON CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_METAL OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_DESKTOP_GL OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_OPENGLES OFF CACHE INTERNAL "")
|
||||
set(DAWN_ENABLE_NULL ON CACHE INTERNAL "")
|
||||
endif ()
|
||||
endfunction()
|
||||
|
||||
# ── Auto: resolve provider based on platform availability ──
|
||||
set(_aurora_dawn_provider "${AURORA_DAWN_PROVIDER}")
|
||||
if (_aurora_dawn_provider STREQUAL "auto")
|
||||
# Prebuilt Dawn packages available for: windows-{amd64,arm64}, linux-{x86_64,aarch64}, darwin-{arm64,x86_64}
|
||||
set(_has_package FALSE)
|
||||
if (WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|x86_64|ARM64|aarch64)$")
|
||||
set(_has_package TRUE)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|aarch64)$")
|
||||
set(_has_package TRUE)
|
||||
elseif (APPLE AND (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|x86_64)$" OR CMAKE_OSX_ARCHITECTURES MATCHES "^(arm64|x86_64)$"))
|
||||
set(_has_package TRUE)
|
||||
endif ()
|
||||
|
||||
if (_has_package)
|
||||
set(_aurora_dawn_provider "package")
|
||||
else ()
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON)
|
||||
find_package(Dawn QUIET)
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF)
|
||||
if (Dawn_FOUND)
|
||||
set(_aurora_dawn_provider "system")
|
||||
else ()
|
||||
set(_aurora_dawn_provider "vendor")
|
||||
endif ()
|
||||
endif ()
|
||||
set(AURORA_DAWN_PROVIDER "${_aurora_dawn_provider}" CACHE STRING "" FORCE)
|
||||
message(STATUS "aurora: Dawn auto-resolved provider: ${_aurora_dawn_provider}")
|
||||
endif ()
|
||||
|
||||
if (_aurora_dawn_provider STREQUAL "vendor")
|
||||
# ── Vendor: FetchContent build from source ──
|
||||
if (NOT TARGET webgpu_dawn)
|
||||
message(STATUS "aurora: Fetching Dawn (provider=vendor, linkage=${AURORA_DAWN_LINKAGE})")
|
||||
|
||||
if (AURORA_DAWN_LINKAGE STREQUAL "shared")
|
||||
set(DAWN_BUILD_MONOLITHIC_LIBRARY SHARED CACHE INTERNAL
|
||||
"Bundle all dawn components into a single shared library.")
|
||||
else ()
|
||||
set(DAWN_BUILD_MONOLITHIC_LIBRARY STATIC CACHE INTERNAL
|
||||
"Bundle all dawn components into a single static library.")
|
||||
endif ()
|
||||
set(DAWN_BUILD_SAMPLES OFF CACHE INTERNAL "Disable Dawn sample applications")
|
||||
set(DAWN_BUILD_BENCHMARKS OFF CACHE INTERNAL "Disable Dawn benchmarks")
|
||||
set(DAWN_SUPPORTS_GLFW_FOR_WINDOWING OFF CACHE INTERNAL "Disable Dawn GLFW windowing")
|
||||
set(DAWN_ENABLE_DESKTOP_GL OFF CACHE INTERNAL "Enable compilation of the OpenGL backend")
|
||||
set(DAWN_ENABLE_OPENGLES OFF CACHE INTERNAL "Enable compilation of the OpenGL ES backend")
|
||||
set(DAWN_FETCH_DEPENDENCIES ON CACHE INTERNAL
|
||||
"Use fetch_dawn_dependencies.py as an alternative to using depot_tools")
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
set(DAWN_USE_WAYLAND ON CACHE INTERNAL "Enable support for Wayland surface")
|
||||
endif ()
|
||||
set(TINT_BUILD_TESTS OFF CACHE INTERNAL "Build tests")
|
||||
set(TINT_BUILD_CMD_TOOLS OFF CACHE INTERNAL "Build the Tint command line tools")
|
||||
if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY OR CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL$")
|
||||
set(ABSL_MSVC_STATIC_RUNTIME OFF CACHE INTERNAL "Link static runtime libraries")
|
||||
else ()
|
||||
set(ABSL_MSVC_STATIC_RUNTIME ON CACHE INTERNAL "Link static runtime libraries")
|
||||
endif ()
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(dawn
|
||||
URL "https://github.com/google/dawn/archive/refs/tags/${AURORA_DAWN_VERSION}.tar.gz"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(dawn)
|
||||
if (NOT TARGET webgpu_dawn)
|
||||
message(FATAL_ERROR "Failed to make dawn available")
|
||||
endif ()
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing Dawn")
|
||||
endif ()
|
||||
|
||||
if (AURORA_DAWN_LINKAGE STREQUAL "shared")
|
||||
set(AURORA_DAWN_IS_SHARED TRUE PARENT_SCOPE)
|
||||
else ()
|
||||
set(AURORA_DAWN_IS_SHARED FALSE PARENT_SCOPE)
|
||||
endif ()
|
||||
|
||||
elseif (_aurora_dawn_provider STREQUAL "system")
|
||||
# ── System: find_package(Dawn) ──
|
||||
message(STATUS "aurora: Using system Dawn (provider=system)")
|
||||
if (NOT Dawn_FOUND)
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON)
|
||||
find_package(Dawn REQUIRED)
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF)
|
||||
endif ()
|
||||
if (NOT TARGET dawn::webgpu_dawn)
|
||||
message(FATAL_ERROR "find_package(Dawn) succeeded but dawn::webgpu_dawn target not found")
|
||||
endif ()
|
||||
_aurora_dawn_set_platform_backends()
|
||||
|
||||
get_target_property(_dawn_type dawn::webgpu_dawn TYPE)
|
||||
if (_dawn_type STREQUAL "SHARED_LIBRARY")
|
||||
set(AURORA_DAWN_IS_SHARED TRUE PARENT_SCOPE)
|
||||
else ()
|
||||
set(AURORA_DAWN_IS_SHARED FALSE PARENT_SCOPE)
|
||||
endif ()
|
||||
|
||||
elseif (_aurora_dawn_provider STREQUAL "package")
|
||||
# ── Package: download prebuilt Dawn install tree ──
|
||||
if (NOT AURORA_DAWN_PACKAGE_URL)
|
||||
string(TOLOWER "${CMAKE_SYSTEM_NAME}" _dawn_system)
|
||||
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _dawn_arch)
|
||||
if (APPLE AND CMAKE_OSX_ARCHITECTURES)
|
||||
list(GET CMAKE_OSX_ARCHITECTURES 0 _dawn_osx_arch)
|
||||
string(TOLOWER "${_dawn_osx_arch}" _dawn_arch)
|
||||
endif ()
|
||||
if (_dawn_system STREQUAL "windows")
|
||||
if (_dawn_arch STREQUAL "x86_64")
|
||||
set(_dawn_arch "amd64")
|
||||
elseif (_dawn_arch STREQUAL "aarch64")
|
||||
set(_dawn_arch "arm64")
|
||||
endif ()
|
||||
endif ()
|
||||
set(AURORA_DAWN_PACKAGE_URL
|
||||
"https://github.com/theofficialgman/dawn-build/releases/download/${AURORA_DAWN_VERSION}/dawn-${_dawn_system}-${_dawn_arch}.tar.gz")
|
||||
|
||||
# A release asset is mutable: the same tag has already served two different windows-amd64 archives,
|
||||
# and a cached extraction is never re-verified. Pin the digest for the combinations we ship.
|
||||
if (NOT AURORA_DAWN_PACKAGE_URL_HASH AND AURORA_DAWN_VERSION STREQUAL "v20260603.191052")
|
||||
if (_dawn_system STREQUAL "windows" AND _dawn_arch STREQUAL "amd64")
|
||||
set(AURORA_DAWN_PACKAGE_URL_HASH
|
||||
"SHA256=13be9cff8b9b179c42dcd16aeabb6effcc8f0dfdcc14463eda2a5caeda225142")
|
||||
elseif (_dawn_system STREQUAL "windows" AND _dawn_arch STREQUAL "arm64")
|
||||
set(AURORA_DAWN_PACKAGE_URL_HASH
|
||||
"SHA256=bf2d921110f14a1d6553f673c5597988e66c02af5587e4a1fee167937d247734")
|
||||
elseif (_dawn_system STREQUAL "linux" AND _dawn_arch STREQUAL "x86_64")
|
||||
set(AURORA_DAWN_PACKAGE_URL_HASH
|
||||
"SHA256=7adcf241bb2a24ec0c576609f2d67203e0e65db9c5a286ca2bbb6281fa644b35")
|
||||
elseif (_dawn_system STREQUAL "linux" AND _dawn_arch STREQUAL "aarch64")
|
||||
set(AURORA_DAWN_PACKAGE_URL_HASH
|
||||
"SHA256=2415e253d46f91b2d72fc73bf6055fb31b98b67c773dc546e1991b1cf019732f")
|
||||
elseif (_dawn_system STREQUAL "darwin" AND _dawn_arch STREQUAL "arm64")
|
||||
set(AURORA_DAWN_PACKAGE_URL_HASH
|
||||
"SHA256=0a8ea8eb0159fc0ba1083c52155d9376fb173cffe690b400464a6ad8881bb461")
|
||||
elseif (_dawn_system STREQUAL "darwin" AND _dawn_arch STREQUAL "x86_64")
|
||||
set(AURORA_DAWN_PACKAGE_URL_HASH
|
||||
"SHA256=5fe2c7a2a8b4cb82acee4af16779a83ae333c7657b9dc1a5008f5fd1f5ad5f80")
|
||||
elseif (_dawn_system STREQUAL "ios" AND _dawn_arch STREQUAL "arm64")
|
||||
set(AURORA_DAWN_PACKAGE_URL_HASH
|
||||
"SHA256=f97701d26fd1f25bbcc260b4c31736ede134c730c12556029e2470fde967f424")
|
||||
elseif (_dawn_system STREQUAL "android" AND _dawn_arch STREQUAL "aarch64")
|
||||
set(AURORA_DAWN_PACKAGE_URL_HASH
|
||||
"SHA256=0e63e8cbf53551f703f582d1306f4257c0380353f66b53369d96952ce6d9f934")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
message(STATUS "aurora: Fetching prebuilt Dawn package from ${AURORA_DAWN_PACKAGE_URL}")
|
||||
|
||||
set(_dawn_prebuilt_hash_argument "")
|
||||
if (AURORA_DAWN_PACKAGE_URL_HASH)
|
||||
set(_dawn_prebuilt_hash_argument URL_HASH "${AURORA_DAWN_PACKAGE_URL_HASH}")
|
||||
endif ()
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(dawn_prebuilt
|
||||
URL "${AURORA_DAWN_PACKAGE_URL}"
|
||||
${_dawn_prebuilt_hash_argument}
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
)
|
||||
FetchContent_MakeAvailable(dawn_prebuilt)
|
||||
|
||||
# Detect package layout: may be nested in a subdirectory
|
||||
set(_dawn_pkg_dir "${dawn_prebuilt_SOURCE_DIR}")
|
||||
file(GLOB _dawn_subdirs
|
||||
"${dawn_prebuilt_SOURCE_DIR}/dawn-*"
|
||||
"${dawn_prebuilt_SOURCE_DIR}/Dawn-*"
|
||||
)
|
||||
foreach (_sd IN LISTS _dawn_subdirs)
|
||||
if (IS_DIRECTORY "${_sd}")
|
||||
set(_dawn_pkg_dir "${_sd}")
|
||||
break()
|
||||
endif ()
|
||||
endforeach ()
|
||||
if (IS_DIRECTORY "${dawn_prebuilt_SOURCE_DIR}/dawn-install")
|
||||
set(_dawn_pkg_dir "${dawn_prebuilt_SOURCE_DIR}/dawn-install")
|
||||
endif ()
|
||||
|
||||
# Static Dawn packages may link Threads::Threads
|
||||
find_package(Threads QUIET)
|
||||
|
||||
# Find DawnConfig.cmake in the package
|
||||
set(_dawn_cmake_found FALSE)
|
||||
foreach (_cmake_path
|
||||
"${_dawn_pkg_dir}/lib/cmake/Dawn"
|
||||
"${_dawn_pkg_dir}/lib64/cmake/Dawn"
|
||||
"${_dawn_pkg_dir}/cmake/Dawn"
|
||||
"${_dawn_pkg_dir}/cmake"
|
||||
)
|
||||
if (EXISTS "${_cmake_path}/DawnConfig.cmake")
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON)
|
||||
find_package(Dawn REQUIRED CONFIG PATHS "${_cmake_path}" NO_DEFAULT_PATH)
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF)
|
||||
set(_dawn_cmake_found TRUE)
|
||||
break()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
if (NOT _dawn_cmake_found OR NOT TARGET dawn::webgpu_dawn)
|
||||
message(FATAL_ERROR
|
||||
"Dawn package does not contain DawnConfig.cmake.\n"
|
||||
"Searched: ${_dawn_pkg_dir}/{lib,lib64,cmake}/cmake/Dawn/\n"
|
||||
"The package must be a Dawn install tree built with DAWN_ENABLE_INSTALL=ON.")
|
||||
endif ()
|
||||
|
||||
_aurora_dawn_set_platform_backends()
|
||||
|
||||
get_target_property(_dawn_pkg_type dawn::webgpu_dawn TYPE)
|
||||
if (_dawn_pkg_type STREQUAL "SHARED_LIBRARY")
|
||||
set(AURORA_DAWN_IS_SHARED TRUE PARENT_SCOPE)
|
||||
|
||||
else ()
|
||||
set(AURORA_DAWN_IS_SHARED FALSE PARENT_SCOPE)
|
||||
endif ()
|
||||
|
||||
else ()
|
||||
message(FATAL_ERROR "Invalid AURORA_DAWN_PROVIDER: ${AURORA_DAWN_PROVIDER} "
|
||||
"(must be auto, vendor, system, or package)")
|
||||
endif ()
|
||||
|
||||
# Ensure dawn::dawncpp_headers target exists (needed by tests).
|
||||
# When Dawn is vendored, this target is created by Dawn's CMake.
|
||||
# For package/system providers, create it from the same include dirs.
|
||||
if (NOT TARGET dawn::dawncpp_headers)
|
||||
add_library(dawn_dawncpp_headers INTERFACE IMPORTED GLOBAL)
|
||||
get_target_property(_dawn_inc dawn::webgpu_dawn INTERFACE_INCLUDE_DIRECTORIES)
|
||||
if (NOT _dawn_inc)
|
||||
if (TARGET dawn::dawn_public_config)
|
||||
get_target_property(_dawn_inc dawn::dawn_public_config INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif ()
|
||||
endif ()
|
||||
if (_dawn_inc)
|
||||
target_include_directories(dawn_dawncpp_headers INTERFACE ${_dawn_inc})
|
||||
else ()
|
||||
target_link_libraries(dawn_dawncpp_headers INTERFACE dawn::webgpu_dawn)
|
||||
endif ()
|
||||
add_library(dawn::dawncpp_headers ALIAS dawn_dawncpp_headers)
|
||||
endif ()
|
||||
@@ -1,43 +0,0 @@
|
||||
# libusb for SDL3's HIDAPI joystick drivers on Windows.
|
||||
#
|
||||
# The official GameCube adapter (WUP-028) is a vendor-specific USB device, not HID, so SDL3
|
||||
# can only reach it through libusb - which the official SDL3 packages leave out. The vendored
|
||||
# SDL3 build compiles libusb from the pinned upstream release and links it in statically.
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(libusb
|
||||
URL "https://github.com/libusb/libusb/releases/download/v${AURORA_LIBUSB_VERSION}/libusb-${AURORA_LIBUSB_VERSION}.tar.bz2"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
)
|
||||
# Upstream ships no CMakeLists.txt, so this only populates the source tree.
|
||||
FetchContent_MakeAvailable(libusb)
|
||||
|
||||
set(_libusb_root "${libusb_SOURCE_DIR}/libusb")
|
||||
add_library(usb-1.0 STATIC
|
||||
"${_libusb_root}/core.c"
|
||||
"${_libusb_root}/descriptor.c"
|
||||
"${_libusb_root}/hotplug.c"
|
||||
"${_libusb_root}/io.c"
|
||||
"${_libusb_root}/strerror.c"
|
||||
"${_libusb_root}/sync.c"
|
||||
"${_libusb_root}/os/events_windows.c"
|
||||
"${_libusb_root}/os/threads_windows.c"
|
||||
"${_libusb_root}/os/windows_common.c"
|
||||
"${_libusb_root}/os/windows_usbdk.c"
|
||||
"${_libusb_root}/os/windows_winusb.c"
|
||||
)
|
||||
target_include_directories(usb-1.0
|
||||
PUBLIC "${_libusb_root}"
|
||||
PRIVATE "${CMAKE_CURRENT_LIST_DIR}/libusb" "${_libusb_root}/os"
|
||||
)
|
||||
set_target_properties(usb-1.0 PROPERTIES UNITY_BUILD OFF)
|
||||
add_library(LibUSB::LibUSB ALIAS usb-1.0)
|
||||
|
||||
# SDL's FindLibUSB expects an installed copy. Satisfy its presence checks with this target
|
||||
# instead: the alias pre-empts the imported target it would otherwise create, and the link
|
||||
# probe is answered up front because the archive does not exist until build time.
|
||||
set(LibUSB_INCLUDE_PATH "${_libusb_root}" CACHE PATH "" FORCE)
|
||||
set(LibUSB_LIBRARY "usb-1.0" CACHE STRING "" FORCE)
|
||||
set(HAVE_LIBUSB_H 1 CACHE INTERNAL "" FORCE)
|
||||
set(SDL_HIDAPI_LIBUSB ON CACHE BOOL "" FORCE)
|
||||
set(SDL_HIDAPI_LIBUSB_SHARED OFF CACHE BOOL "" FORCE)
|
||||
@@ -1,150 +0,0 @@
|
||||
include_guard(GLOBAL)
|
||||
|
||||
# Resolve nod dependency based on AURORA_NOD_PROVIDER.
|
||||
#
|
||||
# After this module runs:
|
||||
# - nod::nod target is available
|
||||
#
|
||||
# AURORA_NOD_LINKAGE controls shared vs static linkage:
|
||||
# - "shared" (default): prefer nod::nod_shared
|
||||
# - "static": prefer nod::nod_static
|
||||
|
||||
# ── Auto: resolve provider based on platform availability ──
|
||||
set(_aurora_nod_provider "${AURORA_NOD_PROVIDER}")
|
||||
if (_aurora_nod_provider STREQUAL "auto")
|
||||
# Prebuilt nod packages available for: windows-x86_64, linux-x86_64, macos-arm64
|
||||
set(_has_package FALSE)
|
||||
if (WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64)$")
|
||||
set(_has_package TRUE)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64)$")
|
||||
set(_has_package TRUE)
|
||||
elseif (APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64)$")
|
||||
set(_has_package TRUE)
|
||||
endif ()
|
||||
|
||||
if (_has_package)
|
||||
set(_aurora_nod_provider "package")
|
||||
else ()
|
||||
find_package(nod QUIET CONFIG)
|
||||
if (nod_FOUND)
|
||||
set(_aurora_nod_provider "system")
|
||||
else ()
|
||||
set(_aurora_nod_provider "vendor")
|
||||
endif ()
|
||||
endif ()
|
||||
set(AURORA_NOD_PROVIDER "${_aurora_nod_provider}" CACHE STRING "" FORCE)
|
||||
message(STATUS "aurora: nod auto-resolved provider: ${_aurora_nod_provider}")
|
||||
endif ()
|
||||
|
||||
if (_aurora_nod_provider STREQUAL "vendor")
|
||||
# ── Vendor: FetchContent + Corrosion build from source ──
|
||||
if (NOT TARGET nod::nod)
|
||||
message(STATUS "aurora: Building nod (provider=vendor, linkage=${AURORA_NOD_LINKAGE})")
|
||||
|
||||
# Corrosion may default to the host Rust target triple (commonly x86_64 on
|
||||
# Windows). Force Rust to i686 for true Win32 builds so nod and its vendored
|
||||
# compression libraries are built for the same architecture as the C/C++ build.
|
||||
if (WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
set(Rust_CARGO_TARGET "i686-pc-windows-msvc" CACHE STRING "Rust target triple" FORCE)
|
||||
set(Rust_RUSTUP_INSTALL_MISSING_TARGET ON CACHE BOOL "Allow Corrosion to install missing Rust targets" FORCE)
|
||||
message(STATUS "aurora: forcing Rust_CARGO_TARGET=${Rust_CARGO_TARGET} for Win32 nod build")
|
||||
endif ()
|
||||
|
||||
# Control whether nod builds shared, static, or both.
|
||||
# Save/restore BUILD_SHARED_LIBS to avoid leaking into other subdirectories.
|
||||
set(_aurora_nod_saved_bsl "${BUILD_SHARED_LIBS}")
|
||||
if (AURORA_NOD_LINKAGE STREQUAL "static")
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
else ()
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif ()
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(aurora_nod
|
||||
GIT_REPOSITORY "https://github.com/encounter/nod.git"
|
||||
GIT_TAG "${AURORA_NOD_VERSION}"
|
||||
GIT_SHALLOW TRUE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(aurora_nod)
|
||||
set(BUILD_SHARED_LIBS "${_aurora_nod_saved_bsl}")
|
||||
unset(_aurora_nod_saved_bsl)
|
||||
if (NOT TARGET nod::nod)
|
||||
message(FATAL_ERROR "Failed to make nod available")
|
||||
endif ()
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing nod")
|
||||
endif ()
|
||||
|
||||
elseif (_aurora_nod_provider STREQUAL "system")
|
||||
# ── System: find preinstalled nod ──
|
||||
message(STATUS "aurora: Using system nod (provider=system, linkage=${AURORA_NOD_LINKAGE})")
|
||||
|
||||
if (NOT nod_FOUND)
|
||||
set(_aurora_nod_saved_bsl "${BUILD_SHARED_LIBS}")
|
||||
if (AURORA_NOD_LINKAGE STREQUAL "static")
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
else ()
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif ()
|
||||
|
||||
find_package(nod REQUIRED CONFIG)
|
||||
set(BUILD_SHARED_LIBS "${_aurora_nod_saved_bsl}")
|
||||
unset(_aurora_nod_saved_bsl)
|
||||
endif ()
|
||||
if (NOT TARGET nod::nod)
|
||||
message(FATAL_ERROR "find_package(nod) succeeded but nod::nod target not found")
|
||||
endif ()
|
||||
message(STATUS "aurora: Found nod via find_package(nod)")
|
||||
|
||||
elseif (_aurora_nod_provider STREQUAL "package")
|
||||
# ── Package: download prebuilt nod library ──
|
||||
if (NOT AURORA_NOD_PACKAGE_URL)
|
||||
if (WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_nod_platform "windows-x86_64")
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|amd64)$")
|
||||
set(_nod_platform "linux-x86_64")
|
||||
elseif (APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)$")
|
||||
set(_nod_platform "macos-arm64")
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"AURORA_NOD_PROVIDER=package requires AURORA_NOD_PACKAGE_URL on this platform.\n"
|
||||
"Prebuilt packages: https://github.com/encounter/nod/releases")
|
||||
endif ()
|
||||
set(AURORA_NOD_PACKAGE_URL
|
||||
"https://github.com/encounter/nod/releases/download/${AURORA_NOD_VERSION}/libnod-${_nod_platform}.tar.gz")
|
||||
endif ()
|
||||
message(STATUS "aurora: Fetching prebuilt nod package (provider=package, linkage=${AURORA_NOD_LINKAGE})")
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(nod_prebuilt
|
||||
URL "${AURORA_NOD_PACKAGE_URL}"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(nod_prebuilt)
|
||||
|
||||
# The prebuilt package ships a CMake config that creates nod::nod_shared,
|
||||
# nod::nod_static, and a default nod::nod (based on BUILD_SHARED_LIBS).
|
||||
# Set BUILD_SHARED_LIBS so the config selects the right default target.
|
||||
set(_aurora_nod_saved_bsl "${BUILD_SHARED_LIBS}")
|
||||
if (AURORA_NOD_LINKAGE STREQUAL "static")
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
else ()
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif ()
|
||||
find_package(nod REQUIRED CONFIG
|
||||
PATHS "${nod_prebuilt_SOURCE_DIR}"
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
set(BUILD_SHARED_LIBS "${_aurora_nod_saved_bsl}")
|
||||
unset(_aurora_nod_saved_bsl)
|
||||
if (NOT TARGET nod::nod)
|
||||
message(FATAL_ERROR "Prebuilt nod package did not provide nod::nod target")
|
||||
endif ()
|
||||
|
||||
else ()
|
||||
message(FATAL_ERROR "Invalid AURORA_NOD_PROVIDER: ${AURORA_NOD_PROVIDER} "
|
||||
"(must be auto, vendor, system, or package)")
|
||||
endif ()
|
||||
@@ -1,388 +0,0 @@
|
||||
# Source-level fixes applied to the vendored SDL3 tree before it is built.
|
||||
#
|
||||
# Each patch is an exact string replacement, checked and idempotent: a tree that
|
||||
# already carries the fix is left alone, a tree where the anchor text is missing
|
||||
# (a different SDL version) stops the configure with a clear message instead of
|
||||
# silently building without the fix.
|
||||
#
|
||||
# Used two ways:
|
||||
# - included by AuroraSDL3Provider.cmake, which calls aurora_sdl3_apply_patches()
|
||||
# on a pre-provided source tree (FETCHCONTENT_SOURCE_DIR_SDL);
|
||||
# - run as `cmake -DSDL_SOURCE_DIR=<dir> -P AuroraSDL3Patches.cmake` from the
|
||||
# FetchContent PATCH_COMMAND for a freshly extracted tarball.
|
||||
|
||||
function(_aurora_sdl3_replace file description old new)
|
||||
file(READ "${file}" _content)
|
||||
string(FIND "${_content}" "${new}" _already)
|
||||
if (NOT _already EQUAL -1)
|
||||
return()
|
||||
endif ()
|
||||
string(FIND "${_content}" "${old}" _anchor)
|
||||
if (_anchor EQUAL -1)
|
||||
message(FATAL_ERROR "aurora: SDL3 patch '${description}' does not apply to ${file}; "
|
||||
"the vendored SDL version changed, review AuroraSDL3Patches.cmake")
|
||||
endif ()
|
||||
string(REPLACE "${old}" "${new}" _content "${_content}")
|
||||
file(WRITE "${file}" "${_content}")
|
||||
message(STATUS "aurora: SDL3 patch applied: ${description}")
|
||||
endfunction()
|
||||
|
||||
function(aurora_sdl3_apply_patches sdl_source_dir)
|
||||
set(_wii "${sdl_source_dir}/src/joystick/hidapi/SDL_hidapi_wii.c")
|
||||
if (NOT EXISTS "${_wii}")
|
||||
message(FATAL_ERROR "aurora: SDL3 source tree at ${sdl_source_dir} has no SDL_hidapi_wii.c")
|
||||
endif ()
|
||||
set(_rumble "${sdl_source_dir}/src/joystick/hidapi/SDL_hidapi_rumble.c")
|
||||
if (NOT EXISTS "${_rumble}")
|
||||
message(FATAL_ERROR "aurora: SDL3 source tree at ${sdl_source_dir} has no SDL_hidapi_rumble.c")
|
||||
endif ()
|
||||
set(_hidapi "${sdl_source_dir}/src/joystick/hidapi/SDL_hidapijoystick.c")
|
||||
if (NOT EXISTS "${_hidapi}")
|
||||
message(FATAL_ERROR "aurora: SDL3 source tree at ${sdl_source_dir} has no SDL_hidapijoystick.c")
|
||||
endif ()
|
||||
|
||||
# Backport of SDL 71f4af732 (drop once SDL includes it): rumble writes must not hold dev_lock.
|
||||
_aurora_sdl3_replace("${_rumble}" "HIDAPI rumble writes no longer hold the device lock"
|
||||
[==[ if (request) {
|
||||
SDL_LockMutex(request->device->dev_lock);
|
||||
if (request->device->dev) {
|
||||
#ifdef DEBUG_RUMBLE
|
||||
HIDAPI_DumpPacket("Rumble packet: size = %d", request->data, request->size);
|
||||
#endif
|
||||
SDL_hid_write(request->device->dev, request->data, request->size);
|
||||
}
|
||||
SDL_UnlockMutex(request->device->dev_lock);
|
||||
]==]
|
||||
[==[ if (request) {
|
||||
if (request->device->dev) {
|
||||
#ifdef DEBUG_RUMBLE
|
||||
HIDAPI_DumpPacket("Rumble packet: size = %d", request->data, request->size);
|
||||
#endif
|
||||
SDL_hid_write(request->device->dev, request->data, request->size);
|
||||
}
|
||||
]==])
|
||||
|
||||
# Without the lock, closing the handle must wait for in-flight rumble writes.
|
||||
_aurora_sdl3_replace("${_hidapi}" "HIDAPI device close waits for pending rumble"
|
||||
[==[ device->driver->FreeDevice(device);
|
||||
device->driver = NULL;
|
||||
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
]==]
|
||||
[==[ device->driver->FreeDevice(device);
|
||||
device->driver = NULL;
|
||||
|
||||
while (SDL_GetAtomicInt(&device->rumble_pending) > 0) {
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
]==])
|
||||
|
||||
# Wii Remote: rebuild the joystick in place after an extension change.
|
||||
#
|
||||
# When a Nunchuk or Classic Controller is plugged in or pulled out, the driver
|
||||
# flags the joystick as disconnected so it can come back with the new name and
|
||||
# capabilities. But the HID device stays open, and HIDAPI only removes a
|
||||
# joystick-less device once its handle is closed, so nothing ever re-creates
|
||||
# the joystick: the remote is gone for good until the application toggles the
|
||||
# driver hint (which closes and re-opens the Bluetooth HID handle, something
|
||||
# some Windows Bluetooth stacks answer by dropping the link). Instead, when the
|
||||
# device has no joystick, probe the extension again (two bounded attempts, at
|
||||
# most once a second) and connect a new joystick on the still-open handle.
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote in-place reconnect (context field)"
|
||||
[==[ Uint64 m_ulNextMotionPlusCheck;
|
||||
bool m_bDisconnected;
|
||||
]==]
|
||||
[==[ Uint64 m_ulNextMotionPlusCheck;
|
||||
bool m_bDisconnected;
|
||||
Uint64 m_ulNextReconnect; /* WiiCompiled: see HIDAPI_DriverWii_UpdateDevice */
|
||||
]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote in-place reconnect (bounded extension probe)"
|
||||
[==[static EWiiExtensionControllerType ReadExtensionControllerType(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
|
||||
EWiiExtensionControllerType eExtensionControllerType = k_eWiiExtensionControllerType_Unknown;
|
||||
const int MAX_ATTEMPTS = 20;
|
||||
int attempts = 0;
|
||||
]==]
|
||||
[==[static EWiiExtensionControllerType ReadExtensionControllerTypeAttempts(SDL_HIDAPI_Device *device, int MAX_ATTEMPTS)
|
||||
{
|
||||
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
|
||||
EWiiExtensionControllerType eExtensionControllerType = k_eWiiExtensionControllerType_Unknown;
|
||||
int attempts = 0;
|
||||
]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote in-place reconnect (probe wrapper)"
|
||||
[==[static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
]==]
|
||||
[==[static EWiiExtensionControllerType ReadExtensionControllerType(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
return ReadExtensionControllerTypeAttempts(device, 20);
|
||||
}
|
||||
|
||||
static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote in-place reconnect (UpdateDevice)"
|
||||
[==[ if (device->num_joysticks > 0) {
|
||||
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
now = SDL_GetTicks();
|
||||
]==]
|
||||
[==[ if (device->num_joysticks > 0) {
|
||||
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
|
||||
} else {
|
||||
/* WiiCompiled: the joystick was dropped (extension plugged or unplugged,
|
||||
* or a failed read) but the HID device is still open, and the device
|
||||
* list only removes a joystick-less device once its handle is closed.
|
||||
* Rebuild the joystick in place, so an extension change behaves like it
|
||||
* does on the console: the remote never goes away, it just changes
|
||||
* type. If the remote does not answer, keep the device and retry. */
|
||||
now = SDL_GetTicks();
|
||||
if (ctx->m_ulNextReconnect != 0 && now < ctx->m_ulNextReconnect) {
|
||||
return false;
|
||||
}
|
||||
ctx->m_ulNextReconnect = now + 1000;
|
||||
{
|
||||
EWiiExtensionControllerType type = ReadExtensionControllerTypeAttempts(device, 2);
|
||||
if (type == k_eWiiExtensionControllerType_Unknown) {
|
||||
return false;
|
||||
}
|
||||
ctx->m_bDisconnected = false;
|
||||
ctx->m_ulLastInput = now;
|
||||
ctx->m_ulNextReconnect = 0;
|
||||
ctx->m_eExtensionControllerType = type;
|
||||
UpdateDeviceIdentity(device);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Reconnected joystick as %s", device->name);
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
now = SDL_GetTicks();
|
||||
]==])
|
||||
|
||||
# Classic Controller sticks: the stock path stretches each half-range by learned min/max;
|
||||
# this posts WPAD's linear value (raw - first-report centre) * unit, times 64.
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Classic Controller linear sticks (helper)"
|
||||
[==[static void HandleGamepadControllerButtonData(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick, const WiiButtonData *data)
|
||||
{
|
||||
]==]
|
||||
[==[/* WiiCompiled: axis = (raw - centre) * unit * 64, y inverted; see AuroraSDL3Patches.cmake */
|
||||
static void PostClassicStickLinear(Uint64 timestamp, SDL_Joystick *joystick, StickCalibrationData *calibration, Uint8 axis, Uint16 data, int unit)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (!calibration->center) {
|
||||
// Center on first read
|
||||
calibration->center = data;
|
||||
return;
|
||||
}
|
||||
value = ((int)data - (int)calibration->center) * unit * 64;
|
||||
if (axis == SDL_GAMEPAD_AXIS_LEFTY || axis == SDL_GAMEPAD_AXIS_RIGHTY) {
|
||||
value = -value;
|
||||
}
|
||||
SDL_SendJoystickAxis(timestamp, joystick, axis, (Sint16)SDL_clamp(value, SDL_JOYSTICK_AXIS_MIN, SDL_JOYSTICK_AXIS_MAX));
|
||||
}
|
||||
|
||||
static void HandleGamepadControllerButtonData(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick, const WiiButtonData *data)
|
||||
{
|
||||
]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Classic Controller linear sticks (axes)"
|
||||
[==[ PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[0], SDL_GAMEPAD_AXIS_LEFTX, lx);
|
||||
PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[1], SDL_GAMEPAD_AXIS_LEFTY, ly);
|
||||
PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[2], SDL_GAMEPAD_AXIS_RIGHTX, rx);
|
||||
PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[3], SDL_GAMEPAD_AXIS_RIGHTY, ry);
|
||||
]==]
|
||||
[==[ PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[0], SDL_GAMEPAD_AXIS_LEFTX, lx, 16);
|
||||
PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[1], SDL_GAMEPAD_AXIS_LEFTY, ly, 16);
|
||||
PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[2], SDL_GAMEPAD_AXIS_RIGHTX, rx, 32);
|
||||
PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[3], SDL_GAMEPAD_AXIS_RIGHTY, ry, 32);
|
||||
]==])
|
||||
|
||||
# Wii Remote: decode the accelerometer with the factory calibration from the EEPROM.
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (context fields)"
|
||||
[==[ StickCalibrationData m_StickCalibrationData[6];
|
||||
} SDL_DriverWii_Context;
|
||||
]==]
|
||||
[==[ StickCalibrationData m_StickCalibrationData[6];
|
||||
|
||||
float m_fAccelZeroG[3];
|
||||
float m_fAccelPerG[3];
|
||||
} SDL_DriverWii_Context;
|
||||
]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (memory space parameter)"
|
||||
[==[static bool ReadRegister(SDL_DriverWii_Context *ctx, Uint32 address, int size, bool sync)
|
||||
{
|
||||
Uint8 readRequest[7];
|
||||
|
||||
readRequest[0] = k_eWiiOutputReportIDs_ReadMemory;
|
||||
readRequest[1] = (Uint8)(0x04 | (Uint8)ctx->m_bRumbleActive);
|
||||
]==]
|
||||
[==[static bool ReadMemory(SDL_DriverWii_Context *ctx, Uint8 addressSpace, Uint32 address, int size, bool sync);
|
||||
|
||||
static bool ReadRegister(SDL_DriverWii_Context *ctx, Uint32 address, int size, bool sync)
|
||||
{
|
||||
return ReadMemory(ctx, 0x04, address, size, sync);
|
||||
}
|
||||
|
||||
static bool ReadMemory(SDL_DriverWii_Context *ctx, Uint8 addressSpace, Uint32 address, int size, bool sync)
|
||||
{
|
||||
Uint8 readRequest[7];
|
||||
|
||||
readRequest[0] = k_eWiiOutputReportIDs_ReadMemory;
|
||||
readRequest[1] = (Uint8)(addressSpace | (Uint8)ctx->m_bRumbleActive);
|
||||
]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (EEPROM read)"
|
||||
[==[static bool HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
]==]
|
||||
[==[// Nominal decode: zero-g at 0x200, 100 units per g
|
||||
#define WII_ACCEL_NOMINAL_ZERO_G 512.0f
|
||||
#define WII_ACCEL_NOMINAL_PER_G 100.0f
|
||||
|
||||
// EEPROM calibration at 0x16, copy at 0x20: zero-g XYZ, 1 g XYZ, LSBs of both, checksum
|
||||
#define WII_ACCEL_CALIBRATION_SIZE 10
|
||||
#define WII_ADDRESS_SPACE_EEPROM 0x00
|
||||
|
||||
static bool ReadAccelCalibrationBlock(SDL_DriverWii_Context *ctx, Uint8 address, Uint8 *block)
|
||||
{
|
||||
if (!ReadMemory(ctx, WII_ADDRESS_SPACE_EEPROM, address, WII_ACCEL_CALIBRATION_SIZE, true)) {
|
||||
return false;
|
||||
}
|
||||
if (ctx->m_rgucReadBuffer[5] != address ||
|
||||
ctx->m_rgucReadBuffer[3] != ((WII_ACCEL_CALIBRATION_SIZE - 1) << 4)) {
|
||||
SDL_SetError("Unexpected EEPROM read response");
|
||||
return false;
|
||||
}
|
||||
SDL_memcpy(block, ctx->m_rgucReadBuffer + 6, WII_ACCEL_CALIBRATION_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseAccelCalibration(SDL_DriverWii_Context *ctx, const Uint8 *block)
|
||||
{
|
||||
int zero[3];
|
||||
int perG[3];
|
||||
Uint8 checksum = 0x55;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < WII_ACCEL_CALIBRATION_SIZE - 1; ++i) {
|
||||
checksum = (Uint8)(checksum + block[i]);
|
||||
}
|
||||
if (checksum != block[WII_ACCEL_CALIBRATION_SIZE - 1]) {
|
||||
SDL_SetError("Bad checksum");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
int shift = 4 - 2 * i;
|
||||
int oneG = (block[4 + i] << 2) | ((block[7] >> shift) & 0x03);
|
||||
|
||||
zero[i] = (block[i] << 2) | ((block[3] >> shift) & 0x03);
|
||||
perG[i] = oneG - zero[i];
|
||||
|
||||
// Sanity limits around the nominal values
|
||||
if (zero[i] < 384 || zero[i] > 640 || perG[i] < 60 || perG[i] > 160) {
|
||||
SDL_SetError("Implausible values");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
ctx->m_fAccelZeroG[i] = (float)zero[i];
|
||||
ctx->m_fAccelPerG[i] = (float)perG[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ReadAccelCalibration(SDL_DriverWii_Context *ctx)
|
||||
{
|
||||
static const Uint8 addresses[] = { 0x16, 0x20 };
|
||||
Uint8 block[WII_ACCEL_CALIBRATION_SIZE];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDL_arraysize(addresses); ++i) {
|
||||
if (ReadAccelCalibrationBlock(ctx, addresses[i], block) &&
|
||||
ParseAccelCalibration(ctx, block)) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Accelerometer calibration from EEPROM 0x%02X: zero %d/%d/%d, %d/%d/%d units per g",
|
||||
addresses[i],
|
||||
(int)ctx->m_fAccelZeroG[0], (int)ctx->m_fAccelZeroG[1], (int)ctx->m_fAccelZeroG[2],
|
||||
(int)ctx->m_fAccelPerG[0], (int)ctx->m_fAccelPerG[1], (int)ctx->m_fAccelPerG[2]);
|
||||
return;
|
||||
}
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Accelerometer calibration at EEPROM 0x%02X unusable: %s", addresses[i], SDL_GetError());
|
||||
}
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Using nominal accelerometer calibration");
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (nominal defaults)"
|
||||
[==[ ctx->device = device;
|
||||
device->context = ctx;
|
||||
]==]
|
||||
[==[ ctx->device = device;
|
||||
device->context = ctx;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
ctx->m_fAccelZeroG[i] = WII_ACCEL_NOMINAL_ZERO_G;
|
||||
ctx->m_fAccelPerG[i] = WII_ACCEL_NOMINAL_PER_G;
|
||||
}
|
||||
]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (read at init)"
|
||||
[==[ ctx->m_eExtensionControllerType = ReadExtensionControllerType(device);
|
||||
]==]
|
||||
[==[ ctx->m_eExtensionControllerType = ReadExtensionControllerType(device);
|
||||
ReadAccelCalibration(ctx);
|
||||
]==])
|
||||
# Reports without accelerometer bytes (status, memory) decoded as garbage.
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer guard"
|
||||
[==[ }
|
||||
|
||||
x = ((data->rgucAccelerometer[0] << 2) | ((data->rgucBaseButtons[0] >> 5) & 0x03))]==]
|
||||
[==[ }
|
||||
|
||||
if (!data->hasAccelerometer) {
|
||||
return;
|
||||
}
|
||||
|
||||
x = ((data->rgucAccelerometer[0] << 2) | ((data->rgucBaseButtons[0] >> 5) & 0x03))]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (nominal constant)"
|
||||
[==[const WiiButtonData *data)
|
||||
{
|
||||
const float ACCEL_RES_PER_G = 100.0f;
|
||||
Sint16 x, y, z;
|
||||
]==]
|
||||
[==[const WiiButtonData *data)
|
||||
{
|
||||
Sint16 x, y, z;
|
||||
]==])
|
||||
_aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (decode)"
|
||||
[==[ x = ((data->rgucAccelerometer[0] << 2) | ((data->rgucBaseButtons[0] >> 5) & 0x03)) - 0x200;
|
||||
y = ((data->rgucAccelerometer[1] << 2) | ((data->rgucBaseButtons[1] >> 4) & 0x02)) - 0x200;
|
||||
z = ((data->rgucAccelerometer[2] << 2) | ((data->rgucBaseButtons[1] >> 5) & 0x02)) - 0x200;
|
||||
|
||||
values[0] = -((float)x / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY;
|
||||
values[1] = ((float)z / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY;
|
||||
values[2] = ((float)y / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY;
|
||||
]==]
|
||||
[==[ x = ((data->rgucAccelerometer[0] << 2) | ((data->rgucBaseButtons[0] >> 5) & 0x03));
|
||||
y = ((data->rgucAccelerometer[1] << 2) | ((data->rgucBaseButtons[1] >> 4) & 0x02));
|
||||
z = ((data->rgucAccelerometer[2] << 2) | ((data->rgucBaseButtons[1] >> 5) & 0x02));
|
||||
if (x == 0 && y == 0 && z == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
values[0] = -(((float)x - ctx->m_fAccelZeroG[0]) / ctx->m_fAccelPerG[0]) * SDL_STANDARD_GRAVITY;
|
||||
values[1] = (((float)z - ctx->m_fAccelZeroG[2]) / ctx->m_fAccelPerG[2]) * SDL_STANDARD_GRAVITY;
|
||||
values[2] = (((float)y - ctx->m_fAccelZeroG[1]) / ctx->m_fAccelPerG[1]) * SDL_STANDARD_GRAVITY;
|
||||
]==])
|
||||
endfunction()
|
||||
|
||||
# Script mode (FetchContent PATCH_COMMAND).
|
||||
if (CMAKE_SCRIPT_MODE_FILE AND DEFINED SDL_SOURCE_DIR)
|
||||
aurora_sdl3_apply_patches("${SDL_SOURCE_DIR}")
|
||||
endif ()
|
||||
@@ -1,164 +0,0 @@
|
||||
include_guard(GLOBAL)
|
||||
|
||||
# Resolve SDL3 dependency based on AURORA_SDL3_PROVIDER and AURORA_SDL3_LINKAGE.
|
||||
#
|
||||
# After this module runs, the variable AURORA_SDL3_TARGET is set to the
|
||||
# appropriate target name for use in target_link_libraries() calls.
|
||||
|
||||
# Select the SDL3 target matching the requested linkage.
|
||||
function(_aurora_sdl3_select_target)
|
||||
if (AURORA_SDL3_LINKAGE STREQUAL "static")
|
||||
if (TARGET SDL3::SDL3-static)
|
||||
set(AURORA_SDL3_TARGET SDL3::SDL3-static CACHE INTERNAL "")
|
||||
message(STATUS "aurora: Using static SDL3")
|
||||
return()
|
||||
elseif (TARGET SDL3::SDL3)
|
||||
message(WARNING "aurora: Static SDL3 requested but only shared is available")
|
||||
set(AURORA_SDL3_TARGET SDL3::SDL3 CACHE INTERNAL "")
|
||||
message(STATUS "aurora: Using shared SDL3")
|
||||
return()
|
||||
endif ()
|
||||
else ()
|
||||
if (TARGET SDL3::SDL3)
|
||||
set(AURORA_SDL3_TARGET SDL3::SDL3 CACHE INTERNAL "")
|
||||
message(STATUS "aurora: Using shared SDL3")
|
||||
return()
|
||||
elseif (TARGET SDL3::SDL3-static)
|
||||
message(WARNING "aurora: Shared SDL3 requested but only static is available")
|
||||
set(AURORA_SDL3_TARGET SDL3::SDL3-static CACHE INTERNAL "")
|
||||
message(STATUS "aurora: Using static SDL3")
|
||||
return()
|
||||
endif ()
|
||||
endif ()
|
||||
message(FATAL_ERROR "No SDL3 target found (looked for SDL3::SDL3 and SDL3::SDL3-static)")
|
||||
endfunction()
|
||||
|
||||
# ── Auto: resolve provider based on platform availability ──
|
||||
set(_aurora_sdl3_provider "${AURORA_SDL3_PROVIDER}")
|
||||
if (_aurora_sdl3_provider STREQUAL "auto")
|
||||
# Prebuilt SDL3 packages are available for Windows (MSVC and MinGW)
|
||||
if (WIN32)
|
||||
set(_aurora_sdl3_provider "package")
|
||||
else ()
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON)
|
||||
# Aurora uses APIs from the SDL version pinned by AURORA_SDL3_VERSION.
|
||||
# Do not silently select an older system package and fail later while
|
||||
# compiling its headers.
|
||||
find_package(SDL3 ${AURORA_SDL3_VERSION} QUIET)
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF)
|
||||
if (SDL3_FOUND)
|
||||
set(_aurora_sdl3_provider "system")
|
||||
else ()
|
||||
set(_aurora_sdl3_provider "vendor")
|
||||
endif ()
|
||||
endif ()
|
||||
set(AURORA_SDL3_PROVIDER "${_aurora_sdl3_provider}" CACHE STRING "" FORCE)
|
||||
message(STATUS "aurora: SDL3 auto-resolved provider: ${_aurora_sdl3_provider}")
|
||||
endif ()
|
||||
|
||||
if (_aurora_sdl3_provider STREQUAL "system")
|
||||
# ── System: find_package(SDL3) ──
|
||||
message(STATUS "aurora: Using system SDL3 (provider=system)")
|
||||
if (NOT SDL3_FOUND)
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON)
|
||||
find_package(SDL3 ${AURORA_SDL3_VERSION} REQUIRED)
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF)
|
||||
endif ()
|
||||
_aurora_sdl3_select_target()
|
||||
|
||||
elseif (_aurora_sdl3_provider STREQUAL "package")
|
||||
# ── Package: download custom build or official SDL3 development package ──
|
||||
if (NOT AURORA_SDL3_PACKAGE_URL)
|
||||
if (MINGW)
|
||||
# WIN32 is also true for MinGW. Select the matching GNU-ABI package
|
||||
# before considering Visual C++ packages.
|
||||
set(AURORA_SDL3_PACKAGE_URL
|
||||
"https://github.com/libsdl-org/SDL/releases/download/release-${AURORA_SDL3_VERSION}/SDL3-devel-${AURORA_SDL3_VERSION}-mingw.tar.gz")
|
||||
elseif (WIN32)
|
||||
# We have custom builds of SDL3 for Win32 x86/AMD64 with libusb support included
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|x86)$")
|
||||
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _sdl3_arch)
|
||||
set(AURORA_SDL3_PACKAGE_URL
|
||||
"https://github.com/encounter/sdl3-build/releases/download/v${AURORA_SDL3_VERSION}/SDL3-windows-${_sdl3_arch}.tar.gz")
|
||||
else ()
|
||||
set(AURORA_SDL3_PACKAGE_URL
|
||||
"https://github.com/libsdl-org/SDL/releases/download/release-${AURORA_SDL3_VERSION}/SDL3-devel-${AURORA_SDL3_VERSION}-VC.zip")
|
||||
endif ()
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"AURORA_SDL3_PROVIDER=package requires AURORA_SDL3_PACKAGE_URL on non-Windows platforms.\n"
|
||||
"Official SDL3 packages: https://github.com/libsdl-org/SDL/releases")
|
||||
endif ()
|
||||
endif ()
|
||||
message(STATUS "aurora: Fetching prebuilt SDL3 package from ${AURORA_SDL3_PACKAGE_URL}")
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(sdl3_prebuilt
|
||||
URL "${AURORA_SDL3_PACKAGE_URL}"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
)
|
||||
FetchContent_MakeAvailable(sdl3_prebuilt)
|
||||
|
||||
set(_sdl3_search_paths
|
||||
"${sdl3_prebuilt_SOURCE_DIR}/cmake"
|
||||
"${sdl3_prebuilt_SOURCE_DIR}/lib/cmake/SDL3"
|
||||
"${sdl3_prebuilt_SOURCE_DIR}"
|
||||
)
|
||||
file(GLOB _sdl3_subdirs "${sdl3_prebuilt_SOURCE_DIR}/SDL3-*")
|
||||
foreach (_sd IN LISTS _sdl3_subdirs)
|
||||
list(APPEND _sdl3_search_paths
|
||||
"${_sd}/cmake"
|
||||
"${_sd}/lib/cmake/SDL3"
|
||||
"${_sd}"
|
||||
)
|
||||
endforeach ()
|
||||
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON)
|
||||
find_package(SDL3 REQUIRED CONFIG PATHS ${_sdl3_search_paths} NO_DEFAULT_PATH)
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF)
|
||||
_aurora_sdl3_select_target()
|
||||
|
||||
elseif (_aurora_sdl3_provider STREQUAL "vendor")
|
||||
# ── Vendor: FetchContent build from source ──
|
||||
if (NOT TARGET SDL3-static AND NOT TARGET SDL3-shared)
|
||||
message(STATUS "aurora: Fetching SDL3 (provider=vendor)")
|
||||
|
||||
if (AURORA_SDL3_LINKAGE STREQUAL "static")
|
||||
set(SDL_STATIC ON CACHE BOOL "Build SDL3 static library" FORCE)
|
||||
set(SDL_SHARED OFF CACHE BOOL "Build SDL3 shared library" FORCE)
|
||||
else ()
|
||||
set(SDL_STATIC OFF CACHE BOOL "Build SDL3 static library" FORCE)
|
||||
set(SDL_SHARED ON CACHE BOOL "Build SDL3 shared library" FORCE)
|
||||
endif ()
|
||||
if (WIN32)
|
||||
set(SDL_LIBC ON CACHE BOOL "Use the system C library" FORCE)
|
||||
if (AURORA_SDL3_LIBUSB)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/AuroraLibUSB.cmake")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
include(FetchContent)
|
||||
# Source fixes for the vendored SDL (see AuroraSDL3Patches.cmake). A freshly
|
||||
# downloaded tarball is patched by the PATCH_COMMAND; a tree handed in through
|
||||
# FETCHCONTENT_SOURCE_DIR_SDL skips the download steps, so patch it here.
|
||||
set(_aurora_sdl3_patches "${CMAKE_CURRENT_LIST_DIR}/AuroraSDL3Patches.cmake")
|
||||
include("${_aurora_sdl3_patches}")
|
||||
if (DEFINED FETCHCONTENT_SOURCE_DIR_SDL AND EXISTS "${FETCHCONTENT_SOURCE_DIR_SDL}")
|
||||
aurora_sdl3_apply_patches("${FETCHCONTENT_SOURCE_DIR_SDL}")
|
||||
endif ()
|
||||
FetchContent_Declare(SDL
|
||||
URL "https://github.com/libsdl-org/SDL/releases/download/release-${AURORA_SDL3_VERSION}/SDL3-${AURORA_SDL3_VERSION}.tar.gz"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
PATCH_COMMAND "${CMAKE_COMMAND}" -DSDL_SOURCE_DIR=<SOURCE_DIR> -P "${_aurora_sdl3_patches}"
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(SDL)
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing SDL3")
|
||||
endif ()
|
||||
_aurora_sdl3_select_target()
|
||||
|
||||
else ()
|
||||
message(FATAL_ERROR "Invalid AURORA_SDL3_PROVIDER: ${AURORA_SDL3_PROVIDER} "
|
||||
"(must be auto, vendor, system, or package)")
|
||||
endif ()
|
||||
@@ -1,17 +0,0 @@
|
||||
add_library(aurora_card STATIC
|
||||
lib/card/BlockAllocationTable.cpp
|
||||
lib/card/CardRawFile.cpp
|
||||
lib/card/CardGciFolder.cpp
|
||||
lib/card/Directory.cpp
|
||||
lib/card/DolphinCardPath.cpp
|
||||
lib/card/File.cpp
|
||||
lib/card/FileIO.cpp
|
||||
lib/card/SRAM.cpp
|
||||
lib/card/Util.cpp
|
||||
lib/dolphin/card.cpp
|
||||
)
|
||||
add_library(aurora::card ALIAS aurora_card)
|
||||
set_target_properties(aurora_card PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_link_libraries(aurora_card PUBLIC aurora::core)
|
||||
target_include_directories(aurora_card PRIVATE include)
|
||||
@@ -1,77 +0,0 @@
|
||||
add_library(aurora_core STATIC
|
||||
lib/aurora.cpp
|
||||
lib/input.cpp
|
||||
lib/window.cpp
|
||||
lib/logging.cpp
|
||||
lib/system_info.cpp
|
||||
lib/system_info.hpp
|
||||
)
|
||||
add_library(aurora::core ALIAS aurora_core)
|
||||
set_target_properties(aurora_core PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_compile_definitions(aurora_core PUBLIC AURORA TARGET_PC)
|
||||
target_include_directories(aurora_core PUBLIC include)
|
||||
target_link_libraries(aurora_core PUBLIC fmt::fmt ${AURORA_SDL3_TARGET} xxhash)
|
||||
target_link_libraries(aurora_core PRIVATE absl::btree absl::flat_hash_map sqlite3 TracyClient)
|
||||
if (AURORA_ENABLE_GX AND AURORA_CACHE_USE_ZSTD)
|
||||
target_compile_definitions(aurora_core PRIVATE AURORA_CACHE_USE_ZSTD)
|
||||
target_link_libraries(aurora_core PRIVATE libzstd_static)
|
||||
endif ()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Windows)
|
||||
# stuff for fetching system info.
|
||||
target_link_libraries(aurora_core PRIVATE ntdll dxgi advapi32 user32)
|
||||
elseif (APPLE)
|
||||
target_sources(aurora_core PRIVATE lib/system_info_mac.mm)
|
||||
endif ()
|
||||
|
||||
if (AURORA_ENABLE_GX)
|
||||
target_sources(aurora_core PRIVATE lib/imgui.cpp)
|
||||
target_link_libraries(aurora_core PUBLIC imgui)
|
||||
endif ()
|
||||
|
||||
if (AURORA_ENABLE_GX)
|
||||
target_compile_definitions(aurora_core PUBLIC AURORA_ENABLE_GX WEBGPU_DAWN)
|
||||
target_sources(aurora_core PRIVATE lib/webgpu/gpu.cpp lib/webgpu/gpu_cache.cpp lib/dawn/BackendBinding.cpp)
|
||||
target_link_libraries(aurora_core PRIVATE dawn::webgpu_dawn)
|
||||
if (APPLE AND DAWN_ENABLE_METAL)
|
||||
find_library(AURORA_METALFX_FRAMEWORK MetalFX)
|
||||
endif ()
|
||||
if (APPLE AND DAWN_ENABLE_METAL AND AURORA_METALFX_FRAMEWORK)
|
||||
target_sources(aurora_core PRIVATE lib/webgpu/metalfx.mm)
|
||||
set_source_files_properties(lib/webgpu/metalfx.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
target_link_options(aurora_core PUBLIC "LINKER:-weak_framework,MetalFX")
|
||||
target_link_libraries(aurora_core PRIVATE "-framework IOSurface")
|
||||
else ()
|
||||
target_sources(aurora_core PRIVATE lib/webgpu/metalfx_stub.cpp)
|
||||
endif ()
|
||||
if (DAWN_ENABLE_VULKAN)
|
||||
target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_VULKAN)
|
||||
endif ()
|
||||
if (DAWN_ENABLE_METAL)
|
||||
target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_METAL)
|
||||
target_sources(aurora_core PRIVATE lib/dawn/MetalBinding.mm)
|
||||
set_source_files_properties(lib/dawn/MetalBinding.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
target_link_options(aurora_core PUBLIC
|
||||
"LINKER:-weak_framework,Metal"
|
||||
"LINKER:-U,_OBJC_CLASS_$_MTLLogStateDescriptor")
|
||||
endif ()
|
||||
if (DAWN_ENABLE_D3D11)
|
||||
target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_D3D11)
|
||||
endif ()
|
||||
if (DAWN_ENABLE_D3D12)
|
||||
target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_D3D12)
|
||||
endif ()
|
||||
if (DAWN_ENABLE_DESKTOP_GL OR DAWN_ENABLE_OPENGLES)
|
||||
target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_OPENGL)
|
||||
if (DAWN_ENABLE_DESKTOP_GL)
|
||||
target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_DESKTOP_GL)
|
||||
endif ()
|
||||
if (DAWN_ENABLE_OPENGLES)
|
||||
target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_OPENGLES)
|
||||
endif ()
|
||||
endif ()
|
||||
if (DAWN_ENABLE_NULL)
|
||||
target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_NULL)
|
||||
endif ()
|
||||
endif ()
|
||||
@@ -1,10 +0,0 @@
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/AuroraNodProvider.cmake)
|
||||
|
||||
add_library(aurora_dvd STATIC lib/dolphin/dvd/dvd.cpp)
|
||||
add_library(aurora::dvd ALIAS aurora_dvd)
|
||||
set_target_properties(aurora_dvd PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_compile_definitions(aurora_dvd PUBLIC AURORA TARGET_PC)
|
||||
target_include_directories(aurora_dvd PUBLIC include)
|
||||
target_link_libraries(aurora_dvd PUBLIC nod::nod ${AURORA_SDL3_TARGET})
|
||||
target_link_libraries(aurora_dvd PRIVATE fmt::fmt)
|
||||
@@ -1,16 +0,0 @@
|
||||
add_library(aurora_gd STATIC
|
||||
lib/dolphin/gd/GDBase.cpp
|
||||
lib/dolphin/gd/GDGeometry.cpp
|
||||
lib/dolphin/gd/GDIndirect.cpp
|
||||
lib/dolphin/gd/GDLight.cpp
|
||||
lib/dolphin/gd/GDPixel.cpp
|
||||
lib/dolphin/gd/GDTev.cpp
|
||||
lib/dolphin/gd/GDTexture.cpp
|
||||
lib/dolphin/gd/GDTransform.cpp
|
||||
lib/dolphin/gd/gd.hpp
|
||||
lib/dolphin/gd/GDAurora.cpp
|
||||
)
|
||||
add_library(aurora::gd ALIAS aurora_gd)
|
||||
set_target_properties(aurora_gd PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_link_libraries(aurora_gd PUBLIC aurora::gx)
|
||||
@@ -1,47 +0,0 @@
|
||||
add_library(aurora_gx STATIC
|
||||
lib/gfx/clear.cpp
|
||||
lib/gfx/common.cpp
|
||||
lib/gfx/depth_peek.cpp
|
||||
lib/gfx/efb_ram_copy.cpp
|
||||
lib/gfx/efb_ram_encoder.cpp
|
||||
lib/gfx/pipeline_cache.cpp
|
||||
lib/gfx/dds_io.cpp
|
||||
lib/gfx/tex_copy_conv.cpp
|
||||
lib/gfx/tex_palette_conv.cpp
|
||||
lib/gfx/texture.cpp
|
||||
lib/gfx/texture_convert.cpp
|
||||
lib/gfx/texture_replacement.cpp
|
||||
lib/gx/command_processor.cpp
|
||||
lib/gx/fifo.cpp
|
||||
lib/gx/frame_interpolation.cpp
|
||||
lib/gx/gx.cpp
|
||||
lib/gx/pipeline.cpp
|
||||
lib/gx/shader.cpp
|
||||
lib/gx/shader_info.cpp
|
||||
lib/dolphin/gx/GXBump.cpp
|
||||
lib/dolphin/gx/GXCull.cpp
|
||||
lib/dolphin/gx/GXCpu2Efb.cpp
|
||||
lib/dolphin/gx/GXDispList.cpp
|
||||
lib/dolphin/gx/GXDraw.cpp
|
||||
lib/dolphin/gx/GXExtra.cpp
|
||||
lib/dolphin/gx/GXFifo.cpp
|
||||
lib/dolphin/gx/GXFrameBuffer.cpp
|
||||
lib/dolphin/gx/GXGeometry.cpp
|
||||
lib/dolphin/gx/GXGet.cpp
|
||||
lib/dolphin/gx/GXLighting.cpp
|
||||
lib/dolphin/gx/GXManage.cpp
|
||||
lib/dolphin/gx/GXPixel.cpp
|
||||
lib/dolphin/gx/GXTev.cpp
|
||||
lib/dolphin/gx/GXTexture.cpp
|
||||
lib/dolphin/gx/GXTransform.cpp
|
||||
lib/dolphin/gx/GXVert.cpp
|
||||
lib/dolphin/gx/GXAurora.cpp
|
||||
lib/gfx/png_io.cpp
|
||||
lib/gfx/png_io.hpp
|
||||
)
|
||||
add_library(aurora::gx ALIAS aurora_gx)
|
||||
set_target_properties(aurora_gx PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_link_libraries(aurora_gx PUBLIC aurora::core xxhash)
|
||||
target_link_libraries(aurora_gx PRIVATE absl::btree absl::flat_hash_map dawn::webgpu_dawn sqlite3 TracyClient PNG::PNG)
|
||||
target_compile_definitions(aurora_gx PRIVATE WEBGPU_DAWN)
|
||||
@@ -1,6 +0,0 @@
|
||||
add_library(aurora_main STATIC lib/main.cpp)
|
||||
add_library(aurora::main ALIAS aurora_main)
|
||||
set_target_properties(aurora_main PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_include_directories(aurora_main PUBLIC include)
|
||||
target_link_libraries(aurora_main PUBLIC ${AURORA_SDL3_TARGET})
|
||||
@@ -1,7 +0,0 @@
|
||||
add_library(aurora_ms STATIC lib/dolphin/ms/mouse.cpp)
|
||||
add_library(aurora::ms ALIAS aurora_ms)
|
||||
set_target_properties(aurora_ms PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_include_directories(aurora_ms PUBLIC include)
|
||||
target_link_libraries(aurora_ms PUBLIC aurora::core)
|
||||
target_link_libraries(aurora_ms PRIVATE absl::flat_hash_map)
|
||||
@@ -1,12 +0,0 @@
|
||||
add_library(aurora_mtx STATIC
|
||||
lib/dolphin/mtx/mtx.c
|
||||
lib/dolphin/mtx/mtxstack.c
|
||||
lib/dolphin/mtx/mtxvec.c
|
||||
lib/dolphin/mtx/mtx44.c
|
||||
lib/dolphin/mtx/vec.c
|
||||
lib/dolphin/mtx/quat.c
|
||||
)
|
||||
add_library(aurora::mtx ALIAS aurora_mtx)
|
||||
set_target_properties(aurora_mtx PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_include_directories(aurora_mtx PUBLIC include)
|
||||
@@ -1,14 +0,0 @@
|
||||
add_library(aurora_os STATIC lib/dolphin/os/OSInit.cpp
|
||||
lib/dolphin/os/OSMemory.cpp
|
||||
lib/dolphin/os/internal.hpp
|
||||
lib/dolphin/os/OSBootInfo.cpp
|
||||
lib/dolphin/os/OSTime.cpp
|
||||
lib/dolphin/os/OSArena.cpp
|
||||
lib/dolphin/os/OSAlloc.cpp
|
||||
lib/dolphin/os/OSAddress.cpp
|
||||
lib/dolphin/AR.cpp)
|
||||
add_library(aurora::os ALIAS aurora_os)
|
||||
set_target_properties(aurora_os PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_include_directories(aurora_os PUBLIC include)
|
||||
target_link_libraries(aurora_os PRIVATE aurora::core)
|
||||
@@ -1,7 +0,0 @@
|
||||
add_library(aurora_pad STATIC lib/dolphin/pad/pad.cpp)
|
||||
add_library(aurora::pad ALIAS aurora_pad)
|
||||
set_target_properties(aurora_pad PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_include_directories(aurora_pad PUBLIC include)
|
||||
target_link_libraries(aurora_pad PUBLIC aurora::core aurora::si)
|
||||
target_link_libraries(aurora_pad PRIVATE absl::flat_hash_map)
|
||||
@@ -1,7 +0,0 @@
|
||||
add_library(aurora_si STATIC lib/dolphin/si/si.cpp)
|
||||
add_library(aurora::si ALIAS aurora_si)
|
||||
set_target_properties(aurora_si PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_include_directories(aurora_si PUBLIC include)
|
||||
target_link_libraries(aurora_si PUBLIC aurora::core)
|
||||
target_link_libraries(aurora_si PRIVATE absl::flat_hash_map)
|
||||
@@ -1,7 +0,0 @@
|
||||
add_library(aurora_vi STATIC
|
||||
lib/dolphin/vi/vi.cpp
|
||||
)
|
||||
add_library(aurora::vi ALIAS aurora_vi)
|
||||
set_target_properties(aurora_vi PROPERTIES FOLDER "aurora")
|
||||
|
||||
target_link_libraries(aurora_vi PUBLIC aurora::core)
|
||||
@@ -1,8 +0,0 @@
|
||||
/* libusb build configuration for the Windows backend (MinGW/Clang). */
|
||||
#pragma once
|
||||
|
||||
#define PLATFORM_WINDOWS 1
|
||||
#define ENABLE_LOGGING 1
|
||||
#define DEFAULT_VISIBILITY
|
||||
#define HAVE_STRUCT_TIMESPEC 1
|
||||
#define PRINTF_FORMAT(a, b) __attribute__((__format__(__printf__, a, b)))
|
||||
@@ -1,55 +0,0 @@
|
||||
# Building
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- CMake 3.25 or later
|
||||
- A C++20 compatible compiler (Clang, GCC, or MSVC)
|
||||
- Git (for cloning)
|
||||
|
||||
## Building the Examples
|
||||
|
||||
To build Aurora's included examples:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/encounter/aurora.git
|
||||
cd aurora
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
cmake --build . --target simple
|
||||
```
|
||||
|
||||
The `simple` example demonstrates a minimal Aurora application with a blue screen. The built executable will be in `build/examples/simple`.
|
||||
|
||||
## Using Aurora in Your Project
|
||||
|
||||
Aurora is designed to be integrated as a library in GameCube/Wii decompilation projects.
|
||||
|
||||
**CMakeLists.txt example:**
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
project(your_game)
|
||||
|
||||
# Add Aurora as a subdirectory
|
||||
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
|
||||
|
||||
# Create your executable
|
||||
add_executable(your_game src/main.c)
|
||||
|
||||
# Link against Aurora components
|
||||
target_link_libraries(your_game PRIVATE
|
||||
aurora::core
|
||||
aurora::gx
|
||||
aurora::main
|
||||
aurora::vi
|
||||
)
|
||||
```
|
||||
|
||||
See [examples/simple.c](../examples/simple.c) for a minimal application template.
|
||||
|
||||
## CMake Options
|
||||
|
||||
- `AURORA_ENABLE_GX` (default: ON) - Enable GX implementation and WebGPU renderer
|
||||
- `AURORA_ENABLE_DVD` (default: OFF) - Enable DVD implementation backed by nod
|
||||
- `AURORA_ENABLE_CARD` (default: ON) - Enable CARD implementation based on kabufuda
|
||||
- `AURORA_CACHE_USE_ZSTD` (default: ON) - Compress WebGPU cache entries with zstd
|
||||
@@ -1,4 +0,0 @@
|
||||
if (AURORA_ENABLE_GX)
|
||||
add_executable(simple simple.c)
|
||||
target_link_libraries(simple PRIVATE aurora::core aurora::gx aurora::main aurora::vi)
|
||||
endif ()
|
||||
@@ -1,90 +0,0 @@
|
||||
#include <aurora/aurora.h>
|
||||
#include <aurora/event.h>
|
||||
#include <aurora/main.h>
|
||||
#include <dolphin/gx.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void log_callback(AuroraLogLevel level, const char* module, const char* message, unsigned int len) {
|
||||
const char* levelStr;
|
||||
FILE* out = stdout;
|
||||
switch (level) {
|
||||
case LOG_DEBUG:
|
||||
levelStr = "DEBUG";
|
||||
break;
|
||||
case LOG_INFO:
|
||||
levelStr = "INFO";
|
||||
break;
|
||||
case LOG_WARNING:
|
||||
levelStr = "WARNING";
|
||||
break;
|
||||
case LOG_ERROR:
|
||||
levelStr = "ERROR";
|
||||
out = stderr;
|
||||
break;
|
||||
case LOG_FATAL:
|
||||
levelStr = "FATAL";
|
||||
out = stderr;
|
||||
break;
|
||||
}
|
||||
fprintf(out, "[%s: %s;%s]\n", levelStr, module, message);
|
||||
if (level == LOG_FATAL) {
|
||||
fflush(out);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void draw() {
|
||||
GXSetCopyClear(
|
||||
(GXColor){
|
||||
.r = 0,
|
||||
.g = 0,
|
||||
.b = 100,
|
||||
.a = 255,
|
||||
},
|
||||
GX_MAX_Z24);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
const AuroraConfig config = {
|
||||
.appName = "Demo",
|
||||
.logCallback = &log_callback,
|
||||
};
|
||||
AuroraInfo initInfo = aurora_initialize(argc, argv, &config);
|
||||
|
||||
bool exiting = false;
|
||||
bool paused = false;
|
||||
while (!exiting) {
|
||||
const AuroraEvent* event = aurora_update();
|
||||
while (event != NULL && event->type != AURORA_NONE) {
|
||||
switch (event->type) {
|
||||
case AURORA_EXIT:
|
||||
exiting = true;
|
||||
break;
|
||||
case AURORA_PAUSED:
|
||||
paused = true;
|
||||
break;
|
||||
case AURORA_UNPAUSED:
|
||||
paused = false;
|
||||
break;
|
||||
case AURORA_WINDOW_RESIZED:
|
||||
initInfo.windowSize = event->windowSize;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
++event;
|
||||
}
|
||||
if (exiting || paused || !aurora_begin_frame()) {
|
||||
continue;
|
||||
}
|
||||
draw();
|
||||
aurora_end_frame();
|
||||
}
|
||||
|
||||
aurora_shutdown();
|
||||
return 0;
|
||||
}
|
||||
Vendored
-360
@@ -1,360 +0,0 @@
|
||||
include(FetchContent)
|
||||
|
||||
# Don't build tests for third party dependencies
|
||||
set(BUILD_TESTING OFF CACHE INTERNAL "Build tests")
|
||||
set(SKIP_INSTALL_ALL ON)
|
||||
if (NOT DEFINED BUILD_SHARED_LIBS)
|
||||
set(_USE_SHARED ON)
|
||||
else ()
|
||||
set(_USE_SHARED OFF)
|
||||
endif ()
|
||||
|
||||
function(aurora_find_package_global)
|
||||
set(_PREV_FIND_PACKAGE_TARGETS_GLOBAL ${CMAKE_FIND_PACKAGE_TARGETS_GLOBAL})
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON)
|
||||
find_package(${ARGV})
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ${_PREV_FIND_PACKAGE_TARGETS_GLOBAL})
|
||||
endfunction()
|
||||
|
||||
# A macOS build for another architecture must not discover Homebrew packages
|
||||
# built for its physical host. CMAKE_CROSSCOMPILING is not sufficient here:
|
||||
# Apple Clang can target another architecture through CMAKE_OSX_ARCHITECTURES
|
||||
# without CMake considering the configure a cross-build.
|
||||
set(_AURORA_EXCLUDE_HOST_HOMEBREW FALSE)
|
||||
if (APPLE AND CMAKE_OSX_ARCHITECTURES)
|
||||
list(LENGTH CMAKE_OSX_ARCHITECTURES _AURORA_OSX_ARCH_COUNT)
|
||||
if (_AURORA_OSX_ARCH_COUNT EQUAL 1)
|
||||
list(GET CMAKE_OSX_ARCHITECTURES 0 _AURORA_TARGET_ARCH)
|
||||
string(TOLOWER "${_AURORA_TARGET_ARCH}" _AURORA_TARGET_ARCH)
|
||||
# hw.optional.arm64 identifies Apple Silicon even when CMake itself runs
|
||||
# through Rosetta, where CMAKE_HOST_SYSTEM_PROCESSOR reports x86_64.
|
||||
execute_process(
|
||||
COMMAND /usr/sbin/sysctl -n hw.optional.arm64
|
||||
RESULT_VARIABLE _AURORA_ARM64_PROBE_RESULT
|
||||
OUTPUT_VARIABLE _AURORA_ARM64_PROBE
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if (_AURORA_ARM64_PROBE_RESULT EQUAL 0 AND _AURORA_ARM64_PROBE STREQUAL "1")
|
||||
set(_AURORA_HOST_ARCH arm64)
|
||||
else ()
|
||||
execute_process(
|
||||
COMMAND /usr/bin/uname -m
|
||||
OUTPUT_VARIABLE _AURORA_HOST_ARCH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(TOLOWER "${_AURORA_HOST_ARCH}" _AURORA_HOST_ARCH)
|
||||
endif ()
|
||||
if (_AURORA_TARGET_ARCH STREQUAL "x86_64" AND _AURORA_HOST_ARCH MATCHES "^(arm64|aarch64)$")
|
||||
list(APPEND CMAKE_IGNORE_PREFIX_PATH "/opt/homebrew")
|
||||
set(_AURORA_EXCLUDE_HOST_HOMEBREW TRUE)
|
||||
elseif (_AURORA_TARGET_ARCH MATCHES "^(arm64|aarch64)$" AND _AURORA_HOST_ARCH MATCHES "^(x86_64|amd64)$")
|
||||
list(APPEND CMAKE_IGNORE_PREFIX_PATH "/usr/local")
|
||||
set(_AURORA_EXCLUDE_HOST_HOMEBREW TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (_AURORA_EXCLUDE_HOST_HOMEBREW)
|
||||
list(REMOVE_DUPLICATES CMAKE_IGNORE_PREFIX_PATH)
|
||||
message(STATUS "aurora: cross-architecture macOS build; ignoring host Homebrew prefixes")
|
||||
endif ()
|
||||
|
||||
if (AURORA_ENABLE_GX)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/AuroraDawnProvider.cmake)
|
||||
endif ()
|
||||
|
||||
# SDL's pkg-config probe can bypass CMake's prefix exclusion. macOS does not
|
||||
# need libusb for the supported SDL input paths, so keep that host-only library
|
||||
# out of a cross-architecture configure.
|
||||
if (_AURORA_EXCLUDE_HOST_HOMEBREW)
|
||||
set(SDL_HIDAPI_LIBUSB OFF CACHE BOOL "" FORCE)
|
||||
set(SDL_HIDAPI_LIBUSB_SHARED OFF CACHE BOOL "" FORCE)
|
||||
endif ()
|
||||
|
||||
# Abseil is needed for core libraries. It normally comes via Dawn's vendor build.
|
||||
# Otherwise prefer a system package and only fetch it as a last resort.
|
||||
if (NOT TARGET absl::flat_hash_map OR NOT TARGET absl::btree)
|
||||
aurora_find_package_global(absl CONFIG QUIET GLOBAL)
|
||||
endif ()
|
||||
|
||||
if (TARGET absl::flat_hash_map AND TARGET absl::btree)
|
||||
message(STATUS "aurora: Using system/existing abseil")
|
||||
else ()
|
||||
message(STATUS "aurora: Fetching abseil-cpp (standalone)")
|
||||
if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY OR CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL$")
|
||||
set(ABSL_MSVC_STATIC_RUNTIME OFF CACHE INTERNAL "Link static runtime libraries")
|
||||
else()
|
||||
set(ABSL_MSVC_STATIC_RUNTIME ON CACHE INTERNAL "Link static runtime libraries")
|
||||
endif()
|
||||
set(ABSL_PROPAGATE_CXX_STD ON)
|
||||
FetchContent_Declare(abseil-cpp
|
||||
URL https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(abseil-cpp)
|
||||
if (NOT TARGET absl::flat_hash_map OR NOT TARGET absl::btree)
|
||||
message(FATAL_ERROR "Failed to make abseil-cpp available")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/AuroraSDL3Provider.cmake)
|
||||
|
||||
if (NOT TARGET xxhash)
|
||||
message(STATUS "aurora: Fetching xxhash")
|
||||
FetchContent_Declare(xxhash
|
||||
URL https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz
|
||||
URL_HASH SHA256=5738270935e7c3d38a79b3adf7c9692566ce7895a25f67de43ad52ab504acd32
|
||||
SOURCE_SUBDIR build/cmake
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
set(XXHASH_BUILD_XXHSUM OFF CACHE INTERNAL "Build the xxhsum binary")
|
||||
# xxhash uses CMAKE_DEPENDENT_OPTION(BUILD_SHARED_LIBS ...) which writes
|
||||
# a sticky CACHE INTERNAL entry on reconfigure. Undo it afterward.
|
||||
set(_aurora_xxhash_saved_bsl "${BUILD_SHARED_LIBS}")
|
||||
FetchContent_MakeAvailable(xxhash)
|
||||
unset(BUILD_SHARED_LIBS CACHE)
|
||||
set(BUILD_SHARED_LIBS "${_aurora_xxhash_saved_bsl}")
|
||||
unset(_aurora_xxhash_saved_bsl)
|
||||
if (NOT TARGET xxhash)
|
||||
message(FATAL_ERROR "Failed to make xxhash available")
|
||||
endif ()
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing xxhash")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET fmt)
|
||||
message(STATUS "aurora: Fetching fmt")
|
||||
FetchContent_Declare(fmt
|
||||
URL https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz
|
||||
URL_HASH SHA256=ac366b7b4c2e9f0dde63a59b3feb5ee59b67974b14ee5dc9ea8ad78aa2c1ee1e
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(fmt)
|
||||
if (NOT TARGET fmt)
|
||||
message(FATAL_ERROR "Failed to make fmt available")
|
||||
endif ()
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing fmt")
|
||||
endif ()
|
||||
|
||||
# fmt 11.1 drops its libc++ transitive includes but still calls malloc/free without <cstdlib>.
|
||||
# Force the missing header for fmt and its consumers until the pinned release is updated.
|
||||
if (MINGW AND TARGET fmt)
|
||||
target_compile_options(fmt PUBLIC
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-include>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:cstdlib>)
|
||||
endif ()
|
||||
|
||||
if (AURORA_ENABLE_GX)
|
||||
if (NOT TARGET ZLIB::ZLIB)
|
||||
aurora_find_package_global(ZLIB QUIET)
|
||||
endif ()
|
||||
if (NOT TARGET ZLIB::ZLIB)
|
||||
message(STATUS "aurora: Fetching zlib")
|
||||
set(_AURORA_ZLIB_SHARED ${_USE_SHARED})
|
||||
# ClangCL injects Clang's C headers into the MSVC resource compiler path, and zlib's DLL version
|
||||
# resource then hits syntax rc.exe cannot parse. Use the resource-free static target here.
|
||||
if (MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(_AURORA_ZLIB_SHARED OFF)
|
||||
endif ()
|
||||
set(ZLIB_BUILD_SHARED ${_AURORA_ZLIB_SHARED} CACHE BOOL "Enable building zlib shared library" FORCE)
|
||||
set(ZLIB_BUILD_TESTING OFF CACHE BOOL "Enable Zlib Examples as tests" FORCE)
|
||||
set(ZLIB_INSTALL OFF CACHE BOOL "Enable installation of zlib" FORCE)
|
||||
FetchContent_Declare(
|
||||
ZLIB
|
||||
URL https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz
|
||||
URL_HASH SHA256=bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(ZLIB)
|
||||
if (NOT TARGET ZLIB::ZLIB AND TARGET ZLIB::ZLIBSTATIC)
|
||||
add_library(ZLIB::ZLIB ALIAS zlibstatic)
|
||||
endif ()
|
||||
if (NOT TARGET ZLIB::ZLIB)
|
||||
message(FATAL_ERROR "Failed to make zlib available")
|
||||
endif ()
|
||||
# libpng calls find_package(ZLIB) even when zlib was already provided by FetchContent.
|
||||
file(WRITE "${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/ZLIBConfig.cmake"
|
||||
"set(ZLIB_FOUND TRUE)\n"
|
||||
"set(ZLIB_INCLUDE_DIR \"${zlib_SOURCE_DIR}\")\n"
|
||||
"set(ZLIB_INCLUDE_DIRS \"${zlib_BINARY_DIR};${zlib_SOURCE_DIR}\")\n"
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET PNG::PNG)
|
||||
if (TARGET png_shared AND _USE_SHARED)
|
||||
add_library(PNG::PNG ALIAS png_shared)
|
||||
elseif (TARGET png_static)
|
||||
add_library(PNG::PNG ALIAS png_static)
|
||||
else ()
|
||||
aurora_find_package_global(PNG QUIET)
|
||||
endif ()
|
||||
endif ()
|
||||
if (NOT TARGET PNG::PNG)
|
||||
message(STATUS "aurora: Fetching libpng")
|
||||
set(PNG_SHARED ${_USE_SHARED} CACHE BOOL "Build libpng as a shared library" FORCE)
|
||||
set(PNG_TESTS OFF CACHE BOOL "Build the libpng tests" FORCE)
|
||||
set(PNG_TOOLS OFF CACHE BOOL "Build the libpng tools" FORCE)
|
||||
FetchContent_Declare(
|
||||
PNG
|
||||
URL https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.58.tar.gz
|
||||
URL_HASH SHA256=A9D4DF463D36A6E5F9C29BD6F4967312D17E996C1854F3511F833924EB1993CF
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(PNG)
|
||||
if (TARGET png_shared AND _USE_SHARED)
|
||||
add_library(PNG::PNG ALIAS png_shared)
|
||||
elseif (TARGET png_static)
|
||||
add_library(PNG::PNG ALIAS png_static)
|
||||
else ()
|
||||
message(FATAL_ERROR "Failed to make libpng available")
|
||||
endif ()
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing libpng")
|
||||
endif ()
|
||||
|
||||
aurora_find_package_global(Freetype QUIET)
|
||||
if (NOT TARGET Freetype::Freetype)
|
||||
message(STATUS "aurora: Fetching Freetype")
|
||||
set(FT_DISABLE_BROTLI ON CACHE BOOL "" FORCE)
|
||||
set(FT_DISABLE_HARFBUZZ ON CACHE BOOL "" FORCE)
|
||||
set(FT_DISABLE_PNG ON CACHE BOOL "" FORCE)
|
||||
FetchContent_Declare(Freetype
|
||||
URL https://files.twilitrealm.dev/freetype-2.14.3.tar.gz
|
||||
URL_HASH SHA256=e61b31ab26358b946e767ed7eb7f4bb2e507da1cfefeb7a8861ace7fd5c899a1
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(Freetype)
|
||||
add_library(Freetype::Freetype ALIAS freetype)
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing Freetype")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET imgui)
|
||||
message(STATUS "aurora: Fetching imgui")
|
||||
FetchContent_Declare(imgui
|
||||
URL https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz
|
||||
URL_HASH SHA256=466fdef9b18de15f0bb6e288e3d00ffa3d82200ec458ce5e4f724a161d9528a5
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(imgui)
|
||||
|
||||
add_library(imgui STATIC
|
||||
${imgui_SOURCE_DIR}/imgui.cpp
|
||||
${imgui_SOURCE_DIR}/imgui_demo.cpp
|
||||
${imgui_SOURCE_DIR}/imgui_draw.cpp
|
||||
${imgui_SOURCE_DIR}/imgui_tables.cpp
|
||||
${imgui_SOURCE_DIR}/imgui_widgets.cpp
|
||||
${imgui_SOURCE_DIR}/misc/cpp/imgui_stdlib.cpp
|
||||
)
|
||||
target_include_directories(imgui PUBLIC ${imgui_SOURCE_DIR})
|
||||
|
||||
add_library(imgui_backends STATIC
|
||||
${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.cpp
|
||||
${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.cpp
|
||||
${imgui_SOURCE_DIR}/backends/imgui_impl_wgpu.cpp
|
||||
)
|
||||
target_compile_definitions(imgui_backends PRIVATE IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
|
||||
target_link_libraries(imgui_backends PRIVATE imgui ${AURORA_SDL3_TARGET} dawn::webgpu_dawn)
|
||||
target_link_libraries(imgui PUBLIC imgui_backends)
|
||||
|
||||
if (TARGET Freetype::Freetype)
|
||||
target_sources(imgui PRIVATE ${imgui_SOURCE_DIR}/misc/freetype/imgui_freetype.cpp)
|
||||
target_compile_definitions(imgui PUBLIC IMGUI_ENABLE_FREETYPE)
|
||||
target_link_libraries(imgui PRIVATE Freetype::Freetype)
|
||||
endif ()
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing imgui")
|
||||
endif ()
|
||||
|
||||
if (TARGET imgui)
|
||||
target_include_directories(imgui PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||
target_compile_definitions(imgui PUBLIC IMGUI_USER_CONFIG="aurora/imgui_config.h")
|
||||
target_sources(imgui PRIVATE ${PROJECT_SOURCE_DIR}/lib/imgui_config.cpp)
|
||||
target_link_libraries(imgui PRIVATE ${AURORA_SDL3_TARGET})
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET sqlite3)
|
||||
message(STATUS "aurora: Fetching sqlite3")
|
||||
FetchContent_Declare(sqlite3
|
||||
URL https://sqlite.org/2026/sqlite-amalgamation-3510300.zip
|
||||
URL_HASH SHA256=acb1e6f5d832484bf6d32b681e858c38add8b2acdfd42ac5df24b8afb46552b4
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(sqlite3)
|
||||
|
||||
add_library(sqlite3 STATIC ${sqlite3_SOURCE_DIR}/sqlite3.c)
|
||||
target_include_directories(sqlite3 PUBLIC ${sqlite3_SOURCE_DIR})
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing sqlite3")
|
||||
endif ()
|
||||
|
||||
if (AURORA_CACHE_USE_ZSTD)
|
||||
if (NOT TARGET libzstd_static)
|
||||
message(STATUS "aurora: Fetching zstd")
|
||||
set(ZSTD_BUILD_STATIC ON)
|
||||
set(ZSTD_BUILD_SHARED OFF)
|
||||
set(ZSTD_BUILD_PROGRAMS OFF CACHE BOOL "BUILD PROGRAMS" FORCE)
|
||||
set(ZSTD_BUILD_TESTS OFF CACHE BOOL "BUILD TESTS" FORCE)
|
||||
|
||||
if (WIN32 AND CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(C_FLAG_WALL TRUE CACHE INTERNAL "")
|
||||
set(CXX_FLAG_WALL TRUE CACHE INTERNAL "")
|
||||
set(C_FLAG_WEXTRA TRUE CACHE INTERNAL "")
|
||||
set(CXX_FLAG_WEXTRA TRUE CACHE INTERNAL "")
|
||||
set(C_FLAG_WUNDEF TRUE CACHE INTERNAL "")
|
||||
set(CXX_FLAG_WUNDEF TRUE CACHE INTERNAL "")
|
||||
set(C_FLAG_WSHADOW TRUE CACHE INTERNAL "")
|
||||
set(CXX_FLAG_WSHADOW TRUE CACHE INTERNAL "")
|
||||
set(C_FLAG_WCAST_ALIGN TRUE CACHE INTERNAL "")
|
||||
set(CXX_FLAG_WCAST_ALIGN TRUE CACHE INTERNAL "")
|
||||
set(C_FLAG_WCAST_QUAL TRUE CACHE INTERNAL "")
|
||||
set(CXX_FLAG_WCAST_QUAL TRUE CACHE INTERNAL "")
|
||||
set(C_FLAG_WSTRICT_PROTOTYPES TRUE CACHE INTERNAL "")
|
||||
set(LD_FLAG_WL_Z_NOEXECSTACK FALSE CACHE INTERNAL "")
|
||||
set(C_FLAG_QUNUSED_ARGUMENTS TRUE CACHE INTERNAL "")
|
||||
set(CXX_FLAG_QUNUSED_ARGUMENTS TRUE CACHE INTERNAL "")
|
||||
set(C_FLAG_WA_NOEXECSTACK TRUE CACHE INTERNAL "")
|
||||
set(CXX_FLAG_WA_NOEXECSTACK TRUE CACHE INTERNAL "")
|
||||
endif()
|
||||
|
||||
FetchContent_Declare(zstd
|
||||
URL https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz
|
||||
URL_HASH SHA256=eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
SOURCE_SUBDIR build/cmake
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(zstd)
|
||||
else ()
|
||||
message(STATUS "aurora: Using existing zstd")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET TracyClient)
|
||||
message(STATUS "aurora: Fetching Tracy")
|
||||
|
||||
# Default to off, users can enable the cache variable if they want to use it.
|
||||
set(TRACY_ENABLE OFF CACHE BOOL "Enable Tracy profiling")
|
||||
|
||||
FetchContent_Declare(
|
||||
tracy
|
||||
URL https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz
|
||||
URL_HASH SHA256=24d342b5127d7f659dc3cf94f24347b348cc736f25b17a691fd7f69541937658
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(tracy)
|
||||
|
||||
if (NOT TARGET TracyClient)
|
||||
message(FATAL_ERROR "Failed to make TracyClient available")
|
||||
endif ()
|
||||
endif ()
|
||||
@@ -1,195 +0,0 @@
|
||||
#ifndef AURORA_AURORA_H
|
||||
#define AURORA_AURORA_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
extern "C" {
|
||||
#else
|
||||
#include "stdbool.h"
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
BACKEND_AUTO,
|
||||
BACKEND_D3D11,
|
||||
BACKEND_D3D12,
|
||||
BACKEND_METAL,
|
||||
BACKEND_VULKAN,
|
||||
BACKEND_OPENGL,
|
||||
BACKEND_OPENGLES,
|
||||
BACKEND_WEBGPU,
|
||||
BACKEND_NULL,
|
||||
} AuroraBackend;
|
||||
|
||||
typedef enum {
|
||||
LOG_DEBUG,
|
||||
LOG_INFO,
|
||||
LOG_WARNING,
|
||||
LOG_ERROR,
|
||||
LOG_FATAL,
|
||||
} AuroraLogLevel;
|
||||
|
||||
typedef enum {
|
||||
AURORA_DISPLAY_MODE_WINDOWED,
|
||||
AURORA_DISPLAY_MODE_BORDERLESS,
|
||||
AURORA_DISPLAY_MODE_EXCLUSIVE,
|
||||
} AuroraDisplayMode;
|
||||
|
||||
typedef struct {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} AuroraWindowPos;
|
||||
|
||||
typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
|
||||
/**
|
||||
* Width of the main GX framebuffer.
|
||||
*/
|
||||
uint32_t fb_width;
|
||||
|
||||
/**
|
||||
* Height of the main GX framebuffer.
|
||||
*/
|
||||
uint32_t fb_height;
|
||||
|
||||
/**
|
||||
* The size of the framebuffer used to present to the operating system.
|
||||
* May differ from fb_width if Aurora is instructed to force an aspect ratio or resolution configuration.
|
||||
*/
|
||||
uint32_t native_fb_width;
|
||||
|
||||
/**
|
||||
* The size of the framebuffer used to present to the operating system.
|
||||
* May differ from fb_height if Aurora is instructed to force an aspect ratio or resolution configuration.
|
||||
*/
|
||||
uint32_t native_fb_height;
|
||||
float scale;
|
||||
} AuroraWindowSize;
|
||||
|
||||
typedef struct SDL_Window SDL_Window;
|
||||
typedef struct AuroraEvent AuroraEvent;
|
||||
|
||||
typedef void (*AuroraLogCallback)(AuroraLogLevel level, const char* module, const char* message, unsigned int len);
|
||||
typedef void (*AuroraImGuiInitCallback)(const AuroraWindowSize* size);
|
||||
|
||||
typedef struct {
|
||||
const char* appName;
|
||||
const char* userPath;
|
||||
const char* cachePath;
|
||||
// Read-only application resources. Defaults to SDL_GetBasePath(), which is
|
||||
// where release builds place initial_pipeline_cache.db.
|
||||
const char* resourcesPath;
|
||||
AuroraBackend desiredBackend;
|
||||
uint32_t msaa;
|
||||
uint16_t maxTextureAnisotropy;
|
||||
// No vsync knob exists: the swapchain is always configured for a
|
||||
// non-blocking present mode (Immediate, else Mailbox). See best_present_mode.
|
||||
bool startFullscreen;
|
||||
bool allowJoystickBackgroundEvents;
|
||||
bool pauseOnFocusLost;
|
||||
bool allowTextureReplacements;
|
||||
bool allowTextureDumps;
|
||||
bool disableCopyFilter;
|
||||
// When false, Aurora centers the first window. When true, windowPosX/Y are restored verbatim,
|
||||
// including negative coordinates on monitors left of or above the primary display.
|
||||
bool hasWindowPosition;
|
||||
int32_t windowPosX;
|
||||
int32_t windowPosY;
|
||||
uint32_t windowWidth;
|
||||
uint32_t windowHeight;
|
||||
void* iconRGBA8;
|
||||
uint32_t iconWidth;
|
||||
uint32_t iconHeight;
|
||||
AuroraLogCallback logCallback;
|
||||
AuroraLogLevel logLevel;
|
||||
AuroraImGuiInitCallback imGuiInitCallback;
|
||||
|
||||
/*
|
||||
* The size of the GameCube's main memory, or MEM1 on the Wii.
|
||||
* Note that it will not be allocated at the exact 0x80000000 address, as that cannot be guaranteed.
|
||||
* This can be set to 0 to disable allocating this region.
|
||||
*/
|
||||
uint32_t mem1Size;
|
||||
|
||||
/*
|
||||
* The size of the GameCube's ARAM, or MEM2 on the Wii.
|
||||
* This can be set to 0 to disable allocating this region.
|
||||
*/
|
||||
uint32_t mem2Size;
|
||||
|
||||
// Optional directory for the portable GX pipeline database. When null, the
|
||||
// database is stored in cachePath with Dawn's machine-specific cache.
|
||||
const char* pipelineCachePath;
|
||||
} AuroraConfig;
|
||||
|
||||
typedef enum {
|
||||
AURORA_INITIALIZATION_SUCCESS = 0,
|
||||
AURORA_INITIALIZATION_GRAPHICS_UNAVAILABLE = 1,
|
||||
} AuroraInitializationStatus;
|
||||
|
||||
typedef struct {
|
||||
AuroraBackend backend;
|
||||
const char* userPath;
|
||||
const char* cachePath;
|
||||
SDL_Window* window;
|
||||
AuroraWindowSize windowSize;
|
||||
AuroraInitializationStatus initializationStatus;
|
||||
// On failure, owned by SDL on the calling thread. Copy before another SDL call.
|
||||
const char* initializationError;
|
||||
} AuroraInfo;
|
||||
|
||||
AuroraInfo aurora_initialize(int argc, char* argv[], const AuroraConfig* config);
|
||||
void aurora_shutdown();
|
||||
const AuroraEvent* aurora_update();
|
||||
bool aurora_begin_frame();
|
||||
void aurora_end_frame();
|
||||
typedef void (*AuroraFrameWorkerWaitCallback)();
|
||||
// Called from the producer thread at bounded intervals while Aurora waits for
|
||||
// the asynchronous frame worker. The callback must not enter Aurora.
|
||||
void aurora_set_frame_worker_wait_callback(AuroraFrameWorkerWaitCallback callback);
|
||||
void aurora_wait_for_frame_worker();
|
||||
bool aurora_wait_for_frame_worker_for(uint32_t timeoutMicros);
|
||||
// Absolute schedule for the next sealed frame, on steady_clock: baseNanos anchors the group and
|
||||
// intervalNanos is the period, so slot k of N+1 fires at base + k*interval/(N+1). Zeros clear it.
|
||||
void aurora_set_present_schedule(uint64_t baseNanos, uint64_t intervalNanos);
|
||||
// Reports whether the frame about to be sealed met its display boundary. Interpolation sizes its
|
||||
// slot group from this, backing off after misses. Only paced presents may report.
|
||||
void aurora_report_producer_paced(bool paced);
|
||||
void aurora_request_frame_capture(uint32_t frame, const char* outputPath);
|
||||
bool aurora_flush_efb_copies_to_ram();
|
||||
bool aurora_flush_efb_copy_to_ram(void* dest);
|
||||
|
||||
void aurora_set_log_level(AuroraLogLevel level);
|
||||
void aurora_set_pause_on_focus_lost(bool value);
|
||||
void aurora_set_background_input(bool value);
|
||||
void aurora_set_display_mode(AuroraDisplayMode mode);
|
||||
AuroraDisplayMode aurora_get_display_mode();
|
||||
|
||||
typedef enum {
|
||||
AURORA_METALFX_DISABLED,
|
||||
AURORA_METALFX_UNSUPPORTED,
|
||||
AURORA_METALFX_NOT_UPSCALING,
|
||||
AURORA_METALFX_ACTIVE,
|
||||
AURORA_METALFX_ERROR,
|
||||
} AuroraMetalFXStatus;
|
||||
|
||||
// Changes are consumed at the next sealed frame boundary. MetalFX only applies
|
||||
// when both source dimensions are smaller than the aspect-fitted output.
|
||||
void aurora_set_metalfx_spatial(bool enabled);
|
||||
bool aurora_get_metalfx_spatial();
|
||||
bool aurora_is_metalfx_spatial_supported();
|
||||
AuroraMetalFXStatus aurora_get_metalfx_status();
|
||||
|
||||
AuroraBackend aurora_get_backend();
|
||||
const AuroraBackend* aurora_get_available_backends(size_t* count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef AURORA_DVD_H
|
||||
#define AURORA_DVD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <dolphin/types.h>
|
||||
|
||||
/**
|
||||
* Open a GC/Wii disc image for use by the DVD API.
|
||||
* Must be called before DVDInit().
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
bool aurora_dvd_open(const char* disc_path);
|
||||
|
||||
/**
|
||||
* Close the disc image and free all resources.
|
||||
*/
|
||||
void aurora_dvd_close(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,44 +0,0 @@
|
||||
#ifndef AURORA_EVENT_H
|
||||
#define AURORA_EVENT_H
|
||||
|
||||
#include "aurora.h"
|
||||
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3/SDL_joystick.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstdint>
|
||||
|
||||
extern "C" {
|
||||
#else
|
||||
#include "stdint.h"
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
AURORA_NONE,
|
||||
AURORA_EXIT,
|
||||
AURORA_SDL_EVENT,
|
||||
AURORA_WINDOW_MOVED,
|
||||
AURORA_WINDOW_RESIZED,
|
||||
AURORA_CONTROLLER_ADDED,
|
||||
AURORA_CONTROLLER_REMOVED,
|
||||
AURORA_PAUSED,
|
||||
AURORA_UNPAUSED,
|
||||
AURORA_DISPLAY_SCALE_CHANGED,
|
||||
} AuroraEventType;
|
||||
|
||||
struct AuroraEvent {
|
||||
AuroraEventType type;
|
||||
union {
|
||||
SDL_Event sdl;
|
||||
AuroraWindowPos windowPos;
|
||||
AuroraWindowSize windowSize;
|
||||
SDL_JoystickID controller;
|
||||
};
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,97 +0,0 @@
|
||||
#ifndef AURORA_GFX_H
|
||||
#define AURORA_GFX_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
extern "C" {
|
||||
#else
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define AURORA_GFX_DEBUG_GROUPS
|
||||
#endif
|
||||
|
||||
void aurora_push_debug_group(const char* label);
|
||||
void aurora_pop_debug_group();
|
||||
|
||||
typedef struct {
|
||||
uint32_t queuedPipelines;
|
||||
uint32_t createdPipelines;
|
||||
uint32_t drawCallCount;
|
||||
uint32_t mergedDrawCallCount;
|
||||
uint32_t lastVertSize;
|
||||
uint32_t lastUniformSize;
|
||||
uint32_t lastIndexSize;
|
||||
uint32_t lastStorageSize;
|
||||
uint32_t lastTextureUploadSize;
|
||||
uint32_t presentedFrameCount;
|
||||
uint32_t interpolatedFrameCount;
|
||||
} AuroraStats;
|
||||
|
||||
typedef struct {
|
||||
uint64_t totalPresentCount;
|
||||
uint32_t sampleCount;
|
||||
double framesPerSecond;
|
||||
double averageFrameTimeMs;
|
||||
double p95FrameTimeMs;
|
||||
double jitterMs;
|
||||
// framesPerSecond with duplicated presentation slots scaled out, so this is the rate of frames
|
||||
// that carried new motion. Equal to framesPerSecond when every slot replayed real interpolation.
|
||||
double effectiveFramesPerSecond;
|
||||
} AuroraPresentTiming;
|
||||
|
||||
const AuroraStats* aurora_get_stats();
|
||||
void aurora_get_present_timing(AuroraPresentTiming* timing);
|
||||
|
||||
// Interpolation health: the per-frame fields describe the last sealed frame, the counters
|
||||
// accumulate since it was configured. This answers "output FPS dropped but the game held 60".
|
||||
typedef struct {
|
||||
uint32_t targetFps; // configured target, 0 when interpolation is off
|
||||
uint32_t targetSamples; // slots the pacing controller currently aims for
|
||||
uint32_t activeSamples; // slots latched for the latest sealed frame
|
||||
uint32_t candidates; // perspective draws in the latest sealed frame
|
||||
uint32_t matchable; // candidates whose identity also existed last frame
|
||||
uint32_t matches; // draws matched to the previous frame
|
||||
uint32_t eligible; // latest frame inserted interpolated slots
|
||||
uint32_t replaySafe; // latest frame could replay its command stream
|
||||
uint64_t framesSealed;
|
||||
uint64_t framesLowMatch;
|
||||
uint64_t framesReplayUnsafe;
|
||||
uint64_t slotReductions;
|
||||
uint64_t lateSealDrops;
|
||||
} AuroraFrameInterpolationDiagnostics;
|
||||
|
||||
void aurora_get_frame_interpolation_diagnostics(AuroraFrameInterpolationDiagnostics* diagnostics);
|
||||
|
||||
// Generates transform-interpolated perspective frames between consecutive 60 Hz logical frames.
|
||||
// Supported targets are 0 (off), 120, 180 and 240. Guest simulation and VI timing are unchanged.
|
||||
void aurora_set_frame_interpolation_fps(uint32_t targetFps);
|
||||
uint32_t aurora_get_frame_interpolation_fps();
|
||||
|
||||
// Newly encountered GX pipelines compile on the bounded worker queue. Draws whose pipeline is not
|
||||
// ready are skipped rather than stalling submission, and pick it up once compilation finishes.
|
||||
void aurora_set_skip_unready_pipelines(bool enabled);
|
||||
bool aurora_get_skip_unready_pipelines();
|
||||
uint32_t aurora_get_queued_pipeline_count();
|
||||
|
||||
// Controls whether display copies bypass the Wii's vertical copy filter.
|
||||
void aurora_set_disable_copy_filter(bool disabled);
|
||||
bool aurora_get_disable_copy_filter();
|
||||
|
||||
// Guest-RAM write tracking. `generation` changes whenever guest RAM covering a host range was
|
||||
// written (or returns AURORA_GUEST_WRITE_UNTRACKED); `notify` reports writes aurora made itself.
|
||||
#define AURORA_GUEST_WRITE_UNTRACKED UINT64_MAX
|
||||
typedef uint64_t (*AuroraGuestWriteGenerationCallback)(const void* hostPtr, size_t size);
|
||||
typedef void (*AuroraGuestWriteNotifyCallback)(const void* hostPtr, size_t size);
|
||||
void aurora_set_guest_write_hooks(AuroraGuestWriteGenerationCallback generation,
|
||||
AuroraGuestWriteNotifyCallback notify);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef AURORA_IMGUI_H
|
||||
#define AURORA_IMGUI_H
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstdint>
|
||||
|
||||
extern "C" {
|
||||
#else
|
||||
#include "stdint.h"
|
||||
#endif
|
||||
|
||||
ImTextureID aurora_imgui_add_texture(uint32_t width, uint32_t height, const void* rgba8);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 1
|
||||
|
||||
typedef struct SDL_IOStream SDL_IOStream;
|
||||
typedef SDL_IOStream* ImFileHandle;
|
||||
typedef unsigned long long ImU64;
|
||||
|
||||
ImFileHandle ImFileOpen(const char* filename, const char* mode);
|
||||
bool ImFileClose(ImFileHandle file);
|
||||
ImU64 ImFileGetSize(ImFileHandle file);
|
||||
ImU64 ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file);
|
||||
ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file);
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef AURORA_MAIN_H
|
||||
#define AURORA_MAIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int aurora_main(int argc, char* argv[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define main aurora_main
|
||||
|
||||
#endif
|
||||
@@ -1,254 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#ifndef AURORA_VEC2_EXTRA
|
||||
#define AURORA_VEC2_EXTRA
|
||||
#endif
|
||||
#ifndef AURORA_VEC3_EXTRA
|
||||
#define AURORA_VEC3_EXTRA
|
||||
#endif
|
||||
#ifndef AURORA_VEC4_EXTRA
|
||||
#define AURORA_VEC4_EXTRA
|
||||
#endif
|
||||
#ifndef AURORA_MAT4X4_EXTRA
|
||||
#define AURORA_MAT4X4_EXTRA
|
||||
#endif
|
||||
|
||||
#ifndef __has_attribute
|
||||
#define __has_attribute(x) 0
|
||||
#endif
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
#if __has_attribute(vector_size) && !defined(__clang__)
|
||||
#define USE_GCC_VECTOR_EXTENSIONS
|
||||
#endif
|
||||
|
||||
namespace aurora {
|
||||
template <typename T>
|
||||
struct Vec2 {
|
||||
T x{};
|
||||
T y{};
|
||||
|
||||
constexpr Vec2() = default;
|
||||
constexpr Vec2(T x, T y) : x(x), y(y) {}
|
||||
AURORA_VEC2_EXTRA
|
||||
|
||||
bool operator==(const Vec2& rhs) const { return x == rhs.x && y == rhs.y; }
|
||||
bool operator!=(const Vec2& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
template <typename T>
|
||||
struct Vec3 {
|
||||
T x{};
|
||||
T y{};
|
||||
T z{};
|
||||
|
||||
constexpr Vec3() = default;
|
||||
constexpr Vec3(T x, T y, T z) : x(x), y(y), z(z) {}
|
||||
AURORA_VEC3_EXTRA
|
||||
|
||||
bool operator==(const Vec3& rhs) const { return x == rhs.x && y == rhs.y && z == rhs.z; }
|
||||
bool operator!=(const Vec3& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
template <typename T>
|
||||
struct Vec4 {
|
||||
#ifdef USE_GCC_VECTOR_EXTENSIONS
|
||||
typedef T Vt __attribute__((vector_size(sizeof(T) * 4)));
|
||||
Vt m;
|
||||
#else
|
||||
using Vt = T[4];
|
||||
Vt m;
|
||||
#endif
|
||||
|
||||
constexpr Vec4() = default;
|
||||
constexpr Vec4(Vt m) : m(m) {}
|
||||
constexpr Vec4(T x, T y, T z, T w) : m{x, y, z, w} {}
|
||||
// For Vec3 with padding
|
||||
constexpr Vec4(T x, T y, T z) : m{x, y, z, {}} {}
|
||||
// For Vec3 -> Vec4
|
||||
constexpr Vec4(Vec3<T> v, T w) : m{v.x, v.y, v.z, w} {}
|
||||
AURORA_VEC4_EXTRA
|
||||
|
||||
inline Vec4& operator=(const Vec4& other) {
|
||||
memcpy(&m, &other.m, sizeof(Vt));
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline T& x() { return m[0]; }
|
||||
[[nodiscard]] inline T x() const { return m[0]; }
|
||||
[[nodiscard]] inline T& y() { return m[1]; }
|
||||
[[nodiscard]] inline T y() const { return m[1]; }
|
||||
[[nodiscard]] inline T& z() { return m[2]; }
|
||||
[[nodiscard]] inline T z() const { return m[2]; }
|
||||
[[nodiscard]] inline T& w() { return m[3]; }
|
||||
[[nodiscard]] inline T w() const { return m[3]; }
|
||||
[[nodiscard]] inline T& operator[](size_t i) { return m[i]; }
|
||||
[[nodiscard]] inline T operator[](size_t i) const { return m[i]; }
|
||||
|
||||
template <size_t x, size_t y, size_t z, size_t w>
|
||||
[[nodiscard]] constexpr Vec4 shuffle() const {
|
||||
static_assert(x < 4 && y < 4 && z < 4 && w < 4);
|
||||
#if defined(USE_GCC_VECTOR_EXTENSIONS) && __has_builtin(__builtin_shuffle)
|
||||
typedef int Vi __attribute__((vector_size(16)));
|
||||
return __builtin_shuffle(m, Vi{x, y, z, w});
|
||||
#else
|
||||
return {m[x], m[y], m[z], m[w]};
|
||||
#endif
|
||||
}
|
||||
|
||||
bool operator==(const Vec4& rhs) const {
|
||||
#if defined(USE_GCC_VECTOR_EXTENSIONS) && __has_builtin(__builtin_reduce_and)
|
||||
return __builtin_reduce_and(m == rhs.m) != 0;
|
||||
#else
|
||||
return m[0] == rhs.m[0] && m[1] == rhs.m[1] && m[2] == rhs.m[2] && m[3] == rhs.m[3];
|
||||
#endif
|
||||
}
|
||||
bool operator!=(const Vec4& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
template <typename T>
|
||||
[[nodiscard]] Vec4<T> operator+(const Vec4<T>& a, const Vec4<T>& b) {
|
||||
#ifdef USE_GCC_VECTOR_EXTENSIONS
|
||||
return a.m + b.m;
|
||||
#else
|
||||
return {a.m[0] + b.m[0], a.m[1] + b.m[1], a.m[2] + b.m[2], a.m[3] + b.m[3]};
|
||||
#endif
|
||||
}
|
||||
template <typename T>
|
||||
[[nodiscard]] Vec4<T> operator*(const Vec4<T>& a, const Vec4<T>& b) {
|
||||
#ifdef USE_GCC_VECTOR_EXTENSIONS
|
||||
return a.m * b.m;
|
||||
#else
|
||||
return {a.m[0] * b.m[0], a.m[1] * b.m[1], a.m[2] * b.m[2], a.m[3] * b.m[3]};
|
||||
#endif
|
||||
}
|
||||
template <typename T>
|
||||
struct Mat3x2 {
|
||||
Vec2<T> m0{};
|
||||
Vec2<T> m1{};
|
||||
Vec2<T> m2{};
|
||||
|
||||
constexpr Mat3x2() = default;
|
||||
constexpr Mat3x2(const Vec2<T>& m0, const Vec2<T>& m1, const Vec2<T>& m2) : m0(m0), m1(m1), m2(m2) {}
|
||||
|
||||
bool operator==(const Mat3x2& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2; }
|
||||
bool operator!=(const Mat3x2& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
template <typename T>
|
||||
struct Mat4x2 {
|
||||
Vec2<T> m0{};
|
||||
Vec2<T> m1{};
|
||||
Vec2<T> m2{};
|
||||
Vec2<T> m3{};
|
||||
|
||||
constexpr Mat4x2() = default;
|
||||
constexpr Mat4x2(const Vec2<T>& m0, const Vec2<T>& m1, const Vec2<T>& m2, const Vec2<T>& m3)
|
||||
: m0(m0), m1(m1), m2(m2), m3(m3) {}
|
||||
|
||||
inline Mat4x2 transpose() const {
|
||||
return {
|
||||
{m0.x, m2.x},
|
||||
{m0.y, m2.y},
|
||||
{m1.x, m3.x},
|
||||
{m1.y, m3.y},
|
||||
};
|
||||
}
|
||||
|
||||
bool operator==(const Mat4x2& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2 && m3 == rhs.m3; }
|
||||
bool operator!=(const Mat4x2& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
template <typename T>
|
||||
struct Mat2x4 {
|
||||
Vec4<T> m0{};
|
||||
Vec4<T> m1{};
|
||||
|
||||
constexpr Mat2x4() = default;
|
||||
constexpr Mat2x4(const Vec4<T>& m0, const Vec4<T>& m1, const Vec4<T>& m2) : m0(m0), m1(m1) {}
|
||||
|
||||
bool operator==(const Mat2x4& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1; }
|
||||
bool operator!=(const Mat2x4& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
static_assert(sizeof(Mat2x4<float>) == 32);
|
||||
template <typename T>
|
||||
struct Mat4x4;
|
||||
template <typename T>
|
||||
struct Mat3x4 {
|
||||
Vec4<T> m0{};
|
||||
Vec4<T> m1{};
|
||||
Vec4<T> m2{};
|
||||
|
||||
constexpr Mat3x4() = default;
|
||||
constexpr Mat3x4(const Vec4<T>& m0, const Vec4<T>& m1, const Vec4<T>& m2) : m0(m0), m1(m1), m2(m2) {}
|
||||
|
||||
[[nodiscard]] Mat4x4<T> to4x4() const;
|
||||
[[nodiscard]] Mat4x4<T> toTransposed4x4() const;
|
||||
|
||||
bool operator==(const Mat3x4& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2; }
|
||||
bool operator!=(const Mat3x4& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
static_assert(sizeof(Mat3x4<float>) == 48);
|
||||
template <typename T>
|
||||
struct Mat4x4 {
|
||||
Vec4<T> m0{};
|
||||
Vec4<T> m1{};
|
||||
Vec4<T> m2{};
|
||||
Vec4<T> m3{};
|
||||
|
||||
constexpr Mat4x4() = default;
|
||||
constexpr Mat4x4(const Vec4<T>& m0, const Vec4<T>& m1, const Vec4<T>& m2, const Vec4<T>& m3)
|
||||
: m0(m0), m1(m1), m2(m2), m3(m3) {}
|
||||
AURORA_MAT4X4_EXTRA
|
||||
|
||||
[[nodiscard]] Mat4x4 transpose() const {
|
||||
return {
|
||||
{m0[0], m1[0], m2[0], m3[0]},
|
||||
{m0[1], m1[1], m2[1], m3[1]},
|
||||
{m0[2], m1[2], m2[2], m3[2]},
|
||||
{m0[3], m1[3], m2[3], m3[3]},
|
||||
};
|
||||
}
|
||||
Mat4x4& operator=(const Mat4x4& other) = default;
|
||||
|
||||
Vec4<T>& operator[](size_t i) { return *(&m0 + i); }
|
||||
const Vec4<T>& operator[](size_t i) const { return *(&m0 + i); }
|
||||
|
||||
bool operator==(const Mat4x4& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2 && m3 == rhs.m3; }
|
||||
bool operator!=(const Mat4x4& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
static_assert(sizeof(Mat4x4<float>) == 64);
|
||||
template <typename T>
|
||||
[[nodiscard]] Mat4x4<T> operator*(const Mat4x4<T>& a, const Mat4x4<T>& b) {
|
||||
Mat4x4<T> out;
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
*(&out.m0 + i) = a.m0 * b[i].template shuffle<0, 0, 0, 0>() + a.m1 * b[i].template shuffle<1, 1, 1, 1>() +
|
||||
a.m2 * b[i].template shuffle<2, 2, 2, 2>() + a.m3 * b[i].template shuffle<3, 3, 3, 3>();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename T>
|
||||
[[nodiscard]] Mat4x4<T> Mat3x4<T>::to4x4() const {
|
||||
return {
|
||||
{m0[0], m0[1], m0[2], 0.f},
|
||||
{m1[0], m1[1], m1[2], 0.f},
|
||||
{m2[0], m2[1], m2[2], 0.f},
|
||||
{m0[3], m1[3], m2[3], 1.f},
|
||||
};
|
||||
}
|
||||
template <typename T>
|
||||
[[nodiscard]] Mat4x4<T> Mat3x4<T>::toTransposed4x4() const {
|
||||
return Mat4x4<T>{
|
||||
{m0[0], m1[0], m2[0], 0.f},
|
||||
{m0[1], m1[1], m2[1], 0.f},
|
||||
{m0[2], m1[2], m2[2], 0.f},
|
||||
{m0[3], m1[3], m2[3], 1.f},
|
||||
};
|
||||
}
|
||||
constexpr Mat4x4 Mat4x4_Identity{
|
||||
Vec4{1.f, 0.f, 0.f, 0.f},
|
||||
Vec4{0.f, 1.f, 0.f, 0.f},
|
||||
Vec4{0.f, 0.f, 1.f, 0.f},
|
||||
Vec4{0.f, 0.f, 0.f, 1.f},
|
||||
};
|
||||
} // namespace aurora
|
||||
@@ -1,81 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace aurora::render_size_limits {
|
||||
|
||||
struct Size {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
// The canvas follows the window aspect however wide it gets, since the presenter stretches it and
|
||||
// a cap would distort the UI. Only the portrait side clamps, where the guest cannot fill taller.
|
||||
inline constexpr float kMaxDynamicPortraitExpansion = 6.f;
|
||||
inline constexpr float kMinDynamicAspect = (16.f / 9.f) / kMaxDynamicPortraitExpansion;
|
||||
|
||||
// The adapter limit is an API ceiling, not an allocation budget: a 16384-wide RGBA attachment is
|
||||
// near 100 MiB. 8192 plus an 8K-UHD pixel budget keeps 8x 16:9 while avoiding device removal.
|
||||
inline constexpr uint32_t kMaxFramebufferDimension = 8192;
|
||||
inline constexpr uint64_t kMaxFramebufferPixels = 7680ull * 4320ull;
|
||||
|
||||
inline float clamp_dynamic_aspect(float aspect) noexcept {
|
||||
if (!std::isfinite(aspect) || aspect <= 0.f) {
|
||||
return 1.f;
|
||||
}
|
||||
return std::max(aspect, kMinDynamicAspect);
|
||||
}
|
||||
|
||||
inline Size scale_framebuffer_to_aspect(uint32_t width, uint32_t height, float scale, float requestedAspect) noexcept {
|
||||
if (width == 0 || height == 0 || !std::isfinite(scale) || scale <= 0.f) {
|
||||
return {std::max(width, 1u), std::max(height, 1u)};
|
||||
}
|
||||
|
||||
const auto scaledWidth = std::max(1u, static_cast<uint32_t>(std::lround(static_cast<double>(width) * scale)));
|
||||
const auto scaledHeight = std::max(1u, static_cast<uint32_t>(std::lround(static_cast<double>(height) * scale)));
|
||||
const float aspect = clamp_dynamic_aspect(requestedAspect);
|
||||
if (aspect >= static_cast<float>(width) / static_cast<float>(height)) {
|
||||
return {
|
||||
std::max(1u, static_cast<uint32_t>(std::lround(static_cast<double>(scaledHeight) * aspect))),
|
||||
scaledHeight,
|
||||
};
|
||||
}
|
||||
return {
|
||||
scaledWidth,
|
||||
std::max(1u, static_cast<uint32_t>(std::lround(static_cast<double>(scaledWidth) / aspect))),
|
||||
};
|
||||
}
|
||||
|
||||
inline Size fit_framebuffer_to_budget(uint32_t width, uint32_t height, uint32_t adapterMaxDimension) noexcept {
|
||||
if (width == 0 || height == 0) {
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
uint32_t dimensionLimit = kMaxFramebufferDimension;
|
||||
if (adapterMaxDimension != 0 && adapterMaxDimension != std::numeric_limits<uint32_t>::max()) {
|
||||
dimensionLimit = std::min(dimensionLimit, adapterMaxDimension);
|
||||
}
|
||||
dimensionLimit = std::max(dimensionLimit, 1u);
|
||||
|
||||
double fitScale = 1.0;
|
||||
fitScale = std::min(fitScale, static_cast<double>(dimensionLimit) / static_cast<double>(width));
|
||||
fitScale = std::min(fitScale, static_cast<double>(dimensionLimit) / static_cast<double>(height));
|
||||
|
||||
const double requestedPixels = static_cast<double>(width) * static_cast<double>(height);
|
||||
if (requestedPixels > static_cast<double>(kMaxFramebufferPixels)) {
|
||||
fitScale = std::min(fitScale, std::sqrt(static_cast<double>(kMaxFramebufferPixels) / requestedPixels));
|
||||
}
|
||||
|
||||
if (fitScale >= 1.0) {
|
||||
return {width, height};
|
||||
}
|
||||
return {
|
||||
std::max(1u, static_cast<uint32_t>(std::floor(static_cast<double>(width) * fitScale))),
|
||||
std::max(1u, static_cast<uint32_t>(std::floor(static_cast<double>(height) * fitScale))),
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace aurora::render_size_limits
|
||||
@@ -1,50 +0,0 @@
|
||||
#ifndef _DOLPHIN_AI_H_
|
||||
#define _DOLPHIN_AI_H_
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*AISCallback)(u32 count);
|
||||
typedef void (*AIDCallback)();
|
||||
|
||||
#define AI_STREAM_START 1
|
||||
#define AI_STREAM_STOP 0
|
||||
|
||||
#define AI_SAMPLERATE_32KHZ 0
|
||||
#define AI_SAMPLERATE_48KHZ 1
|
||||
|
||||
AIDCallback AIRegisterDMACallback(AIDCallback callback);
|
||||
void AIInitDMA(u32 start_addr, u32 length);
|
||||
BOOL AIGetDMAEnableFlag(void);
|
||||
void AIStartDMA(void);
|
||||
void AIStopDMA(void);
|
||||
u32 AIGetDMABytesLeft(void);
|
||||
u32 AIGetDMAStartAddr(void);
|
||||
u32 AIGetDMALength(void);
|
||||
BOOL AICheckInit(void);
|
||||
AISCallback AIRegisterStreamCallback(AISCallback callback);
|
||||
u32 AIGetStreamSampleCount(void);
|
||||
void AIResetStreamSampleCount(void);
|
||||
void AISetStreamTrigger(u32 trigger);
|
||||
u32 AIGetStreamTrigger(void);
|
||||
void AISetStreamPlayState(u32 state);
|
||||
u32 AIGetStreamPlayState(void);
|
||||
void AISetDSPSampleRate(u32 rate);
|
||||
u32 AIGetDSPSampleRate(void);
|
||||
void AISetStreamSampleRate(u32 rate);
|
||||
u32 AIGetStreamSampleRate(void);
|
||||
void AISetStreamVolLeft(u8 vol);
|
||||
u8 AIGetStreamVolLeft(void);
|
||||
void AISetStreamVolRight(u8 vol);
|
||||
u8 AIGetStreamVolRight(void);
|
||||
void AIInit(u8* stack);
|
||||
void AIReset(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,79 +0,0 @@
|
||||
#ifndef _DOLPHIN_AR_H_
|
||||
#define _DOLPHIN_AR_H_
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*ARQCallback)(uintptr_t pointerToARQRequest);
|
||||
|
||||
struct ARQRequest {
|
||||
/* 0x00 */ struct ARQRequest *next;
|
||||
/* 0x04 */ u32 owner;
|
||||
/* 0x08 */ u32 type;
|
||||
/* 0x0C */ u32 priority;
|
||||
/* 0x10 */ u32 source;
|
||||
/* 0x14 */ u32 dest;
|
||||
/* 0x18 */ u32 length;
|
||||
/* 0x1C */ ARQCallback callback;
|
||||
};
|
||||
|
||||
#define ARQ_DMA_ALIGNMENT 32
|
||||
|
||||
#define ARAM_DIR_MRAM_TO_ARAM 0x00
|
||||
#define ARAM_DIR_ARAM_TO_MRAM 0x01
|
||||
|
||||
#define ARStartDMARead(mmem, aram, len) \
|
||||
ARStartDMA(ARAM_DIR_ARAM_TO_MRAM, mmem, aram, len)
|
||||
#define ARStartDMAWrite(mmem, aram, len) \
|
||||
ARStartDMA(ARAM_DIR_MRAM_TO_ARAM, mmem, aram, len)
|
||||
|
||||
typedef struct ARQRequest ARQRequest;
|
||||
|
||||
#define ARQ_TYPE_MRAM_TO_ARAM ARAM_DIR_MRAM_TO_ARAM
|
||||
#define ARQ_TYPE_ARAM_TO_MRAM ARAM_DIR_ARAM_TO_MRAM
|
||||
|
||||
#define ARQ_PRIORITY_LOW 0
|
||||
#define ARQ_PRIORITY_HIGH 1
|
||||
|
||||
// AR
|
||||
ARQCallback ARRegisterDMACallback(ARQCallback callback);
|
||||
u32 ARGetDMAStatus(void);
|
||||
void ARStartDMA(u32 type, u32 mainmem_addr, u32 aram_addr, u32 length);
|
||||
u32 ARAlloc(u32 length);
|
||||
u32 ARFree(u32* length);
|
||||
BOOL ARCheckInit(void);
|
||||
u32 ARInit(u32* stack_index_addr, u32 num_entries);
|
||||
void ARReset(void);
|
||||
void ARSetSize(void);
|
||||
u32 ARGetBaseAddress(void);
|
||||
u32 ARGetSize(void);
|
||||
u32 ARGetInternalSize(void);
|
||||
void ARClear(u32 flag);
|
||||
|
||||
/**
|
||||
* Aurora extension: gets the memory address where ARAM is stored, for direct access.
|
||||
*/
|
||||
void* ARGetStorageAddress();
|
||||
|
||||
// ARQ
|
||||
void ARQInit(void);
|
||||
void ARQReset(void);
|
||||
void ARQPostRequest(ARQRequest* request, u32 owner, u32 type, u32 priority, uintptr_t source, uintptr_t dest, u32 length, ARQCallback callback);
|
||||
void ARQRemoveRequest(ARQRequest* request);
|
||||
void ARQRemoveOwnerRequest(u32 owner);
|
||||
void ARQFlushQueue(void);
|
||||
void ARQSetChunkSize(u32 size);
|
||||
u32 ARQGetChunkSize(void);
|
||||
BOOL ARQCheckInit(void);
|
||||
|
||||
u16 __ARGetInterruptStatus(void);
|
||||
void __ARClearInterrupt(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,542 +0,0 @@
|
||||
#ifndef _DOLPHIN_PPCARCH
|
||||
#define _DOLPHIN_PPCARCH
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CTR 9
|
||||
#define XER 1
|
||||
#define LR 8
|
||||
|
||||
#define UPMC1 937
|
||||
#define UPMC2 938
|
||||
#define UPMC3 941
|
||||
#define UPMC4 942
|
||||
|
||||
#define USIA 939
|
||||
|
||||
#define UMMCR0 936
|
||||
#define UMMCR1 940
|
||||
|
||||
#define HID0 1008
|
||||
#define HID1 1009
|
||||
|
||||
#define PVR 287
|
||||
|
||||
#define IBAT0U 528
|
||||
#define IBAT0L 529
|
||||
#define IBAT1U 530
|
||||
#define IBAT1L 531
|
||||
#define IBAT2U 532
|
||||
#define IBAT2L 533
|
||||
#define IBAT3U 534
|
||||
#define IBAT3L 535
|
||||
|
||||
#define DBAT0U 536
|
||||
#define DBAT0L 537
|
||||
#define DBAT1U 538
|
||||
#define DBAT1L 539
|
||||
#define DBAT2U 540
|
||||
#define DBAT2L 541
|
||||
#define DBAT3U 542
|
||||
#define DBAT3L 543
|
||||
|
||||
#define SDR1 25
|
||||
|
||||
#define SPRG0 272
|
||||
#define SPRG1 273
|
||||
#define SPRG2 274
|
||||
#define SPRG3 275
|
||||
|
||||
#define DAR 19
|
||||
#define DSISR 18
|
||||
|
||||
#define SRR0 26
|
||||
#define SRR1 27
|
||||
|
||||
#define EAR 282
|
||||
|
||||
#define DABR 1013
|
||||
|
||||
#define TBL 284
|
||||
#define TBU 285
|
||||
|
||||
#define L2CR 1017
|
||||
|
||||
#define DEC 22
|
||||
|
||||
#define IABR 1010
|
||||
|
||||
#define PMC1 953
|
||||
#define PMC2 954
|
||||
#define PMC3 957
|
||||
#define PMC4 958
|
||||
|
||||
#define SIA 955
|
||||
|
||||
#define MMCR0 952
|
||||
#define MMCR1 956
|
||||
|
||||
#define THRM1 1020
|
||||
#define THRM2 1021
|
||||
#define THRM3 1022
|
||||
|
||||
#define ICTC 1019
|
||||
|
||||
#define GQR0 912
|
||||
#define GQR1 913
|
||||
#define GQR2 914
|
||||
#define GQR3 915
|
||||
#define GQR4 916
|
||||
#define GQR5 917
|
||||
#define GQR6 918
|
||||
#define GQR7 919
|
||||
|
||||
#define HID2 920
|
||||
|
||||
#define WPAR 921
|
||||
|
||||
#define DMA_U 922
|
||||
#define DMA_L 923
|
||||
|
||||
#define MSR_POW 0x00040000 // Power Management
|
||||
#define MSR_ILE 0x00010000 // Interrupt Little Endian
|
||||
#define MSR_EE 0x00008000 // external interrupt
|
||||
#define MSR_PR 0x00004000 // privilege level(should be 0)
|
||||
#define MSR_FP 0x00002000 // floating point available
|
||||
#define MSR_ME 0x00001000 // machine check enable
|
||||
#define MSR_FE0 0x00000800 // floating point exception enable
|
||||
#define MSR_SE 0x00000400 // single step trace enable
|
||||
#define MSR_BE 0x00000200 // branch trace enable
|
||||
#define MSR_FE1 0x00000100 // floating point exception enable
|
||||
#define MSR_IP 0x00000040 // Exception prefix
|
||||
#define MSR_IR 0x00000020 // instruction relocate
|
||||
#define MSR_DR 0x00000010 // data relocate
|
||||
#define MSR_PM 0x00000004 // Performance monitor marked mode
|
||||
#define MSR_RI 0x00000002 // Recoverable interrupt
|
||||
#define MSR_LE 0x00000001 // Little Endian
|
||||
|
||||
#define MSR_POW_BIT 13 // Power Management
|
||||
#define MSR_ILE_BIT 15 // Interrupt Little Endian
|
||||
#define MSR_EE_BIT 16 // external interrupt
|
||||
#define MSR_PR_BIT 17 // privilege level (should be 0)
|
||||
#define MSR_FP_BIT 18 // floating point available
|
||||
#define MSR_ME_BIT 19 // machine check enable
|
||||
#define MSR_FE0_BIT 20 // floating point exception enable
|
||||
#define MSR_SE_BIT 21 // single step trace enable
|
||||
#define MSR_BE_BIT 22 // branch trace enable
|
||||
#define MSR_FE1_BIT 23 // floating point exception enable
|
||||
#define MSR_IP_BIT 25 // Exception prefix
|
||||
#define MSR_IR_BIT 26 // instruction relocate
|
||||
#define MSR_DR_BIT 27 // data relocate
|
||||
#define MSR_PM_BIT 29 // Performance monitor marked mode
|
||||
#define MSR_RI_BIT 30 // Recoverable interrupt
|
||||
#define MSR_LE_BIT 31 // Little Endian
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
HID0 bits
|
||||
*---------------------------------------------------------------------------*/
|
||||
#define HID0_EMCP 0x80000000u // Enable MCP
|
||||
#define HID0_DBP 0x40000000u // Enable 60x bus address and data parity chk
|
||||
#define HID0_EBA 0x20000000u // Enable 60x address parity checking
|
||||
#define HID0_EBD 0x10000000u // Enable 60x data parity checking
|
||||
#define HID0_BCLK 0x08000000u // CLK_OUT output enable and clk selection
|
||||
#define HID0_ECLK 0x02000000u // CLK_OUT output enable and clk selection
|
||||
#define HID0_PAR 0x01000000u // Disable !ARTRY precharge
|
||||
#define HID0_DOZE 0x00800000u // Doze mode enable
|
||||
#define HID0_NAP 0x00400000u // Nap mode enable
|
||||
#define HID0_SLEEP 0x00200000u // Sleep mode enable
|
||||
#define HID0_DPM 0x00100000u // Dynamic power management enable
|
||||
#define HID0_NHR 0x00010000u // Not hard reset (0 hard reset if s/w set it)
|
||||
#define HID0_ICE 0x00008000u // Instruction cache enable
|
||||
#define HID0_DCE 0x00004000u // Data cache enable
|
||||
#define HID0_ILOCK 0x00002000u // ICache lock
|
||||
#define HID0_DLOCK 0x00001000u // DCache lock
|
||||
#define HID0_ICFI 0x00000800u // ICache flash invalidate
|
||||
#define HID0_DCFI 0x00000400u // DCache flash invalidate
|
||||
#define HID0_SPD 0x00000200u // Speculative cache access enable (0 enable)
|
||||
#define HID0_IFEM 0x00000100u // Enable M bit on bus for Ifetch
|
||||
#define HID0_SGE 0x00000080u // Store gathering enable
|
||||
#define HID0_DCFA 0x00000040u // DCache flush assist - set before a flush
|
||||
#define HID0_BTIC 0x00000020u // Branch target icache enable
|
||||
#define HID0_ABE 0x00000008u // Address bcast enable
|
||||
#define HID0_BHT 0x00000004u // Branch history table enable
|
||||
#define HID0_NOOPTI 0x00000001u // No-op Dcache touch instructions
|
||||
|
||||
#define HID0_ICE_BIT 16 // Instruction cache enable
|
||||
#define HID0_DCE_BIT 17 // Data cache enable
|
||||
#define HID0_ILOCK_BIT 18 // ICache lock
|
||||
#define HID0_DLOCK_BIT 19 // DCache lock
|
||||
|
||||
#define HID2_LSQE 0x80000000 // L/S quantize enable
|
||||
#define HID2_WPE 0x40000000 // Write pipe enable
|
||||
#define HID2_PSE 0x20000000 // Paired single enable
|
||||
#define HID2_LCE 0x10000000 // Locked cache enable
|
||||
|
||||
#define HID2_DCHERR 0x00800000 // ERROR: dcbz_l cache hit
|
||||
#define HID2_DNCERR 0x00400000 // ERROR: DMA access to normal cache
|
||||
#define HID2_DCMERR 0x00200000 // ERROR: DMA cache miss error
|
||||
#define HID2_DQOERR 0x00100000 // ERROR: DMA queue overflow
|
||||
#define HID2_DCHEE 0x00080000 // dcbz_l cache hit error enable
|
||||
#define HID2_DNCEE 0x00040000 // DMA access to normal cache error enable
|
||||
#define HID2_DCMEE 0x00020000 // DMA cache miss error error enable
|
||||
#define HID2_DQOEE 0x00010000 // DMA queue overflow error enable
|
||||
|
||||
#define HID2_DMAQL_MASK 0x0F000000 // DMA queue length mask
|
||||
#define HID2_DMAQL_SHIFT 24 // DMA queue shift
|
||||
|
||||
#define HID2_LSQE_BIT 0
|
||||
#define HID2_WPE_BIT 1
|
||||
#define HID2_PSE_BIT 2
|
||||
#define HID2_LCE_BIT 3
|
||||
|
||||
#define HID2_DCHERR_BIT 8
|
||||
#define HID2_DNCERR_BIT 9
|
||||
#define HID2_DCMERR_BIT 10
|
||||
#define HID2_DQOERR_BIT 11
|
||||
#define HID2_DCHEE_BIT 12
|
||||
#define HID2_DNCEE_BIT 13
|
||||
#define HID2_DCMEE_BIT 14
|
||||
#define HID2_DQOEE_BIT 15
|
||||
|
||||
#define GQR_LOAD_SCALE_MASK 0x3F000000 // load scale field
|
||||
#define GQR_LOAD_TYPE_MASK 0x00070000 // load type field
|
||||
#define GQR_STORE_SCALE_MASK 0x00003F00 // store scale field
|
||||
#define GQR_STORE_TYPE_MASK 0x00000007 // store type field
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 _pad0 :2;
|
||||
u32 loadScale :6;
|
||||
u32 _pad1 :5;
|
||||
u32 loadType :3;
|
||||
u32 _pad2 :2;
|
||||
u32 storeScale :6;
|
||||
u32 _pad3 :5;
|
||||
u32 storeType :3;
|
||||
} PPC_GQR_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
u32 val;
|
||||
PPC_GQR_t f;
|
||||
} PPC_GQR_u;
|
||||
|
||||
|
||||
#define DMA_U_ADDR_MASK 0xFFFFFFE0 // Start addr in memory
|
||||
#define DMA_U_LEN_U_MASK 0x0000001F // lines to transfer (U)
|
||||
|
||||
#define DMA_L_LC_ADDR_MASK 0xFFFFFFE0 // Start addr in LC
|
||||
#define DMA_L_LOAD 0x00000010 // 0 - store, 1 - load
|
||||
#define DMA_L_STORE 0x00000000 // 0 - store, 1 - load
|
||||
#define DMA_L_LEN_MASK 0x0000000C // lines to transfer (L)
|
||||
#define DMA_L_TRIGGER 0x00000002 // 0 - cmd inactive, 1 - cmd rdy
|
||||
#define DMA_L_FLUSH 0x00000001 // 1 - Flush DMA queue
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 memAddr :27;
|
||||
u32 dmaLenU :5;
|
||||
} PPC_DMA_U_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
u32 val;
|
||||
PPC_DMA_U_t f;
|
||||
} PPC_DMA_U_u;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 lcAddr :27;
|
||||
u32 dmaLd :1;
|
||||
u32 dmaLenL :2;
|
||||
u32 dmaTrigger :1;
|
||||
u32 dmaFlush :1;
|
||||
} PPC_DMA_L_t;
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
u32 val;
|
||||
PPC_DMA_L_t f;
|
||||
} PPC_DMA_L_u;
|
||||
|
||||
|
||||
#define WPAR_ADDR 0xFFFFFFE0 // 32byte gather address
|
||||
#define WPAR_BNE 0x00000001 // Buffer not empty (R)
|
||||
|
||||
#define SRR1_DMA_BIT 0x00200000
|
||||
#define SRR1_L2DP_BIT 0x00100000
|
||||
|
||||
#define L2CR_L2E 0x80000000 // L2 Enable
|
||||
#define L2CR_L2PE 0x40000000 // L2 data parity generation and checking enable
|
||||
|
||||
#define L2CR_L2SIZ_256K 0x10000000 // L2 size 256K
|
||||
#define L2CR_L2SIZ_512K 0x20000000 // L2 size 512
|
||||
#define L2CR_L2SIZ_1M 0x30000000 // L2 size 1M
|
||||
|
||||
#define L2CR_L2CLK_1_0 0x02000000 // L2 clock ratio 1
|
||||
#define L2CR_L2CLK_1_5 0x04000000 // L2 clock ratio 1.5
|
||||
#define L2CR_L2CLK_2_0 0x08000000 // L2 clock ratio 2
|
||||
#define L2CR_L2CLK_2_5 0x0A000000 // L2 clock ratio 2.5
|
||||
#define L2CR_L2CLK_3_0 0x0C000000 // L2 clock ratio 3
|
||||
|
||||
#define L2CR_RAM_FLOW_THRU_BURST 0x00000000 // L2 RAM type flow-through sync. burst SRAM
|
||||
#define L2CR_RAM_PIPELINE_BURST 0x01000000 // L2 RAM type pipelined sync. burst SRAM
|
||||
#define L2CR_RAM_PIPELINE_LATE 0x01800000 // L2 RAM type pipelined sync. late-write SRAM
|
||||
|
||||
#define L2CR_L2DO 0x00400000 // Data only
|
||||
#define L2CR_L2I 0x00200000 // Global invalidate
|
||||
#define L2CR_L2CTL 0x00100000 // ZZ enable
|
||||
#define L2CR_L2WT 0x00080000 // L2 write through
|
||||
#define L2CR_L2TS 0x00040000 // L2 test support
|
||||
|
||||
#define L2CR_L2OH_0_5 0x00000000 // L2 output hold 0.5 ns
|
||||
#define L2CR_L2OH_1_0 0x00010000 // L2 output hold 1.0 ns
|
||||
|
||||
#define L2CR_L2SL 0x00008000 // L2 DLL slow
|
||||
#define L2CR_L2DF 0x00004000 // L2 differential clock
|
||||
#define L2CR_L2BYP 0x00002000 // L2 DLL bypass
|
||||
#define L2CR_L2CS 0x00000200 // L2 clock stop
|
||||
#define L2CR_L2DRO 0x00000100 // L2 DLL rollover checkstop enable
|
||||
#define L2CR_L2CTR_MASK 0x000000FE // L2 counter value mask
|
||||
#define L2CR_L2IP 0x00000001 // L2 global invalidate in progress
|
||||
|
||||
#define MMCR0_DIS 0x80000000 // Disables counting unconditionally
|
||||
#define MMCR0_DP 0x40000000 // Disables counting while in supervisor mode
|
||||
#define MMCR0_DU 0x20000000 // Disables counting while in user mode
|
||||
#define MMCR0_DMS 0x10000000 // Disables counting while MSR[PM] is set
|
||||
#define MMCR0_DMR 0x08000000 // Disables counting while MSR[PM] is zero
|
||||
#define MMCR0_ENINT 0x04000000 // Enables performance monitor interrupt signaling
|
||||
#define MMCR0_DISCOUNT 0x02000000 // Disables counting of PMCn when a performance monitor interrupt is signaled or...
|
||||
#define MMCR0_RTCSELECT_MASK 0x01800000 // 64-bit time base, bit selection enable
|
||||
#define MMCR0_RTCSELECT_63 0x00000000 // Pick bit 63 to count
|
||||
#define MMCR0_RTCSELECT_55 0x00800000 // Pick bit 55 to count
|
||||
#define MMCR0_RTCSELECT_51 0x01000000 // Pick bit 51 to count
|
||||
#define MMCR0_RTCSELECT_47 0x01800000 // Pick bit 47 to count
|
||||
#define MMCR0_INTONBITTRANS 0x00400000 // Causes interrupt signaling on bit transition from off to on
|
||||
#define MMCR0_THRESHOLD_MASK 0x003F0000 // Threshold value
|
||||
#define MMCR0_THRESHOLD(n) ((n) << 16) // Threshold value (0 - 63)
|
||||
#define MMCR0_PMC1INTCONTROL 0x00008000 // Enables interrupt signaling due to PMC1 counter overflow
|
||||
#define MMCR0_PMC2INTCONTROL 0x00004000 // Enables interrupt signaling due to PMC2-PMC4 counter overflow
|
||||
#define MMCR0_PMCTRIGGER 0x00002000 // Can be used to trigger counting of PMC2-PMC4 after PMC1 has overflowed or...
|
||||
#define MMCR0_PMC1SELECT_MASK 0x00001FC0 // PMC1 input selector
|
||||
#define MMCR0_PMC2SELECT_MASK 0x0000003F // PMC2 input selector
|
||||
|
||||
#define MMCR1_PMC3SELECT_MASK 0xF8000000 // PMC3 input selector
|
||||
#define MMCR1_PMC4SELECT_MASK 0x07C00000 // PMC4 input selector
|
||||
|
||||
#define PMC1_OV 0x80000000 // Overflow
|
||||
#define PMC1_COUNTER 0x7FFFFFFF // Counter value
|
||||
#define PMC2_OV 0x80000000 // Overflow
|
||||
#define PMC2_COUNTER 0x7FFFFFFF // Counter value
|
||||
#define PMC3_OV 0x80000000 // Overflow
|
||||
#define PMC3_COUNTER 0x7FFFFFFF // Counter value
|
||||
#define PMC4_OV 0x80000000 // Overflow
|
||||
#define PMC4_COUNTER 0x7FFFFFFF // Counter value
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
PMC1 Events
|
||||
*---------------------------------------------------------------------------*/
|
||||
#define MMCR0_PMC1_HOLD 0x00000000 // Register holds current value
|
||||
#define MMCR0_PMC1_CYCLE 0x00000040 // Processor cycles
|
||||
#define MMCR0_PMC1_INSTRUCTION 0x00000080 // # of instructions completed.
|
||||
#define MMCR0_PMC1_TRANSITION 0x000000C0 // # of transitions for 0 to 1
|
||||
#define MMCR0_PMC1_DISPATCHED 0x00000100 // # of instructions dispatched
|
||||
#define MMCR0_PMC1_EIEIO 0x00000140 // # of eieio instructions completed
|
||||
#define MMCR0_PMC1_ITLB_CYCLE 0x00000180 // # of cycles spent performing table search op. for the ITLB
|
||||
#define MMCR0_PMC1_L2_HIT 0x000001C0 // # of access that hit the L2.
|
||||
#define MMCR0_PMC1_EA 0x00000200 // # of valid instruction EAs delivered to the memory subsystem
|
||||
#define MMCR0_PMC1_IABR 0x00000240 // # of time the address of an instruction matches the IABR
|
||||
#define MMCR0_PMC1_L1_MISS 0x00000280 // # of loads that miss the L1
|
||||
#define MMCR0_PMC1_Bx_UNRESOLVED 0x000002C0 // # of branches that are unresolved when processed
|
||||
#define MMCR0_PMC1_Bx_STALL_CYCLE 0x00000300 // # of cycles that dispatcher stalls due to a second
|
||||
// unresolved branch in the instruction stream
|
||||
#define MMCR0_PMC1_IC_FETCH_MISS 0x00000340 // # of times an instruction fetch missed the L1 Icache
|
||||
#define MMCR0_PMC2_HOLD 0x00000000 // Register holds current value
|
||||
#define MMCR0_PMC2_CYCLE 0x00000001 // Processor cycles
|
||||
#define MMCR0_PMC2_INSTRUCTION 0x00000002 // # of instructions completed
|
||||
#define MMCR0_PMC2_TRANSITION 0x00000003 // # of time-base (lower) bit transitions
|
||||
#define MMCR0_PMC2_DISPATCHED 0x00000004 // # of instructions dispatched
|
||||
#define MMCR0_PMC2_IC_MISS 0x00000005 // # of L1 instruction cache misses
|
||||
#define MMCR0_PMC2_ITLB_MISS 0x00000006 // # of ITLB misses
|
||||
#define MMCR0_PMC2_L2_I_MISS 0x00000007 // # of L2 instruction misses
|
||||
#define MMCR0_PMC2_Bx_FALL_TROUGH 0x00000008 // # of fall-through branches
|
||||
#define MMCR0_PMC2_PR_SWITCH 0x00000009 // # of MSR[PR] bit toggles
|
||||
#define MMCR0_PMC2_RESERVED_LOAD 0x0000000A // # of reserved loads completed
|
||||
#define MMCR0_PMC2_LOAD_STORE 0x0000000B // # of completed loads and stores
|
||||
#define MMCR0_PMC2_SNOOP 0x0000000C // # of snoops
|
||||
#define MMCR0_PMC2_L1_CASTOUT 0x0000000D // # of L1 castouts to L2
|
||||
#define MMCR0_PMC2_SYSTEM 0x0000000E // # of completed system unit instructions
|
||||
#define MMCR0_PMC2_IC_FETCH_MISS 0x0000000F // # of instruction fetch misses in the L1
|
||||
#define MMCR0_PMC2_Bx_OUT_OF_ORDER 0x00000010 // # of branches allowing out-of-order execution
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
PMC3 Events
|
||||
*---------------------------------------------------------------------------*/
|
||||
#define MMCR1_PMC3_HOLD 0x00000000 // Register holds current value
|
||||
#define MMCR1_PMC3_CYCLE 0x08000000 // Processor cycles
|
||||
#define MMCR1_PMC3_INSTRUCTION 0x10000000 // # of instructions completed
|
||||
#define MMCR1_PMC3_TRANSITION 0x18000000 // # of time-base (lower) bit transitions
|
||||
#define MMCR1_PMC3_DISPATCHED 0x20000000 // # of instructions dispatched
|
||||
#define MMCR1_PMC3_DC_MISS 0x28000000 // # of L1 data cache misses
|
||||
#define MMCR1_PMC3_DTLB_MISS 0x30000000 // # of DTLB misses
|
||||
#define MMCR1_PMC3_L2_D_MISS 0x38000000 // # of L2 data misses
|
||||
#define MMCR1_PMC3_Bx_TAKEN 0x40000000 // # predicted branches that were taken
|
||||
#define MMCR1_PMC3_PM_SWITCH 0x48000000 // # of transitions between marked and unmarked processes
|
||||
#define MMCR1_PMC3_COND_STORE 0x50000000 // # of store conditional instructions completed
|
||||
#define MMCR1_PMC3_FPU 0x58000000 // # of instructions completed from the FPU
|
||||
#define MMCR1_PMC3_L2_SNOOP_CASTOUT 0x60000000 // # of L2 castout caused by snoops to modified lines
|
||||
#define MMCR1_PMC3_L2_HIT 0x68000000 // # of cache operations that hit in the L2 cache
|
||||
#define MMCR1_PMC3_L1_MISS_CYCLE 0x78000000 // # of cycles generated by L1 load misses
|
||||
#define MMCR1_PMC3_Bx_SECOND 0x80000000 // # of branches in the second speculative branch
|
||||
// resolved correctly
|
||||
#define MMCR1_PMC3_BPU_LR_CR 0x88000000 // # of cycles the BPU stalls due to LR or CR unresolved
|
||||
// dependencies
|
||||
|
||||
#define MMCR1_PMC4_HOLD 0x00000000 // Register holds current value
|
||||
#define MMCR1_PMC4_CYCLE 0x00400000 // Processor cycles
|
||||
#define MMCR1_PMC4_INSTRUCTION 0x00800000 // # of instructions completed
|
||||
#define MMCR1_PMC4_TRANSITION 0x00C00000 // # of time-base (lower) bit transitions
|
||||
#define MMCR1_PMC4_DISPATCHED 0x01000000 // # of instructions dispatched
|
||||
#define MMCR1_PMC4_L2_CASTOUT 0x01400000 // # of L2 castouts
|
||||
#define MMCR1_PMC4_DTLB_CYCLE 0x01800000 // # of cycles spent performing table searches for DTLB accesses
|
||||
#define MMCR1_PMC4_Bx_MISSED 0x02000000 // # of mispredicted branches
|
||||
#define MMCR1_PMC4_COND_STORE_INT 0x02800000 // # of store conditional instructions completed
|
||||
// with reservation intact
|
||||
#define MMCR1_PMC4_SYNC 0x02C00000 // # of completed sync instructions
|
||||
#define MMCR1_PMC4_SNOOP_RETRY 0x03000000 // # of snoop request retries
|
||||
#define MMCR1_PMC4_INTEGER 0x03400000 // # of completed integer operations
|
||||
#define MMCR1_PMC4_BPU_THIRD 0x03800000 // # of cycles the BPU cannot process new branches
|
||||
// due to having two unresolved branches
|
||||
#define MMCR1_PMC4_DC_MISS 0x07C00000 // # of L1 data cache misses
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
FPSCR bits
|
||||
*---------------------------------------------------------------------------*/
|
||||
#ifndef FPSCR_FX
|
||||
#define FPSCR_FX 0x80000000 // Exception summary
|
||||
#define FPSCR_FEX 0x40000000 // Enabled exception summary
|
||||
#define FPSCR_VX 0x20000000 // Invalid operation
|
||||
#define FPSCR_OX 0x10000000 // Overflow exception
|
||||
#define FPSCR_UX 0x08000000 // Underflow exception
|
||||
#define FPSCR_ZX 0x04000000 // Zero divide exception
|
||||
#define FPSCR_XX 0x02000000 // Inexact exception
|
||||
#define FPSCR_VXSNAN 0x01000000 // SNaN
|
||||
#define FPSCR_VXISI 0x00800000 // Infinity - Infinity
|
||||
#define FPSCR_VXIDI 0x00400000 // Infinity / Infinity
|
||||
#define FPSCR_VXZDZ 0x00200000 // 0 / 0
|
||||
#define FPSCR_VXIMZ 0x00100000 // Infinity * 0
|
||||
#define FPSCR_VXVC 0x00080000 // Invalid compare
|
||||
#define FPSCR_FR 0x00040000 // Fraction rounded
|
||||
#define FPSCR_FI 0x00020000 // Fraction inexact
|
||||
#define FPSCR_VXSOFT 0x00000400 // Software request
|
||||
#define FPSCR_VXSQRT 0x00000200 // Invalid square root
|
||||
#define FPSCR_VXCVI 0x00000100 // Invalid integer convert
|
||||
#define FPSCR_VE 0x00000080 // Invalid operation exception enable
|
||||
#define FPSCR_OE 0x00000040 // Overflow exception enable
|
||||
#define FPSCR_UE 0x00000020 // Underflow exception enable
|
||||
#define FPSCR_ZE 0x00000010 // Zero divide exception enable
|
||||
#define FPSCR_XE 0x00000008 // Inexact exception enable
|
||||
#define FPSCR_NI 0x00000004 // Non-IEEE mode
|
||||
#endif
|
||||
|
||||
#ifndef FPSCR_FX_BIT
|
||||
#define FPSCR_FX_BIT 0 // Exception summary
|
||||
#define FPSCR_FEX_BIT 1 // Enabled exception summary
|
||||
#define FPSCR_VX_BIT 2 // Invalid operation
|
||||
#define FPSCR_OX_BIT 3 // Overflow exception
|
||||
#define FPSCR_UX_BIT 4 // Underflow exception
|
||||
#define FPSCR_ZX_BIT 5 // Zero divide exception
|
||||
#define FPSCR_XX_BIT 6 // Inexact exception
|
||||
#define FPSCR_VXSNAN_BIT 7 // SNaN
|
||||
#define FPSCR_VXISI_BIT 8 // Infinity - Infinity
|
||||
#define FPSCR_VXIDI_BIT 9 // Infinity / Infinity
|
||||
#define FPSCR_VXZDZ_BIT 10 // 0 / 0
|
||||
#define FPSCR_VXIMZ_BIT 11 // Infinity * 0
|
||||
#define FPSCR_VXVC_BIT 12 // Invalid compare
|
||||
#define FPSCR_FR_BIT 13 // Fraction rounded
|
||||
#define FPSCR_FI_BIT 14 // Fraction inexact
|
||||
#define FPSCR_VXSOFT_BIT 21 // Software request
|
||||
#define FPSCR_VXSQRT_BIT 22 // Invalid square root
|
||||
#define FPSCR_VXCVI_BIT 23 // Invalid integer convert
|
||||
#define FPSCR_VE_BIT 24 // Invalid operation exception enable
|
||||
#define FPSCR_OE_BIT 25 // Overflow exception enable
|
||||
#define FPSCR_UE_BIT 26 // Underflow exception enable
|
||||
#define FPSCR_ZE_BIT 27 // Zero divide exception enable
|
||||
#define FPSCR_XE_BIT 28 // Inexact exception enable
|
||||
#define FPSCR_NI_BIT 29 // Non-IEEE mode
|
||||
#endif
|
||||
|
||||
union FpscrUnion {
|
||||
f64 f;
|
||||
struct {
|
||||
u32 fpscr_pad;
|
||||
u32 fpscr;
|
||||
} u;
|
||||
};
|
||||
|
||||
// PPCArch
|
||||
u32 PPCMfmsr();
|
||||
void PPCMtmsr(u32 newMSR);
|
||||
u32 PPCOrMsr(u32 value);
|
||||
u32 PPCMfhid0();
|
||||
void PPCMthid0(u32 newHID0);
|
||||
u32 PPCMfl2cr();
|
||||
void PPCMtl2cr(u32 newL2cr);
|
||||
void PPCMtdec(u32 newDec);
|
||||
void PPCSync();
|
||||
void PPCHalt();
|
||||
u32 PPCMffpscr();
|
||||
void PPCMtfpscr(u32 newFPSCR);
|
||||
u32 PPCMfhid2();
|
||||
void PPCMthid2(u32 newhid2);
|
||||
u32 PPCMfwpar();
|
||||
void PPCMtwpar(u32 newwpar);
|
||||
void PPCEnableSpeculation();
|
||||
void PPCDisableSpeculation();
|
||||
void PPCSetFpIEEEMode();
|
||||
void PPCSetFpNonIEEEMode();
|
||||
u32 PPCMfpmc4();
|
||||
u32 PPCMfpmc3();
|
||||
u32 PPCMfpmc1();
|
||||
void PPCMtpmc1(u32 newPmc1);
|
||||
void PPCMtpmc2(u32 newPmc1);
|
||||
void PPCMtpmc3(u32 newPmc1);
|
||||
void PPCMtpmc4(u32 newPmc1);
|
||||
void PPCMtmmcr0(u32 newMmcr0);
|
||||
void PPCMtmmcr1(u32 newMmcr0);
|
||||
void PPCMtdmaU(u32 newdmau);
|
||||
void PPCMtdmaL(u32 newdmal);
|
||||
u32 PPCMfdec(void);
|
||||
u32 PPCMfpmc2(void);
|
||||
u32 PPCAndMsr(u32 value);
|
||||
u32 PPCAndCMsr(u32 value);
|
||||
u32 PPCMfhid1();
|
||||
void PPCEieio();
|
||||
u32 PPCMfmmcr0();
|
||||
u32 PPCMfmmcr1();
|
||||
u32 PPCMfpmc2();
|
||||
u32 PPCMfsia();
|
||||
void PPCMtsia(u32 newSia);
|
||||
u32 PPCMfdmaL();
|
||||
u32 PPCMfpvr();
|
||||
u32 PPCMfdmaU();
|
||||
|
||||
// PPCPm
|
||||
void PMBegin(void);
|
||||
void PMEnd(void);
|
||||
void PMCycles(void);
|
||||
void PML1FetchMisses(void);
|
||||
void PML1MissCycles(void);
|
||||
void PMInstructions(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _DOLPHIN_PPCARCH
|
||||
@@ -1,340 +0,0 @@
|
||||
#ifndef _DOLPHIN_CARD_H_
|
||||
#define _DOLPHIN_CARD_H_
|
||||
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CARD_FILENAME_MAX 32
|
||||
#define CARD_MAX_FILE 127
|
||||
#define CARD_ICON_MAX 8
|
||||
|
||||
#if TARGET_PC
|
||||
|
||||
typedef enum {
|
||||
CARD_RAWIMAGE,
|
||||
CARD_GCIFOLDER,
|
||||
} CARDFileType;
|
||||
|
||||
#endif
|
||||
|
||||
typedef void (*CARDCallback)(s32 chan, s32 result);
|
||||
|
||||
typedef struct CARDFileInfo {
|
||||
s32 chan;
|
||||
s32 fileNo;
|
||||
s32 offset;
|
||||
s32 length;
|
||||
u16 iBlock;
|
||||
} CARDFileInfo;
|
||||
|
||||
typedef struct CARDDir {
|
||||
u8 gameName[4];
|
||||
u8 company[2];
|
||||
u8 _padding0;
|
||||
u8 bannerFormat;
|
||||
u8 fileName[CARD_FILENAME_MAX];
|
||||
u32 time; // seconds since 01/01/2000 midnight
|
||||
u32 iconAddr; // 0xffffffff if not used
|
||||
u16 iconFormat;
|
||||
u16 iconSpeed;
|
||||
u8 permission;
|
||||
u8 copyTimes;
|
||||
u16 startBlock;
|
||||
u16 length;
|
||||
u8 _padding1[2];
|
||||
u32 commentAddr; // 0xffffffff if not used
|
||||
} CARDDir;
|
||||
|
||||
typedef struct CARDControl {
|
||||
/* 0x000 */ BOOL attached;
|
||||
/* 0x004 */ s32 result;
|
||||
/* 0x008 */ u16 size;
|
||||
/* 0x00A */ u16 pageSize;
|
||||
/* 0x00C */ s32 sectorSize;
|
||||
/* 0x010 */ u16 cBlock;
|
||||
/* 0x012 */ u16 vendorID;
|
||||
/* 0x014 */ s32 latency;
|
||||
/* 0x018 */ u8 id[12];
|
||||
/* 0x024 */ int mountStep;
|
||||
/* 0x028 */ int formatStep;
|
||||
/* 0x028 */ u32 scramble;
|
||||
/* 0x02C */ DSPTaskInfo task;
|
||||
/* 0x080 */ void* workArea;
|
||||
/* 0x084 */ CARDDir *currentDir;
|
||||
/* 0x088 */ u16* currentFat;
|
||||
/* 0x08C */ OSThreadQueue threadQueue;
|
||||
/* 0x094 */ u8 cmd[9];
|
||||
/* 0x0A0 */ s32 cmdlen;
|
||||
/* 0x0A4 */ volatile u32 mode;
|
||||
/* 0x0A8 */ int retry;
|
||||
/* 0x0AC */ int repeat;
|
||||
/* 0x0B0 */ u32 addr;
|
||||
/* 0x0B4 */ void* buffer;
|
||||
/* 0x0B8 */ s32 xferred;
|
||||
/* 0x0BC */ u16 freeNo;
|
||||
/* 0x0BE */ u16 startBlock;
|
||||
/* 0x0C0 */ CARDFileInfo* fileInfo;
|
||||
/* 0x0C4 */ CARDCallback extCallback;
|
||||
/* 0x0C8 */ CARDCallback txCallback;
|
||||
/* 0x0CC */ CARDCallback exiCallback;
|
||||
/* 0x0D0 */ CARDCallback apiCallback;
|
||||
/* 0x0D4 */ CARDCallback xferCallback;
|
||||
/* 0x0D8 */ CARDCallback eraseCallback;
|
||||
/* 0x0DC */ CARDCallback unlockCallback;
|
||||
/* 0x0E0 */ OSAlarm alarm;
|
||||
/* 0x108 */ u32 cid;
|
||||
/* 0x10C */ const DVDDiskID* diskID;
|
||||
} CARDControl;
|
||||
|
||||
typedef struct CARDDecParam {
|
||||
/* 0x00 */ u8* inputAddr;
|
||||
/* 0x04 */ u32 inputLength;
|
||||
/* 0x08 */ u32 aramAddr;
|
||||
/* 0x0C */ u8* outputAddr;
|
||||
} CARDDecParam;
|
||||
|
||||
typedef struct CARDID {
|
||||
/* 0x000 */ u8 serial[32];
|
||||
/* 0x020 */ u16 deviceID;
|
||||
/* 0x022 */ u16 size;
|
||||
/* 0x024 */ u16 encode;
|
||||
/* 0x026 */ u8 padding[470];
|
||||
/* 0x1FC */ u16 checkSum;
|
||||
/* 0x1FE */ u16 checkSumInv;
|
||||
} CARDID;
|
||||
|
||||
typedef struct CARDDirCheck {
|
||||
/* 0x00 */ u8 padding0[56];
|
||||
/* 0x38 */ u16 padding1;
|
||||
/* 0x3A */ s16 checkCode;
|
||||
/* 0x3C */ u16 checkSum;
|
||||
/* 0x3E */ u16 checkSumInv;
|
||||
} CARDDirCheck;
|
||||
|
||||
typedef struct CARDStat {
|
||||
/* 0x00 */ char fileName[CARD_FILENAME_MAX];
|
||||
/* 0x20 */ u32 length;
|
||||
/* 0x24 */ u32 time;
|
||||
/* 0x28 */ u8 gameName[4];
|
||||
/* 0x2C */ u8 company[2];
|
||||
/* 0x2E */ u8 bannerFormat;
|
||||
/* 0x30 */ u32 iconAddr;
|
||||
/* 0x34 */ u16 iconFormat;
|
||||
/* 0x36 */ u16 iconSpeed;
|
||||
/* 0x38 */ u32 commentAddr;
|
||||
/* 0x3C */ u32 offsetBanner;
|
||||
/* 0x40 */ u32 offsetBannerTlut;
|
||||
/* 0x44 */ u32 offsetIcon[CARD_ICON_MAX];
|
||||
/* 0x64 */ u32 offsetIconTlut;
|
||||
/* 0x68 */ u32 offsetData;
|
||||
} CARDStat;
|
||||
|
||||
#define CARD_ATTR_PUBLIC 0x04u
|
||||
#define CARD_ATTR_NO_COPY 0x08u
|
||||
#define CARD_ATTR_NO_MOVE 0x10u
|
||||
#define CARD_ATTR_GLOBAL 0x20u
|
||||
#define CARD_ATTR_COMPANY 0x40u
|
||||
|
||||
#define CARD_FAT_AVAIL 0x0000u
|
||||
#define CARD_FAT_CHECKSUM 0x0000u
|
||||
#define CARD_FAT_CHECKSUMINV 0x0001u
|
||||
#define CARD_FAT_CHECKCODE 0x0002u
|
||||
#define CARD_FAT_FREEBLOCKS 0x0003u
|
||||
#define CARD_FAT_LASTSLOT 0x0004u
|
||||
|
||||
#define CARD_WORKAREA_SIZE (5 * 8 * 1024)
|
||||
|
||||
#define CARD_SEG_SIZE 0x200u
|
||||
#define CARD_PAGE_SIZE 0x80u
|
||||
#define CARD_MAX_SIZE 0x01000000U
|
||||
|
||||
#define CARD_NUM_SYSTEM_BLOCK 5
|
||||
#define CARD_SYSTEM_BLOCK_SIZE (8 * 1024u)
|
||||
|
||||
#define CARD_MAX_MOUNT_STEP (CARD_NUM_SYSTEM_BLOCK + 2)
|
||||
|
||||
#define CARD_STAT_SPEED_END 0
|
||||
#define CARD_STAT_SPEED_FAST 1
|
||||
#define CARD_STAT_SPEED_MIDDLE 2
|
||||
#define CARD_STAT_SPEED_SLOW 3
|
||||
#define CARD_STAT_SPEED_MASK 3
|
||||
|
||||
#define CARD_STAT_ANIM_LOOP 0
|
||||
#define CARD_STAT_ANIM_BOUNCE 4
|
||||
#define CARD_STAT_ANIM_MASK 0x4
|
||||
|
||||
#define CARD_RESULT_UNLOCKED 1
|
||||
#define CARD_RESULT_READY 0
|
||||
#define CARD_RESULT_BUSY -1
|
||||
#define CARD_RESULT_WRONGDEVICE -2
|
||||
#define CARD_RESULT_NOCARD -3
|
||||
#define CARD_RESULT_NOFILE -4
|
||||
#define CARD_RESULT_IOERROR -5
|
||||
#define CARD_RESULT_BROKEN -6
|
||||
#define CARD_RESULT_EXIST -7
|
||||
#define CARD_RESULT_NOENT -8
|
||||
#define CARD_RESULT_INSSPACE -9
|
||||
#define CARD_RESULT_NOPERM -10
|
||||
#define CARD_RESULT_LIMIT -11
|
||||
#define CARD_RESULT_NAMETOOLONG -12
|
||||
#define CARD_RESULT_ENCODING -13
|
||||
#define CARD_RESULT_CANCELED -14
|
||||
#define CARD_RESULT_FATAL_ERROR -128
|
||||
|
||||
#define CARDIsValidBlockNo(card, blockNo) ((blockNo) >= CARD_NUM_SYSTEM_BLOCK && (blockNo) < (card)->cBlock)
|
||||
|
||||
#define CARD_READ_SIZE 512
|
||||
|
||||
#define CARD_COMMENT_SIZE 64
|
||||
|
||||
#define CARD_ICON_WIDTH 32
|
||||
#define CARD_ICON_HEIGHT 32
|
||||
|
||||
#define CARD_BANNER_WIDTH 96
|
||||
#define CARD_BANNER_HEIGHT 32
|
||||
|
||||
#define CARD_STAT_ICON_NONE 0
|
||||
#define CARD_STAT_ICON_C8 1
|
||||
#define CARD_STAT_ICON_RGB5A3 2
|
||||
#define CARD_STAT_ICON_MASK 3
|
||||
|
||||
#define CARD_STAT_BANNER_NONE 0
|
||||
#define CARD_STAT_BANNER_C8 1
|
||||
#define CARD_STAT_BANNER_RGB5A3 2
|
||||
#define CARD_STAT_BANNER_MASK 3
|
||||
|
||||
#define CARD_ENCODE_ANSI 0
|
||||
#define CARD_ENCODE_SJIS 1
|
||||
|
||||
#define CARDGetDirCheck(dir) ((CARDDirCheck*)&(dir)[CARD_MAX_FILE])
|
||||
#define CARDGetBannerFormat(stat) (((stat)->bannerFormat) & CARD_STAT_BANNER_MASK)
|
||||
#define CARDGetIconAnim(stat) (((stat)->bannerFormat) & CARD_STAT_ANIM_MASK)
|
||||
#define CARDGetIconFormat(stat, n) (((stat)->iconFormat >> (2 * (n))) & CARD_STAT_ICON_MASK)
|
||||
#define CARDGetIconSpeed(stat, n) (((stat)->iconSpeed >> (2 * (n))) & CARD_STAT_SPEED_MASK)
|
||||
#define CARDSetBannerFormat(stat, f) \
|
||||
((stat)->bannerFormat = (u8)(((stat)->bannerFormat & ~CARD_STAT_BANNER_MASK) | (f)))
|
||||
#define CARDSetIconAnim(stat, f) \
|
||||
((stat)->bannerFormat = (u8)(((stat)->bannerFormat & ~CARD_STAT_ANIM_MASK) | (f)))
|
||||
#define CARDSetIconFormat(stat, n, f) \
|
||||
((stat)->iconFormat = \
|
||||
(u16)(((stat)->iconFormat & ~(CARD_STAT_ICON_MASK << (2 * (n)))) | ((f) << (2 * (n)))))
|
||||
#define CARDSetIconSpeed(stat, n, f) \
|
||||
((stat)->iconSpeed = \
|
||||
(u16)(((stat)->iconSpeed & ~(CARD_STAT_SPEED_MASK << (2 * (n)))) | ((f) << (2 * (n)))))
|
||||
#define CARDSetIconAddress(stat, addr) ((stat)->iconAddr = (u32)(addr))
|
||||
#define CARDSetCommentAddress(stat, addr) ((stat)->commentAddr = (u32)(addr))
|
||||
#define CARDGetFileNo(fileInfo) ((fileInfo)->fileNo)
|
||||
|
||||
extern u32 __CARDFreq;
|
||||
|
||||
#if DEBUG
|
||||
#define CARDFreq __CARDFreq
|
||||
#else
|
||||
#define CARDFreq EXI_FREQ_16M
|
||||
#endif
|
||||
|
||||
s32 CARDRenameAsync(s32 chan, const char* oldName, const char* newName, CARDCallback callback);
|
||||
|
||||
// CARDBios
|
||||
#if TARGET_PC
|
||||
void CARDInit(const char* game, const char* maker);
|
||||
void CARDSetGameAndMaker(const s32 chan, const char* game, const char* maker);
|
||||
|
||||
// pass -1 to set both
|
||||
void CARDDetectDolphin(s32 chan);
|
||||
// pass -1 to set both
|
||||
void CARDSetBasePath(const char*, s32 chan);
|
||||
void CARDSetLoadType(CARDFileType type);
|
||||
|
||||
#else
|
||||
void CARDInit(void);
|
||||
#endif
|
||||
s32 CARDGetResultCode(s32 chan);
|
||||
s32 CARDFreeBlocks(s32 chan, s32* byteNotUsed, s32* filesNotUsed);
|
||||
s32 CARDGetEncoding(s32 chan, u16* encode);
|
||||
s32 CARDGetMemSize(s32 chan, u16* size);
|
||||
s32 CARDGetSectorSize(s32 chan, u32* size);
|
||||
const DVDDiskID* CARDGetDiskID(s32 chan);
|
||||
s32 CARDSetDiskID(s32 chan, const DVDDiskID* diskID);
|
||||
BOOL CARDSetFastMode(BOOL enable);
|
||||
BOOL CARDGetFastMode(void);
|
||||
s32 CARDGetCurrentMode(s32 chan, u32* mode);
|
||||
|
||||
// CARDCheck
|
||||
s32 CARDCheckExAsync(s32 chan, s32* xferBytes, CARDCallback callback);
|
||||
s32 CARDCheckAsync(s32 chan, CARDCallback callback);
|
||||
s32 CARDCheckEx(s32 chan, s32* xferBytes);
|
||||
s32 CARDCheck(s32 chan);
|
||||
|
||||
// CARDCreate
|
||||
s32 CARDCreateAsync(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo, CARDCallback callback);
|
||||
s32 CARDCreate(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo);
|
||||
|
||||
// CARDDelete
|
||||
s32 CARDFastDeleteAsync(s32 chan, s32 fileNo, CARDCallback callback);
|
||||
s32 CARDFastDelete(s32 chan, s32 fileNo);
|
||||
s32 CARDDeleteAsync(s32 chan, const char* fileName, CARDCallback callback);
|
||||
s32 CARDDelete(s32 chan, const char* fileName);
|
||||
|
||||
// CARDErase
|
||||
s32 CARDEraseAsync(CARDFileInfo* fileInfo, s32 length, s32 offset, CARDCallback callback);
|
||||
s32 CARDErase(CARDFileInfo* fileInfo, s32 length, s32 offset);
|
||||
|
||||
// CARDFormat
|
||||
s32 CARDFormat(s32 chan);
|
||||
|
||||
// CARDMount
|
||||
int CARDProbe(s32 chan);
|
||||
s32 CARDProbeEx(s32 chan, s32* memSize, s32* sectorSize);
|
||||
s32 CARDMountAsync(s32 chan, void* workArea, CARDCallback detachCallback, CARDCallback attachCallback);
|
||||
s32 CARDMount(s32 chan, void* workArea, CARDCallback detachCallback);
|
||||
s32 CARDUnmount(s32 chan);
|
||||
|
||||
// CARDNet
|
||||
u16 CARDSetVendorID(u16 vendorID);
|
||||
u16 CARDGetVendorID();
|
||||
s32 CARDGetSerialNo(s32 chan, u64* serialNo);
|
||||
s32 CARDGetUniqueCode(s32 chan, u64* uniqueCode);
|
||||
s32 CARDGetAttributes(s32 chan, s32 fileNo, u8* attr);
|
||||
s32 CARDSetAttributesAsync(s32 chan, s32 fileNo, u8 attr, CARDCallback callback);
|
||||
s32 CARDSetAttributes(s32 chan, s32 fileNo, u8 attr);
|
||||
|
||||
// CARDOpen
|
||||
s32 CARDFastOpen(s32 chan, s32 fileNo, CARDFileInfo* fileInfo);
|
||||
s32 CARDOpen(s32 chan, const char* fileName, CARDFileInfo* fileInfo);
|
||||
s32 CARDClose(CARDFileInfo* fileInfo);
|
||||
|
||||
// CARDProgram
|
||||
s32 CARDProgramAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback);
|
||||
s32 CARDProgram(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset);
|
||||
|
||||
// CARDRdwr
|
||||
s32 CARDGetXferredBytes(s32 chan);
|
||||
|
||||
// CARDRead
|
||||
s32 CARDReadAsync(const CARDFileInfo* fileInfo, void* addr, s32 length, s32 offset, CARDCallback callback);
|
||||
s32 CARDRead(const CARDFileInfo* fileInfo, void* addr, s32 length, s32 offset);
|
||||
s32 CARDCancel(CARDFileInfo* fileInfo);
|
||||
|
||||
// CARDRename
|
||||
s32 CARDRename(s32 chan, const char* oldName, const char* newName);
|
||||
|
||||
// CARDStat
|
||||
s32 CARDGetStatus(s32 chan, s32 fileNo, CARDStat* stat);
|
||||
s32 CARDSetStatusAsync(s32 chan, s32 fileNo, const CARDStat* stat, CARDCallback callback);
|
||||
s32 CARDSetStatus(s32 chan, s32 fileNo, const CARDStat* stat);
|
||||
|
||||
// CARDWrite
|
||||
s32 CARDWriteAsync(const CARDFileInfo* fileInfo, const void* addr, s32 length, s32 offset, CARDCallback callback);
|
||||
s32 CARDWrite(const CARDFileInfo* fileInfo, const void* addr, s32 length, s32 offset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef _DOLPHIN_DB_H_
|
||||
#define _DOLPHIN_DB_H_
|
||||
|
||||
#include <dolphin/types.h>
|
||||
#include <dolphin/db/DBInterface.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OS_DBINTERFACE_ADDR 0x00000040
|
||||
|
||||
BOOL DBIsDebuggerPresent(void);
|
||||
void DBPrintf(char* str, ...);
|
||||
s32 DBQueryData(void);
|
||||
u32 DBRead(u8*, u32);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _DOLPHIN_DB_H_
|
||||
@@ -1,31 +0,0 @@
|
||||
#ifndef _DOLPHIN_DBINTERFACE_H_
|
||||
#define _DOLPHIN_DBINTERFACE_H_
|
||||
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct DBInterface {
|
||||
u32 bPresent;
|
||||
u32 exceptionMask;
|
||||
void (*ExceptionDestination)(void);
|
||||
void* exceptionReturn;
|
||||
} DBInterface;
|
||||
|
||||
extern DBInterface* __DBInterface;
|
||||
|
||||
void DBInit(void);
|
||||
void DBInitComm(int* inputFlagPtr, int* mtrCallback);
|
||||
void __DBExceptionDestination(void);
|
||||
void __DBExceptionDestinationAux(void);
|
||||
BOOL __DBIsExceptionMarked(__OSException exception);
|
||||
void __DBMarkException(u8 exception, int value);
|
||||
void __DBSetPresent(u32 value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef _DOLPHIN_H_
|
||||
#define _DOLPHIN_H_
|
||||
|
||||
#include <dolphin/types.h>
|
||||
#include <dolphin/os.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/gx.h>
|
||||
#include <dolphin/hio.h>
|
||||
#include <dolphin/mtx.h>
|
||||
#include <dolphin/vi.h>
|
||||
#include <dolphin/card.h>
|
||||
#include <dolphin/perf.h>
|
||||
#include <dolphin/ar.h>
|
||||
#include <dolphin/base/PPCArch.h>
|
||||
#include <dolphin/db.h>
|
||||
#include <dolphin/pad.h>
|
||||
#include <dolphin/dtk.h>
|
||||
#include <dolphin/ai.h>
|
||||
// #include <dolphin/demo.h>
|
||||
#include <dolphin/exi.h>
|
||||
#include <dolphin/si.h>
|
||||
|
||||
#endif
|
||||
@@ -1,57 +0,0 @@
|
||||
#ifndef _DOLPHIN_DSP_H_
|
||||
#define _DOLPHIN_DSP_H_
|
||||
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*DSPCallback)(void* task);
|
||||
typedef struct STRUCT_DSP_TASK DSPTaskInfo;
|
||||
|
||||
typedef struct STRUCT_DSP_TASK {
|
||||
/* 0x00 */ volatile u32 state;
|
||||
/* 0x04 */ volatile u32 priority;
|
||||
/* 0x08 */ volatile u32 flags;
|
||||
/* 0x0C */ u16* iram_mmem_addr;
|
||||
/* 0x10 */ u32 iram_length;
|
||||
/* 0x14 */ u32 iram_addr;
|
||||
/* 0x18 */ u16* dram_mmem_addr;
|
||||
/* 0x1C */ u32 dram_length;
|
||||
/* 0x20 */ u32 dram_addr;
|
||||
/* 0x24 */ u16 dsp_init_vector;
|
||||
/* 0x26 */ u16 dsp_resume_vector;
|
||||
/* 0x28 */ DSPCallback init_cb;
|
||||
/* 0x2C */ DSPCallback res_cb;
|
||||
/* 0x30 */ DSPCallback done_cb;
|
||||
/* 0x34 */ DSPCallback req_cb;
|
||||
/* 0x38 */ DSPTaskInfo* next;
|
||||
/* 0x3C */ DSPTaskInfo* prev;
|
||||
/* 0x40 */ OSTime t_context;
|
||||
/* 0x48 */ OSTime t_task;
|
||||
} DSPTaskInfo;
|
||||
|
||||
u32 DSPCheckMailToDSP(void);
|
||||
u32 DSPCheckMailFromDSP(void);
|
||||
u32 DSPReadCPUToDSPMbox(void);
|
||||
u32 DSPReadMailFromDSP(void);
|
||||
void DSPSendMailToDSP(u32 mail);
|
||||
void DSPAssertInt(void);
|
||||
void DSPInit(void);
|
||||
BOOL DSPCheckInit(void);
|
||||
void DSPReset(void);
|
||||
void DSPHalt(void);
|
||||
void DSPUnhalt(void);
|
||||
u32 DSPGetDMAStatus(void);
|
||||
DECL_WEAK DSPTaskInfo* DSPAddTask(DSPTaskInfo* task);
|
||||
DSPTaskInfo* DSPCancelTask(DSPTaskInfo* task);
|
||||
DSPTaskInfo* DSPAssertTask(DSPTaskInfo* task);
|
||||
|
||||
DSPTaskInfo* __DSPGetCurrentTask(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef _DOLPHIN_DTK_H_
|
||||
#define _DOLPHIN_DTK_H_
|
||||
|
||||
#include <dolphin/dvd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*DTKCallback)(u32 eventMask);
|
||||
typedef void (*DTKFlushCallback)(void);
|
||||
|
||||
typedef struct DTKTrack {
|
||||
/* 0x00 */ struct DTKTrack* prev;
|
||||
/* 0x04 */ struct DTKTrack* next;
|
||||
/* 0x08 */ char* fileName;
|
||||
/* 0x0C */ u32 eventMask;
|
||||
/* 0x10 */ DTKCallback callback;
|
||||
/* 0x14 */ DVDFileInfo dvdFileInfo;
|
||||
} DTKTrack;
|
||||
|
||||
#define DTK_STATE_STOP 0
|
||||
#define DTK_STATE_RUN 1
|
||||
#define DTK_STATE_PAUSE 2
|
||||
#define DTK_STATE_BUSY 3
|
||||
#define DTK_STATE_PREPARE 4
|
||||
|
||||
#define DTK_MODE_NOREPEAT 0
|
||||
#define DTK_MODE_ALLREPEAT 1
|
||||
#define DTK_MODE_REPEAT1 2
|
||||
|
||||
void DTKInit(void);
|
||||
void DTKShutdown(void);
|
||||
u32 DTKQueueTrack(char* fileName, DTKTrack* track, u32 eventMask, DTKCallback callback);
|
||||
u32 DTKRemoveTrack(DTKTrack* track);
|
||||
int DTKFlushTracks(DTKFlushCallback callback);
|
||||
void DTKSetSampleRate(u32 samplerate);
|
||||
void DTKSetInterruptFrequency(u32 samples);
|
||||
void DTKSetRepeatMode(u32 repeat);
|
||||
int DTKSetState(u32 state);
|
||||
int DTKNextTrack(void);
|
||||
int DTKPrevTrack(void);
|
||||
u32 DTKGetSampleRate(void);
|
||||
u32 DTKGetRepeatMode(void);
|
||||
u32 DTKGetState(void);
|
||||
u32 DTKGetPosition(void);
|
||||
u32 DTKGetInterruptFrequency(void);
|
||||
DTKTrack* DTKGetCurrentTrack(void);
|
||||
void DTKSetVolume(u8 left, u8 right);
|
||||
u16 DTKGetVolume(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,237 +0,0 @@
|
||||
#ifndef _DOLPHIN_DVD_H_
|
||||
#define _DOLPHIN_DVD_H_
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DVD_ASSERTMSGLINE(line, cond, msg) \
|
||||
if (!(cond)) \
|
||||
OSPanic(__FILE__, line, msg)
|
||||
|
||||
#define DVD_ASSERTMSG1LINE(line, cond, msg, arg1) \
|
||||
if (!(cond)) \
|
||||
OSPanic(__FILE__, line, msg, arg1)
|
||||
|
||||
#define DVD_ASSERTMSG2LINE(line, cond, msg, arg1, arg2) \
|
||||
if (!(cond)) \
|
||||
OSPanic(__FILE__, line, msg, arg1, arg2)
|
||||
|
||||
#define DVD_RESULT_GOOD 0
|
||||
#define DVD_RESULT_FATAL_ERROR -1
|
||||
#define DVD_RESULT_IGNORED -2
|
||||
#define DVD_RESULT_CANCELED -6
|
||||
|
||||
#define DVD_STATE_FATAL_ERROR -1
|
||||
#define DVD_STATE_END 0
|
||||
#define DVD_STATE_BUSY 1
|
||||
#define DVD_STATE_WAITING 2
|
||||
#define DVD_STATE_COVER_CLOSED 3
|
||||
#define DVD_STATE_NO_DISK 4
|
||||
#define DVD_STATE_COVER_OPEN 5
|
||||
#define DVD_STATE_WRONG_DISK 6
|
||||
#define DVD_STATE_MOTOR_STOPPED 7
|
||||
#define DVD_STATE_PAUSING 8
|
||||
#define DVD_STATE_IGNORED 9
|
||||
#define DVD_STATE_CANCELED 10
|
||||
#define DVD_STATE_RETRY 11
|
||||
|
||||
#define DVD_MIN_TRANSFER_SIZE 32
|
||||
|
||||
// could be bitfields
|
||||
#define DVD_INTTYPE_TC 1
|
||||
#define DVD_INTTYPE_DE 2
|
||||
// unk type 3
|
||||
#define DVD_INTTYPE_CVR 4
|
||||
|
||||
// DVD Commands
|
||||
#define DVD_COMMAND_NONE 0
|
||||
#define DVD_COMMAND_READ 1
|
||||
#define DVD_COMMAND_SEEK 2
|
||||
#define DVD_COMMAND_CHANGE_DISK 3
|
||||
#define DVD_COMMAND_BSREAD 4
|
||||
#define DVD_COMMAND_READID 5
|
||||
#define DVD_COMMAND_INITSTREAM 6
|
||||
#define DVD_COMMAND_CANCELSTREAM 7
|
||||
#define DVD_COMMAND_STOP_STREAM_AT_END 8
|
||||
#define DVD_COMMAND_REQUEST_AUDIO_ERROR 9
|
||||
#define DVD_COMMAND_REQUEST_PLAY_ADDR 10
|
||||
#define DVD_COMMAND_REQUEST_START_ADDR 11
|
||||
#define DVD_COMMAND_REQUEST_LENGTH 12
|
||||
#define DVD_COMMAND_AUDIO_BUFFER_CONFIG 13
|
||||
#define DVD_COMMAND_INQUIRY 14
|
||||
#define DVD_COMMAND_BS_CHANGE_DISK 15
|
||||
#define DVD_COMMAND_UNK_16 16
|
||||
|
||||
typedef struct DVDDiskID {
|
||||
char gameName[4];
|
||||
char company[2];
|
||||
u8 diskNumber;
|
||||
u8 gameVersion;
|
||||
u8 streaming;
|
||||
u8 streamingBufSize;
|
||||
u8 padding[22];
|
||||
} DVDDiskID;
|
||||
|
||||
typedef struct DVDCommandBlock DVDCommandBlock;
|
||||
typedef void (*DVDCBCallback)(s32 result, DVDCommandBlock* block);
|
||||
typedef void (*DVDLowCallback)(u32);
|
||||
|
||||
typedef void (*DVDCommandCheckerCallback)(u32);
|
||||
typedef void (*DVDCommandChecker)(DVDCommandBlock*, DVDCommandCheckerCallback);
|
||||
|
||||
struct DVDCommandBlock {
|
||||
/* 0x00 */ DVDCommandBlock* next;
|
||||
/* 0x04 */ DVDCommandBlock* prev;
|
||||
/* 0x08 */ u32 command;
|
||||
/* 0x0C */ s32 state;
|
||||
/* 0x10 */ u32 offset;
|
||||
/* 0x14 */ u32 length;
|
||||
/* 0x18 */ void* addr;
|
||||
/* 0x1C */ u32 currTransferSize;
|
||||
/* 0x20 */ u32 transferredSize;
|
||||
/* 0x24 */ DVDDiskID* id;
|
||||
/* 0x28 */ DVDCBCallback callback;
|
||||
/* 0x2C */ void* userData;
|
||||
};
|
||||
|
||||
typedef struct DVDFileInfo DVDFileInfo;
|
||||
typedef void (*DVDCallback)(s32 result, DVDFileInfo *fileInfo);
|
||||
struct DVDFileInfo {
|
||||
/* 0x00 */ DVDCommandBlock cb;
|
||||
/* 0x30 */ u32 startAddr;
|
||||
/* 0x34 */ u32 length;
|
||||
/* 0x38 */ DVDCallback callback;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u32 entryNum;
|
||||
u32 location;
|
||||
u32 next;
|
||||
} DVDDir;
|
||||
|
||||
typedef struct {
|
||||
u32 entryNum;
|
||||
BOOL isDir;
|
||||
char* name;
|
||||
} DVDDirEntry;
|
||||
|
||||
typedef struct DVDBB2 {
|
||||
/* 0x00 */ u32 bootFilePosition;
|
||||
/* 0x04 */ u32 FSTPosition;
|
||||
/* 0x08 */ u32 FSTLength;
|
||||
/* 0x0C */ u32 FSTMaxLength;
|
||||
/* 0x10 */ void* FSTAddress;
|
||||
/* 0x14 */ u32 userPosition;
|
||||
/* 0x18 */ u32 userLength;
|
||||
/* 0x1C */ u32 padding0;
|
||||
} DVDBB2;
|
||||
|
||||
typedef struct DVDDriveInfo {
|
||||
/* 0x00 */ u16 revisionLevel;
|
||||
/* 0x02 */ u16 deviceCode;
|
||||
/* 0x04 */ u32 releaseDate;
|
||||
/* 0x08 */ u8 padding[24];
|
||||
} DVDDriveInfo;
|
||||
|
||||
// DVD
|
||||
void DVDInit(void);
|
||||
int DVDReadAbsAsyncPrio(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback, s32 prio);
|
||||
int DVDSeekAbsAsyncPrio(DVDCommandBlock* block, s32 offset, DVDCBCallback callback, s32 prio);
|
||||
int DVDReadAbsAsyncForBS(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback);
|
||||
int DVDReadDiskID(DVDCommandBlock* block, DVDDiskID* diskID, DVDCBCallback callback);
|
||||
int DVDPrepareStreamAbsAsync(DVDCommandBlock* block, u32 length, u32 offset, DVDCBCallback callback);
|
||||
int DVDCancelStreamAsync(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
s32 DVDCancelStream(DVDCommandBlock* block);
|
||||
int DVDStopStreamAtEndAsync(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
s32 DVDStopStreamAtEnd(DVDCommandBlock* block);
|
||||
int DVDGetStreamErrorStatusAsync(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
s32 DVDGetStreamErrorStatus(DVDCommandBlock* block);
|
||||
int DVDGetStreamPlayAddrAsync(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
s32 DVDGetStreamPlayAddr(DVDCommandBlock* block);
|
||||
int DVDGetStreamStartAddrAsync(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
s32 DVDGetStreamStartAddr(DVDCommandBlock* block);
|
||||
int DVDGetStreamLengthAsync(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
s32 DVDGetStreamLength(DVDCommandBlock* block);
|
||||
int DVDChangeDiskAsyncForBS(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
int DVDChangeDiskAsync(DVDCommandBlock* block, DVDDiskID* id, DVDCBCallback callback);
|
||||
s32 DVDChangeDisk(DVDCommandBlock* block, DVDDiskID* id);
|
||||
int DVDStopMotorAsync(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
s32 DVDStopMotor(DVDCommandBlock* block);
|
||||
int DVDInquiryAsync(DVDCommandBlock* block, DVDDriveInfo* info, DVDCBCallback callback);
|
||||
s32 DVDInquiry(DVDCommandBlock* block, DVDDriveInfo* info);
|
||||
void DVDReset(void);
|
||||
int DVDResetRequired(void);
|
||||
s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block);
|
||||
s32 DVDGetDriveStatus(void);
|
||||
BOOL DVDSetAutoInvalidation(BOOL autoInval);
|
||||
void DVDPause(void);
|
||||
void DVDResume(void);
|
||||
int DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
s32 DVDCancel(volatile DVDCommandBlock* block);
|
||||
int DVDCancelAllAsync(DVDCBCallback callback);
|
||||
s32 DVDCancelAll(void);
|
||||
DVDDiskID* DVDGetCurrentDiskID(void);
|
||||
BOOL DVDCheckDisk(void);
|
||||
|
||||
// DVD FATAL
|
||||
int DVDSetAutoFatalMessaging(BOOL enable);
|
||||
|
||||
// DVD FS
|
||||
s32 DVDConvertPathToEntrynum(const char* pathPtr);
|
||||
BOOL DVDFastOpen(s32 entrynum, DVDFileInfo* fileInfo);
|
||||
BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo);
|
||||
BOOL DVDClose(DVDFileInfo* fileInfo);
|
||||
BOOL DVDGetCurrentDir(char* path, u32 maxlen);
|
||||
BOOL DVDChangeDir(const char* dirName);
|
||||
BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset,
|
||||
DVDCallback callback, s32 prio);
|
||||
s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio);
|
||||
int DVDSeekAsyncPrio(DVDFileInfo* fileInfo, s32 offset, void (* callback)(s32, DVDFileInfo *), s32 prio);
|
||||
s32 DVDSeekPrio(DVDFileInfo* fileInfo, s32 offset, s32 prio);
|
||||
s32 DVDGetFileInfoStatus(const DVDFileInfo* fileInfo);
|
||||
BOOL DVDFastOpenDir(s32 entrynum, DVDDir* dir);
|
||||
int DVDOpenDir(const char* dirName, DVDDir* dir);
|
||||
int DVDReadDir(DVDDir* dir, DVDDirEntry* dirent);
|
||||
int DVDCloseDir(DVDDir* dir);
|
||||
void DVDRewindDir(DVDDir* dir);
|
||||
void* DVDGetFSTLocation(void);
|
||||
const u8* DVDGetDOLLocation(s32* out_size);
|
||||
BOOL DVDPrepareStreamAsync(DVDFileInfo* fileInfo, u32 length, u32 offset, DVDCallback callback);
|
||||
s32 DVDPrepareStream(DVDFileInfo* fileInfo, u32 length, u32 offset);
|
||||
s32 DVDGetTransferredSize(DVDFileInfo* fileinfo);
|
||||
|
||||
#define DVDReadAsync(fileInfo, addr, length, offset, callback) \
|
||||
DVDReadAsyncPrio((fileInfo), (addr), (length), (offset), (callback), 2)
|
||||
|
||||
// DVD ID UTILS
|
||||
int DVDCompareDiskID(const DVDDiskID* id1, const DVDDiskID* id2);
|
||||
DVDDiskID* DVDGenerateDiskID(DVDDiskID* id, const char* game, const char* company, u8 diskNum, u8 version);
|
||||
|
||||
// DVD LOW
|
||||
BOOL DVDLowRead(void* addr, u32 length, u32 offset, DVDLowCallback callback);
|
||||
BOOL DVDLowSeek(u32 offset, DVDLowCallback callback);
|
||||
BOOL DVDLowWaitCoverClose(DVDLowCallback callback);
|
||||
BOOL DVDLowReadDiskID(DVDDiskID* diskID, DVDLowCallback callback);
|
||||
BOOL DVDLowStopMotor(DVDLowCallback callback);
|
||||
BOOL DVDLowRequestError(DVDLowCallback callback);
|
||||
BOOL DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback);
|
||||
BOOL DVDLowAudioStream(u32 subcmd, u32 length, u32 offset, DVDLowCallback callback);
|
||||
BOOL DVDLowRequestAudioStatus(u32 subcmd, DVDLowCallback callback);
|
||||
BOOL DVDLowAudioBufferConfig(BOOL enable, u32 size, DVDLowCallback callback);
|
||||
void DVDLowReset(void);
|
||||
DVDLowCallback DVDLowSetResetCoverCallback(DVDLowCallback callback);
|
||||
BOOL DVDLowBreak(void);
|
||||
DVDLowCallback DVDLowClearCallback(void);
|
||||
u32 DVDLowGetCoverStatus(void);
|
||||
|
||||
// DVD QUEUE
|
||||
void DVDDumpWaitingQueue(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,103 +0,0 @@
|
||||
#ifndef _DOLPHIN_EXI_H_
|
||||
#define _DOLPHIN_EXI_H_
|
||||
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EXI_MEMORY_CARD_59 0x00000004
|
||||
#define EXI_MEMORY_CARD_123 0x00000008
|
||||
#define EXI_MEMORY_CARD_251 0x00000010
|
||||
#define EXI_MEMORY_CARD_507 0x00000020
|
||||
|
||||
#define EXI_MEMORY_CARD_1019 0x00000040
|
||||
#define EXI_MEMORY_CARD_2043 0x00000080
|
||||
|
||||
#define EXI_MEMORY_CARD_1019A 0x00000140
|
||||
#define EXI_MEMORY_CARD_1019B 0x00000240
|
||||
#define EXI_MEMORY_CARD_1019C 0x00000340
|
||||
#define EXI_MEMORY_CARD_1019D 0x00000440
|
||||
#define EXI_MEMORY_CARD_1019E 0x00000540
|
||||
#define EXI_MEMORY_CARD_1019F 0x00000640
|
||||
#define EXI_MEMORY_CARD_1019G 0x00000740
|
||||
|
||||
#define EXI_MEMORY_CARD_2043A 0x00000180
|
||||
#define EXI_MEMORY_CARD_2043B 0x00000280
|
||||
#define EXI_MEMORY_CARD_2043C 0x00000380
|
||||
#define EXI_MEMORY_CARD_2043D 0x00000480
|
||||
#define EXI_MEMORY_CARD_2043E 0x00000580
|
||||
#define EXI_MEMORY_CARD_2043F 0x00000680
|
||||
#define EXI_MEMORY_CARD_2043G 0x00000780
|
||||
|
||||
#define EXI_USB_ADAPTER 0x01010000
|
||||
#define EXI_NPDP_GDEV 0x01020000
|
||||
|
||||
#define EXI_MODEM 0x02020000
|
||||
#define EXI_ETHER 0x04020200
|
||||
#define EXI_MIC 0x04060000
|
||||
#define EXI_AD16 0x04120000
|
||||
#define EXI_RS232C 0x04040404
|
||||
#define EXI_ETHER_VIEWER 0x04220001
|
||||
#define EXI_STREAM_HANGER 0x04130000
|
||||
|
||||
#define EXI_MARLIN 0x03010000
|
||||
|
||||
#define EXI_IS_VIEWER 0x05070000
|
||||
|
||||
#define EXI_READ 0
|
||||
#define EXI_WRITE 1
|
||||
|
||||
#define EXI_FREQ_1M 0
|
||||
#define EXI_FREQ_2M 1
|
||||
#define EXI_FREQ_4M 2
|
||||
#define EXI_FREQ_8M 3
|
||||
#define EXI_FREQ_16M 4
|
||||
#define EXI_FREQ_32M 5
|
||||
|
||||
typedef void (*EXICallback)(s32 chan, OSContext* context);
|
||||
typedef struct EXIControl {
|
||||
EXICallback exiCallback;
|
||||
EXICallback tcCallback;
|
||||
EXICallback extCallback;
|
||||
volatile u32 state;
|
||||
int immLen;
|
||||
u8* immBuf;
|
||||
u32 dev;
|
||||
u32 id;
|
||||
s32 idTime;
|
||||
int items;
|
||||
struct {
|
||||
u32 dev;
|
||||
EXICallback callback;
|
||||
} queue[3];
|
||||
} EXIControl;
|
||||
|
||||
EXICallback EXISetExiCallback(s32 channel, EXICallback callback);
|
||||
|
||||
void EXIInit(void);
|
||||
BOOL EXILock(s32 channel, u32 device, EXICallback callback);
|
||||
BOOL EXIUnlock(s32 channel);
|
||||
BOOL EXISelect(s32 channel, u32 device, u32 frequency);
|
||||
BOOL EXIDeselect(s32 channel);
|
||||
BOOL EXIImm(s32 channel, void* buffer, s32 length, u32 type, EXICallback callback);
|
||||
BOOL EXIImmEx(s32 channel, void* buffer, s32 length, u32 type);
|
||||
BOOL EXIDma(s32 channel, void* buffer, s32 length, u32 type, EXICallback callback);
|
||||
BOOL EXISync(s32 channel);
|
||||
BOOL EXIProbe(s32 channel);
|
||||
s32 EXIProbeEx(s32 channel);
|
||||
BOOL EXIAttach(s32 channel, EXICallback callback);
|
||||
BOOL EXIDetach(s32 channel);
|
||||
u32 EXIGetState(s32 channel);
|
||||
s32 EXIGetID(s32 channel, u32 device, u32* id);
|
||||
void EXIProbeReset(void);
|
||||
int EXISelectSD(s32 chan, u32 dev, u32 freq);
|
||||
s32 EXIGetType(s32 chan, u32 dev, u32* type);
|
||||
char* EXIGetTypeString(u32 type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_H_
|
||||
#define _DOLPHIN_GD_H_
|
||||
|
||||
#include <dolphin/gd/GDAurora.h>
|
||||
#include <dolphin/gd/GDBase.h>
|
||||
#include <dolphin/gd/GDFile.h>
|
||||
#include <dolphin/gd/GDGeometry.h>
|
||||
#include <dolphin/gd/GDIndirect.h>
|
||||
#include <dolphin/gd/GDLight.h>
|
||||
#include <dolphin/gd/GDPixel.h>
|
||||
#include <dolphin/gd/GDTev.h>
|
||||
#include <dolphin/gd/GDTexture.h>
|
||||
#include <dolphin/gd/GDTransform.h>
|
||||
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef DOLPHIN_GDAURORA_H
|
||||
#define DOLPHIN_GDAURORA_H
|
||||
|
||||
/**
|
||||
* Pushes a debug group to the backend graphics API. These may show in debugging tools such as RenderDoc.
|
||||
*
|
||||
* It is considered an error to have unpopped debug groups at the end of the frame. They will be automatically cleared.
|
||||
* Debug groups are *not* automatically scoped to a display list.
|
||||
*/
|
||||
void GDPushDebugGroup(const char* label);
|
||||
|
||||
/**
|
||||
* Pop a debug group previously pushed via GXPushDebugGroup().
|
||||
*/
|
||||
void GDPopDebugGroup();
|
||||
|
||||
/**
|
||||
* Sends a debug marker to the backend graphics API. These may show in debugging tools such as RenderDoc.
|
||||
*/
|
||||
void GDInsertDebugMarker(const char* label);
|
||||
|
||||
#endif // DOLPHIN_GDAURORA_H
|
||||
@@ -1,177 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_BASE_H
|
||||
#define _DOLPHIN_GD_BASE_H
|
||||
|
||||
#include <dolphin/types.h>
|
||||
#include <dolphin/gx/GXEnum.h>
|
||||
#include <dolphin/gx/GXCommandList.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*GDOverflowCb)(void);
|
||||
|
||||
typedef struct _GDLObj {
|
||||
u8* start;
|
||||
u32 length;
|
||||
u8* ptr;
|
||||
u8* top;
|
||||
} GDLObj;
|
||||
|
||||
extern GDLObj* __GDCurrentDL;
|
||||
|
||||
void GDInitGDLObj(GDLObj* dl, void* start, u32 length);
|
||||
void GDFlushCurrToMem(void);
|
||||
void GDPadCurr32(void);
|
||||
void GDOverflowed(void);
|
||||
void GDSetOverflowCallback(GDOverflowCb callback);
|
||||
GDOverflowCb GDGetOverflowCallback(void);
|
||||
|
||||
inline static void GDOverflowCheck(u32 size) {
|
||||
if (__GDCurrentDL->ptr + size > __GDCurrentDL->top) {
|
||||
GDOverflowed();
|
||||
}
|
||||
}
|
||||
|
||||
inline static void __GDWrite(u8 data) {
|
||||
*__GDCurrentDL->ptr++ = data;
|
||||
}
|
||||
|
||||
inline static void GDWrite_data(const void* data, u32 length) {
|
||||
GDOverflowCheck(length);
|
||||
// The compiler realizes this is memcpy, trust.
|
||||
const u8* dataPtr = static_cast<const u8*>(data);
|
||||
for (u32 i = 0; i < length; i++) {
|
||||
__GDWrite(dataPtr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
inline static void GDWrite_u8(u8 data) {
|
||||
GDOverflowCheck(sizeof(u8));
|
||||
__GDWrite(data);
|
||||
}
|
||||
|
||||
inline static void GDWrite_u16(u16 data) {
|
||||
GDOverflowCheck(sizeof(u16));
|
||||
__GDWrite((u8)((data >> 8)));
|
||||
__GDWrite((u8)((data >> 0) & 0xFF));
|
||||
}
|
||||
|
||||
inline static void GDWrite_u24(u32 data) {
|
||||
GDOverflowCheck(3);
|
||||
__GDWrite((u8)((data >> 16) & 0xFF));
|
||||
__GDWrite((u8)((data >> 8) & 0xFF));
|
||||
__GDWrite((u8)((data >> 0) & 0xFF));
|
||||
}
|
||||
|
||||
inline static void GDWrite_u32(u32 data) {
|
||||
GDOverflowCheck(sizeof(u32));
|
||||
__GDWrite((u8)((data >> 24) & 0xFF));
|
||||
__GDWrite((u8)((data >> 16) & 0xFF));
|
||||
__GDWrite((u8)((data >> 8) & 0xFF));
|
||||
__GDWrite((u8)((data >> 0) & 0xFF));
|
||||
}
|
||||
|
||||
inline static void GDWrite_u64(u64 data) {
|
||||
GDOverflowCheck(sizeof(u64));
|
||||
__GDWrite((u8)((data >> 56) & 0xFF));
|
||||
__GDWrite((u8)((data >> 48) & 0xFF));
|
||||
__GDWrite((u8)((data >> 40) & 0xFF));
|
||||
__GDWrite((u8)((data >> 32) & 0xFF));
|
||||
__GDWrite((u8)((data >> 24) & 0xFF));
|
||||
__GDWrite((u8)((data >> 16) & 0xFF));
|
||||
__GDWrite((u8)((data >> 8) & 0xFF));
|
||||
__GDWrite((u8)((data >> 0) & 0xFF));
|
||||
}
|
||||
|
||||
inline static void GDWrite_f32(f32 data) {
|
||||
union {
|
||||
f32 f;
|
||||
u32 u;
|
||||
} fid;
|
||||
fid.f = data;
|
||||
GDWrite_u32(fid.u);
|
||||
}
|
||||
|
||||
inline static void GDWriteXFCmdHdr(u16 addr, u8 len) {
|
||||
GDWrite_u8(GX_LOAD_XF_REG);
|
||||
GDWrite_u16(len - 1);
|
||||
GDWrite_u16(addr);
|
||||
}
|
||||
|
||||
inline static void GDWriteXFCmd(u16 addr, u32 val) {
|
||||
GDWrite_u8(GX_LOAD_XF_REG);
|
||||
GDWrite_u16(0);
|
||||
GDWrite_u16(addr);
|
||||
GDWrite_u32(val);
|
||||
}
|
||||
|
||||
inline static void GDWriteXFIndxDCmd(u16 addr, u8 len, u16 index) {
|
||||
GDWrite_u8(GX_LOAD_INDX_D);
|
||||
GDWrite_u16(index);
|
||||
GDWrite_u16((len - 1) << 12 | addr);
|
||||
}
|
||||
|
||||
inline static void GDWriteXFIndxACmd(u16 addr, u8 len, u16 index) {
|
||||
GDWrite_u8(GX_LOAD_INDX_A);
|
||||
GDWrite_u16(index);
|
||||
GDWrite_u16(((len - 1) << 12) | addr);
|
||||
}
|
||||
|
||||
inline static void GDWriteXFIndxBCmd(u16 addr, u8 len, u16 index) {
|
||||
GDWrite_u8(GX_LOAD_INDX_B);
|
||||
GDWrite_u16(index);
|
||||
GDWrite_u16(((len - 1) << 12) | addr);
|
||||
}
|
||||
|
||||
inline static void GDWriteXFIndxCCmd(u16 addr, u8 len, u16 index) {
|
||||
GDWrite_u8(GX_LOAD_INDX_C);
|
||||
GDWrite_u16(index);
|
||||
GDWrite_u16(((len - 1) << 12) | addr);
|
||||
}
|
||||
|
||||
inline static void GDWriteCPCmd(u8 addr, u32 val) {
|
||||
GDWrite_u8(GX_LOAD_CP_REG);
|
||||
GDWrite_u8(addr);
|
||||
GDWrite_u32(val);
|
||||
}
|
||||
|
||||
inline static void GDWriteBPCmd(u32 regval) {
|
||||
GDWrite_u8(GX_LOAD_BP_REG);
|
||||
GDWrite_u32(regval);
|
||||
}
|
||||
|
||||
inline static void GDWriteAuroraCmd(u16 subCommand) {
|
||||
GDWrite_u8(GX_LOAD_AURORA);
|
||||
GDWrite_u16(subCommand);
|
||||
}
|
||||
|
||||
inline static void GDSetCurrent(GDLObj* dl) {
|
||||
__GDCurrentDL = dl;
|
||||
}
|
||||
|
||||
static inline u32 GDGetCurrOffset(void) {
|
||||
return (u32)(__GDCurrentDL->ptr - __GDCurrentDL->start);
|
||||
}
|
||||
|
||||
static inline void GDSetCurrOffset(u32 offset) {
|
||||
__GDCurrentDL->ptr = __GDCurrentDL->start + offset;
|
||||
}
|
||||
|
||||
static inline void* GDGetCurrPointer(void) {
|
||||
return (void*)__GDCurrentDL->ptr;
|
||||
}
|
||||
|
||||
static inline u8* GDGetCurrPointer2(void) {
|
||||
return __GDCurrentDL->ptr;
|
||||
}
|
||||
|
||||
static inline u32 GDGetGDLObjOffset(const GDLObj* dl) {
|
||||
return (u32)(dl->ptr - dl->start);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_FILE_H
|
||||
#define _DOLPHIN_GD_FILE_H
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GD_FILE_VERSION_NUMBER 0x11223344
|
||||
|
||||
typedef struct _GDGList {
|
||||
void* ptr;
|
||||
u32 byteLength;
|
||||
} GDGList;
|
||||
|
||||
typedef struct _GDFileHeader {
|
||||
u32 versionNumber;
|
||||
u32 numDLs;
|
||||
u32 numPLs;
|
||||
GDGList* DLDescArray;
|
||||
GDGList* PLDescArray;
|
||||
} GDFileHeader;
|
||||
|
||||
s32 GDReadDLFile(const char* fName, u32* numDLs, u32* numPLs, GDGList** DLDescArray, GDGList** PLDescArray);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,525 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_GEOMETRY_H_
|
||||
#define _DOLPHIN_GD_GEOMETRY_H_
|
||||
|
||||
#include <dolphin/gx/GXStruct.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Command processor register IDs
|
||||
#define CP_REG_MTXIDXA_ID 0x30 // Matrix index A
|
||||
#define CP_REG_MTXIDXB_ID 0x40 // Matrix index B
|
||||
#define CP_REG_VCD_LO_ID 0x50 // Vertex descriptor (lo)
|
||||
#define CP_REG_VCD_HI_ID 0x60 // Vertex descriptor (hi)
|
||||
#define CP_REG_VAT_GRP0_ID 0x70 // Vertex attribute table (group 0)
|
||||
#define CP_REG_VAT_GRP1_ID 0x80 // Vertex attribute table (group 1)
|
||||
#define CP_REG_VAT_GRP2_ID 0x90 // Vertex attribute table (group 2)
|
||||
#define CP_REG_ARRAYBASE_ID 0xA0 // Vertex array start/base
|
||||
#define CP_REG_ARRAYSTRIDE_ID 0xB0 // Vertex array stride
|
||||
|
||||
// XF locators for textures
|
||||
// Projection type [30-30]
|
||||
#define GX_XF_TEX_PROJTYPE_ST 30
|
||||
#define GX_XF_TEX_PROJTYPE_END 30
|
||||
|
||||
// Input format [29-29]
|
||||
#define GX_XF_TEX_INPUTFORM_ST 29
|
||||
#define GX_XF_TEX_INPUTFORM_END 29
|
||||
|
||||
// Texture gen type [25-27]
|
||||
#define GX_XF_TEX_TEXGENTYPE_ST 25
|
||||
#define GX_XF_TEX_TEXGENTYPE_END 27
|
||||
|
||||
// Source row [20-24]
|
||||
#define GX_XF_TEX_SRCROW_ST 20
|
||||
#define GX_XF_TEX_SRCROW_END 24
|
||||
|
||||
// Bump source texture [17-19]
|
||||
#define GX_XF_TEX_BUMPSRCTEX_ST 17
|
||||
#define GX_XF_TEX_BUMPSRCTEX_END 19
|
||||
|
||||
// Bump source light [14-16]
|
||||
#define GX_XF_TEX_BUMPSRCLIGHT_ST 14
|
||||
#define GX_XF_TEX_BUMPSRCLIGHT_END 16
|
||||
|
||||
// Blitting processor registers.
|
||||
#define GX_BP_REG_GENMODE 0x0 // gen mode
|
||||
|
||||
// display copy filters
|
||||
#define GX_BP_REG_DISPCOPYFILTER0 0x1 // display copy filter 0
|
||||
#define GX_BP_REG_DISPCOPYFILTER1 0x2 // display copy filter 1
|
||||
#define GX_BP_REG_DISPCOPYFILTER2 0x3 // display copy filter 2
|
||||
#define GX_BP_REG_DISPCOPYFILTER3 0x4 // display copy filter 3
|
||||
|
||||
// indirect matrices
|
||||
#define GX_BP_REG_INDMTX0A 0x6 // indirect matrix 0A
|
||||
#define GX_BP_REG_INDMTX0B 0x7 // indirect matrix 0B
|
||||
#define GX_BP_REG_INDMTX0C 0x8 // indirect matrix 0C
|
||||
#define GX_BP_REG_INDMTX1A 0x9 // indirect matrix 1A
|
||||
#define GX_BP_REG_INDMTX1B 0xA // indirect matrix 1B
|
||||
#define GX_BP_REG_INDMTX1C 0xB // indirect matrix 1C
|
||||
#define GX_BP_REG_INDMTX2A 0xC // indirect matrix 2A
|
||||
#define GX_BP_REG_INDMTX2B 0xD // indirect matrix 2B
|
||||
#define GX_BP_REG_INDMTX2C 0xE // indirect matrix 2C
|
||||
#define GX_BP_REG_INDIMASK 0xF // indirect mask
|
||||
|
||||
// indirect TEV stages
|
||||
#define GX_BP_REG_INDTEVSTAGE0 0x10 // indirect TEV stage 0
|
||||
#define GX_BP_REG_INDTEVSTAGE1 0x11 // indirect TEV stage 1
|
||||
#define GX_BP_REG_INDTEVSTAGE2 0x12 // indirect TEV stage 2
|
||||
#define GX_BP_REG_INDTEVSTAGE3 0x13 // indirect TEV stage 3
|
||||
#define GX_BP_REG_INDTEVSTAGE4 0x14 // indirect TEV stage 4
|
||||
#define GX_BP_REG_INDTEVSTAGE5 0x15 // indirect TEV stage 5
|
||||
#define GX_BP_REG_INDTEVSTAGE6 0x16 // indirect TEV stage 6
|
||||
#define GX_BP_REG_INDTEVSTAGE7 0x17 // indirect TEV stage 7
|
||||
#define GX_BP_REG_INDTEVSTAGE8 0x18 // indirect TEV stage 8
|
||||
#define GX_BP_REG_INDTEVSTAGE9 0x19 // indirect TEV stage 9
|
||||
#define GX_BP_REG_INDTEVSTAGE10 0x1A // indirect TEV stage 10
|
||||
#define GX_BP_REG_INDTEVSTAGE11 0x1B // indirect TEV stage 11
|
||||
#define GX_BP_REG_INDTEVSTAGE12 0x1C // indirect TEV stage 12
|
||||
#define GX_BP_REG_INDTEVSTAGE13 0x1D // indirect TEV stage 13
|
||||
#define GX_BP_REG_INDTEVSTAGE14 0x1E // indirect TEV stage 14
|
||||
#define GX_BP_REG_INDTEVSTAGE15 0x1F // indirect TEV stage 15
|
||||
|
||||
// performance manips
|
||||
#define GX_BP_REG_SCISSORTL 0x20 // scissor top left
|
||||
#define GX_BP_REG_SCISSORBR 0x21 // scissor bottom right
|
||||
#define GX_BP_REG_LINEPTWIDTH 0x22 // line point width
|
||||
#define GX_BP_REG_PERF0TRI 0x23 // performance 0 (triangle)
|
||||
#define GX_BP_REG_PERF0QUAD 0x24 // performance 0 (quad)
|
||||
|
||||
// rasters
|
||||
#define GX_BP_REG_RAS1_SS0 0x25
|
||||
#define GX_BP_REG_RAS1_SS1 0x26
|
||||
#define GX_BP_REG_RAS1_IREF 0x27
|
||||
#define GX_BP_REG_RAS1_TREF0 0x28
|
||||
#define GX_BP_REG_RAS1_TREF1 0x29
|
||||
#define GX_BP_REG_RAS1_TREF2 0x2A
|
||||
#define GX_BP_REG_RAS1_TREF3 0x2B
|
||||
#define GX_BP_REG_RAS1_TREF4 0x2C
|
||||
#define GX_BP_REG_RAS1_TREF5 0x2D
|
||||
#define GX_BP_REG_RAS1_TREF6 0x2E
|
||||
#define GX_BP_REG_RAS1_TREF7 0x2F
|
||||
|
||||
// setup sizes
|
||||
#define GX_BP_REG_SU_SSIZE0 0x30
|
||||
#define GX_BP_REG_SU_TSIZE0 0x31
|
||||
#define GX_BP_REG_SU_SSIZE1 0x32
|
||||
#define GX_BP_REG_SU_TSIZE1 0x33
|
||||
#define GX_BP_REG_SU_SSIZE2 0x34
|
||||
#define GX_BP_REG_SU_TSIZE2 0x35
|
||||
#define GX_BP_REG_SU_SSIZE3 0x36
|
||||
#define GX_BP_REG_SU_TSIZE3 0x37
|
||||
#define GX_BP_REG_SU_SSIZE4 0x38
|
||||
#define GX_BP_REG_SU_TSIZE4 0x39
|
||||
#define GX_BP_REG_SU_SSIZE5 0x3A
|
||||
#define GX_BP_REG_SU_TSIZE5 0x3B
|
||||
#define GX_BP_REG_SU_SSIZE6 0x3C
|
||||
#define GX_BP_REG_SU_TSIZE6 0x3D
|
||||
#define GX_BP_REG_SU_SSIZE7 0x3E
|
||||
#define GX_BP_REG_SU_TSIZE7 0x3F
|
||||
|
||||
// Z and blend controls
|
||||
#define GX_BP_REG_ZMODE 0x40
|
||||
#define GX_BP_REG_BLENDMODE 0x41
|
||||
#define GX_BP_REG_DSTALPHA 0x42
|
||||
#define GX_BP_REG_ZCONTROL 0x43
|
||||
#define GX_BP_REG_FIELDMASK 0x44
|
||||
#define GX_BP_REG_DRAWDONE 0x45
|
||||
#define GX_BP_REG_PETOKEN 0x47
|
||||
#define GX_BP_REG_PETOKENINT 0x48
|
||||
|
||||
// copying
|
||||
#define GX_BP_REG_TEXCOPYSRCXY 0x49
|
||||
#define GX_BP_REG_TEXCOPYSRCWH 0x4A
|
||||
#define GX_BP_REG_TEXCOPYDST 0x4B
|
||||
#define GX_BP_REG_DISPCOPYSTRIDE 0x4D
|
||||
#define GX_BP_REG_DISPCOPYSCALEY 0x4E
|
||||
#define GX_BP_REG_COPYCLEARAR 0x4F
|
||||
#define GX_BP_REG_COPYCLEARGB 0x50
|
||||
#define GX_BP_REG_COPYCLEARZ 0x51
|
||||
#define GX_BP_REG_COPYFILTER0 0x53
|
||||
#define GX_BP_REG_COPYFILTER1 0x54
|
||||
|
||||
//
|
||||
#define GX_BP_REG_BOUNDINGBOX0 0x55
|
||||
#define GX_BP_REG_BOUNDINGBOX1 0x56
|
||||
|
||||
#define GX_BP_REG_SCISSOROFFSET 0x59
|
||||
|
||||
// texture memory
|
||||
#define GX_BP_REG_TMEMPRELOADADDR 0x60
|
||||
#define GX_BP_REG_TMEMPRELOADEVEN 0x61
|
||||
#define GX_BP_REG_TMEMPRELOADODD 0x62
|
||||
#define GX_BP_REG_TMEMPRELOADMODE 0x63
|
||||
#define GX_BP_REG_TMEMTLUTSRC 0x64
|
||||
#define GX_BP_REG_TMEMTLUTDST 0x65
|
||||
#define GX_BP_REG_TMEMTEXINVALIDATE 0x66
|
||||
|
||||
// performance 1
|
||||
#define GX_BP_REG_PERF1 0x67
|
||||
#define GX_BP_REG_FIELDMODE 0x68
|
||||
|
||||
// set modes
|
||||
#define GX_BP_REG_SETMODE0_TEX0 0x80
|
||||
#define GX_BP_REG_SETMODE0_TEX1 0x81
|
||||
#define GX_BP_REG_SETMODE0_TEX2 0x82
|
||||
#define GX_BP_REG_SETMODE0_TEX3 0x83
|
||||
#define GX_BP_REG_SETMODE1_TEX0 0x84
|
||||
#define GX_BP_REG_SETMODE1_TEX1 0x85
|
||||
#define GX_BP_REG_SETMODE1_TEX2 0x86
|
||||
#define GX_BP_REG_SETMODE1_TEX3 0x87
|
||||
|
||||
// set images
|
||||
#define GX_BP_REG_SETIMAGE0_TEX0 0x88
|
||||
#define GX_BP_REG_SETIMAGE0_TEX1 0x89
|
||||
#define GX_BP_REG_SETIMAGE0_TEX2 0x8A
|
||||
#define GX_BP_REG_SETIMAGE0_TEX3 0x8B
|
||||
#define GX_BP_REG_SETIMAGE1_TEX0 0x8C
|
||||
#define GX_BP_REG_SETIMAGE1_TEX1 0x8D
|
||||
#define GX_BP_REG_SETIMAGE1_TEX2 0x8E
|
||||
#define GX_BP_REG_SETIMAGE1_TEX3 0x8F
|
||||
#define GX_BP_REG_SETIMAGE2_TEX0 0x90
|
||||
#define GX_BP_REG_SETIMAGE2_TEX1 0x91
|
||||
#define GX_BP_REG_SETIMAGE2_TEX2 0x92
|
||||
#define GX_BP_REG_SETIMAGE2_TEX3 0x93
|
||||
#define GX_BP_REG_SETIMAGE3_TEX0 0x94
|
||||
#define GX_BP_REG_SETIMAGE3_TEX1 0x95
|
||||
#define GX_BP_REG_SETIMAGE3_TEX2 0x96
|
||||
#define GX_BP_REG_SETIMAGE3_TEX3 0x97
|
||||
|
||||
// set texture lookups
|
||||
#define GX_BP_REG_SETTLUT_TEX0 0x98
|
||||
#define GX_BP_REG_SETTLUT_TEX1 0x99
|
||||
#define GX_BP_REG_SETTLUT_TEX2 0x9A
|
||||
#define GX_BP_REG_SETTLUT_TEX3 0x9B
|
||||
|
||||
// set modes continued
|
||||
#define GX_BP_REG_SETMODE0_TEX4 0xA0
|
||||
#define GX_BP_REG_SETMODE0_TEX5 0xA1
|
||||
#define GX_BP_REG_SETMODE0_TEX6 0xA2
|
||||
#define GX_BP_REG_SETMODE0_TEX7 0xA3
|
||||
#define GX_BP_REG_SETMODE1_TEX4 0xA4
|
||||
#define GX_BP_REG_SETMODE1_TEX5 0xA5
|
||||
#define GX_BP_REG_SETMODE1_TEX6 0xA6
|
||||
#define GX_BP_REG_SETMODE1_TEX7 0xA7
|
||||
|
||||
// set images continued
|
||||
#define GX_BP_REG_SETIMAGE0_TEX4 0xA8
|
||||
#define GX_BP_REG_SETIMAGE0_TEX5 0xA9
|
||||
#define GX_BP_REG_SETIMAGE0_TEX6 0xAA
|
||||
#define GX_BP_REG_SETIMAGE0_TEX7 0xAB
|
||||
#define GX_BP_REG_SETIMAGE1_TEX4 0xAC
|
||||
#define GX_BP_REG_SETIMAGE1_TEX5 0xAD
|
||||
#define GX_BP_REG_SETIMAGE1_TEX6 0xAE
|
||||
#define GX_BP_REG_SETIMAGE1_TEX7 0xAF
|
||||
#define GX_BP_REG_SETIMAGE2_TEX4 0xB0
|
||||
#define GX_BP_REG_SETIMAGE2_TEX5 0xB1
|
||||
#define GX_BP_REG_SETIMAGE2_TEX6 0xB2
|
||||
#define GX_BP_REG_SETIMAGE2_TEX7 0xB3
|
||||
#define GX_BP_REG_SETIMAGE3_TEX4 0xB4
|
||||
#define GX_BP_REG_SETIMAGE3_TEX5 0xB5
|
||||
#define GX_BP_REG_SETIMAGE3_TEX6 0xB6
|
||||
#define GX_BP_REG_SETIMAGE3_TEX7 0xB7
|
||||
|
||||
// set texture lookups continued
|
||||
#define GX_BP_REG_SETTLUT_TEX4 0xB8
|
||||
#define GX_BP_REG_SETTLUT_TEX5 0xB9
|
||||
#define GX_BP_REG_SETTLUT_TEX6 0xBA
|
||||
#define GX_BP_REG_SETTLUT_TEX7 0xBB
|
||||
|
||||
// TEV color manips
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER0 0xC0
|
||||
#define GX_BP_REG_TEVALPHACOMBINER0 0xC1
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER1 0xC2
|
||||
#define GX_BP_REG_TEVALPHACOMBINER1 0xC3
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER2 0xC4
|
||||
#define GX_BP_REG_TEVALPHACOMBINER2 0xC5
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER3 0xC6
|
||||
#define GX_BP_REG_TEVALPHACOMBINER3 0xC7
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER4 0xC8
|
||||
#define GX_BP_REG_TEVALPHACOMBINER4 0xC9
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER5 0xCA
|
||||
#define GX_BP_REG_TEVALPHACOMBINER5 0xCB
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER6 0xCC
|
||||
#define GX_BP_REG_TEVALPHACOMBINER6 0xCD
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER7 0xCE
|
||||
#define GX_BP_REG_TEVALPHACOMBINER7 0xCF
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER8 0xD0
|
||||
#define GX_BP_REG_TEVALPHACOMBINER8 0xD1
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER9 0xD2
|
||||
#define GX_BP_REG_TEVALPHACOMBINER9 0xD3
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER10 0xD4
|
||||
#define GX_BP_REG_TEVALPHACOMBINER10 0xD5
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER11 0xD6
|
||||
#define GX_BP_REG_TEVALPHACOMBINER11 0xD7
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER12 0xD8
|
||||
#define GX_BP_REG_TEVALPHACOMBINER12 0xD9
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER13 0xDA
|
||||
#define GX_BP_REG_TEVALPHACOMBINER13 0xDB
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER14 0xDC
|
||||
#define GX_BP_REG_TEVALPHACOMBINER14 0xDD
|
||||
#define GX_BP_REG_TEVCOLORCOMBINER15 0xDE
|
||||
#define GX_BP_REG_TEVALPHACOMBINER15 0xDF
|
||||
|
||||
// TEV registers
|
||||
#define GX_BP_REG_TEVREG0LO 0xE0
|
||||
#define GX_BP_REG_TEVREG0HI 0xE1
|
||||
#define GX_BP_REG_TEVREG1LO 0xE2
|
||||
#define GX_BP_REG_TEVREG1HI 0xE3
|
||||
#define GX_BP_REG_TEVREG2LO 0xE4
|
||||
#define GX_BP_REG_TEVREG2HI 0xE5
|
||||
#define GX_BP_REG_TEVREG3LO 0xE6
|
||||
#define GX_BP_REG_TEVREG3HI 0xE7
|
||||
|
||||
// fog registers
|
||||
#define GX_BP_REG_FOGRANGE 0xE8
|
||||
#define GX_BP_REG_FOGRANGEK0 0xE9
|
||||
#define GX_BP_REG_FOGRANGEK1 0xEA
|
||||
#define GX_BP_REG_FOGRANGEK2 0xEB
|
||||
#define GX_BP_REG_FOGRANGEK3 0xEC
|
||||
#define GX_BP_REG_FOGRANGEK4 0xED
|
||||
#define GX_BP_REG_FOGPARAM0 0xEE
|
||||
#define GX_BP_REG_FOGPARAM1 0xEF
|
||||
#define GX_BP_REG_FOGPARAM2 0xF0
|
||||
#define GX_BP_REG_FOGPARAM3 0xF1
|
||||
#define GX_BP_REG_FOGCOLOR 0xF2
|
||||
|
||||
// performance manip registers
|
||||
#define GX_BP_REG_ALPHACOMPARE 0xF3
|
||||
#define GX_BP_REG_ZTEXTURE0 0xF4
|
||||
#define GX_BP_REG_ZTEXTURE1 0xF5
|
||||
|
||||
// TEV K selectors
|
||||
#define GX_BP_REG_TEVKSEL0 0xF6
|
||||
#define GX_BP_REG_TEVKSEL1 0xF7
|
||||
#define GX_BP_REG_TEVKSEL2 0xF8
|
||||
#define GX_BP_REG_TEVKSEL3 0xF9
|
||||
#define GX_BP_REG_TEVKSEL4 0xFA
|
||||
#define GX_BP_REG_TEVKSEL5 0xFB
|
||||
#define GX_BP_REG_TEVKSEL6 0xFC
|
||||
#define GX_BP_REG_TEVKSEL7 0xFD
|
||||
|
||||
// SS mask
|
||||
#define GX_BP_REG_SSMASK 0xFE
|
||||
|
||||
// Transform Unit Registers
|
||||
#define GX_XF_REG_ERROR 0x1000
|
||||
#define GX_XF_REG_DIAGNOSTICS 0x1001
|
||||
#define GX_XF_REG_STATE0 0x1002
|
||||
#define GX_XF_REG_STATE1 0x1003
|
||||
#define GX_XF_REG_CLOCK 0x1004
|
||||
#define GX_XF_REG_CLIPDISABLE 0x1005
|
||||
#define GX_XF_REG_PERF0 0x1006
|
||||
#define GX_XF_REG_PERF1 0x1007
|
||||
#define GX_XF_REG_INVERTEXSPEC 0x1008
|
||||
#define GX_XF_REG_NUMCOLORS 0x1009
|
||||
#define GX_XF_REG_AMBIENT0 0x100A
|
||||
#define GX_XF_REG_AMBIENT1 0x100B
|
||||
#define GX_XF_REG_MATERIAL0 0x100C
|
||||
#define GX_XF_REG_MATERIAL1 0x100D
|
||||
#define GX_XF_REG_COLOR0CNTRL 0x100E
|
||||
#define GX_XF_REG_COLOR1CNTRL 0x100F
|
||||
#define GX_XF_REG_ALPHA0CNTRL 0x1010
|
||||
#define GX_XF_REG_ALPHA1CNTRL 0x1011
|
||||
#define GX_XF_REG_DUALTEXTRAN 0x1012
|
||||
#define GX_XF_REG_MATRIXINDEX0 0x1018
|
||||
#define GX_XF_REG_MATRIXINDEX1 0x1019
|
||||
#define GX_XF_REG_SCALEX 0x101A
|
||||
#define GX_XF_REG_SCALEY 0x101B
|
||||
#define GX_XF_REG_SCALEZ 0x101C
|
||||
#define GX_XF_REG_OFFSETX 0x101D
|
||||
#define GX_XF_REG_OFFSETY 0x101E
|
||||
#define GX_XF_REG_OFFSETZ 0x101F
|
||||
#define GX_XF_REG_PROJECTIONA 0x1020
|
||||
#define GX_XF_REG_PROJECTIONB 0x1021
|
||||
#define GX_XF_REG_PROJECTIONC 0x1022
|
||||
#define GX_XF_REG_PROJECTIOND 0x1023
|
||||
#define GX_XF_REG_PROJECTIONE 0x1024
|
||||
#define GX_XF_REG_PROJECTIONF 0x1025
|
||||
#define GX_XF_REG_PROJECTORTHO 0x1026
|
||||
#define GX_XF_REG_NUMTEX 0x103F
|
||||
#define GX_XF_REG_TEX0 0x1040
|
||||
#define GX_XF_REG_TEX1 0x1041
|
||||
#define GX_XF_REG_TEX2 0x1042
|
||||
#define GX_XF_REG_TEX3 0x1043
|
||||
#define GX_XF_REG_TEX4 0x1044
|
||||
#define GX_XF_REG_TEX5 0x1045
|
||||
#define GX_XF_REG_TEX6 0x1046
|
||||
#define GX_XF_REG_TEX7 0x1047
|
||||
#define GX_XF_REG_DUALTEX0 0x1050
|
||||
#define GX_XF_REG_DUALTEX1 0x1051
|
||||
#define GX_XF_REG_DUALTEX2 0x1052
|
||||
#define GX_XF_REG_DUALTEX3 0x1053
|
||||
#define GX_XF_REG_DUALTEX4 0x1054
|
||||
#define GX_XF_REG_DUALTEX5 0x1055
|
||||
#define GX_XF_REG_DUALTEX6 0x1056
|
||||
#define GX_XF_REG_DUALTEX7 0x1057
|
||||
|
||||
#define CP_REG_VCD_LO(pnMtxIdx, txMtxIdxMask, posn, norm, col0, col1) \
|
||||
( \
|
||||
(pnMtxIdx) << 0 | \
|
||||
(txMtxIdxMask) << 1 | \
|
||||
(posn) << 9 | \
|
||||
(norm) << 11 | \
|
||||
(col0) << 13 | \
|
||||
(col1) << 15 \
|
||||
)
|
||||
|
||||
#define CP_REG_VCD_HI(tex0, tex1, tex2, tex3, tex4, tex5, tex6, tex7) \
|
||||
( \
|
||||
(tex0) << 0 | \
|
||||
(tex1) << 2 | \
|
||||
(tex2) << 4 | \
|
||||
(tex3) << 6 | \
|
||||
(tex4) << 8 | \
|
||||
(tex5) << 10 | \
|
||||
(tex6) << 12 | \
|
||||
(tex7) << 14 \
|
||||
)
|
||||
|
||||
#define CP_REG_VAT_GRP0(posCnt, posType, posFrac, nrmCnt, nrmType, c0Cnt, c0Type, c1Cnt, c1Type, tx0Cnt, tx0Type, tx0Frac, p12, nrmIdx3) \
|
||||
( \
|
||||
(posCnt) << 0 | \
|
||||
(posType) << 1 | \
|
||||
(posFrac) << 4 | \
|
||||
(nrmCnt) << 9 | \
|
||||
(nrmType) << 10 | \
|
||||
(c0Cnt) << 13 | \
|
||||
(c0Type) << 14 | \
|
||||
(c1Cnt) << 17 | \
|
||||
(c1Type) << 18 | \
|
||||
(tx0Cnt) << 21 | \
|
||||
(tx0Type) << 22 | \
|
||||
(tx0Frac) << 25 | \
|
||||
(p12) << 30 | \
|
||||
(nrmIdx3) << 31 \
|
||||
)
|
||||
|
||||
#define CP_REG_VAT_GRP1(tx1Cnt, tx1Type, tx1Frac, tx2Cnt, tx2Type, tx2Frac, tx3Cnt, tx3Type, tx3Frac, tx4Cnt, tx4Type, p11) \
|
||||
( \
|
||||
(tx1Cnt) << 0 | \
|
||||
(tx1Type) << 1 | \
|
||||
(tx1Frac) << 4 | \
|
||||
(tx2Cnt) << 9 | \
|
||||
(tx2Type) << 10 | \
|
||||
(tx2Frac) << 13 | \
|
||||
(tx3Cnt) << 18 | \
|
||||
(tx3Type) << 19 | \
|
||||
(tx3Frac) << 22 | \
|
||||
(tx4Cnt) << 27 | \
|
||||
(tx4Type) << 28 | \
|
||||
p11 << 31 \
|
||||
)
|
||||
|
||||
#define CP_REG_VAT_GRP2(tx4Frac, tx5Cnt, tx5Type, tx5Frac, tx6Cnt, tx6Type, tx6Frac, tx7Cnt, tx7Type, tx7Frac) \
|
||||
( \
|
||||
(tx4Frac) << 0 | \
|
||||
(tx5Cnt) << 5 | \
|
||||
(tx5Type) << 6 | \
|
||||
(tx5Frac) << 9 | \
|
||||
(tx6Cnt) << 14 | \
|
||||
(tx6Type) << 15 | \
|
||||
(tx6Frac) << 18 | \
|
||||
(tx7Cnt) << 23 | \
|
||||
(tx7Type) << 24 | \
|
||||
(tx7Frac) << 27 \
|
||||
)
|
||||
|
||||
// Transform unit register IDs
|
||||
#define XF_REG_ERROR_ID 0x1000
|
||||
#define XF_REG_DIAGNOSTICS_ID 0x1001
|
||||
#define XF_REG_STATE0_ID 0x1002
|
||||
#define XF_REG_STATE1_ID 0x1003
|
||||
#define XF_REG_CLOCK_ID 0x1004
|
||||
#define XF_REG_CLIPDISABLE_ID 0x1005
|
||||
#define XF_REG_PERF0_ID 0x1006
|
||||
#define XF_REG_PERF1_ID 0x1007
|
||||
#define XF_REG_INVERTEXSPEC_ID 0x1008
|
||||
#define XF_REG_NUMCOLORS_ID 0x1009
|
||||
#define XF_REG_DUALTEXTRAN_ID 0x1012
|
||||
#define XF_REG_SCALEX_ID 0x101A
|
||||
#define XF_REG_SCALEY_ID 0x101B
|
||||
#define XF_REG_SCALEZ_ID 0x101C
|
||||
#define XF_REG_OFFSETX_ID 0x101D
|
||||
#define XF_REG_OFFSETY_ID 0x101E
|
||||
#define XF_REG_OFFSETZ_ID 0x101F
|
||||
#define XF_REG_NUMTEX_ID 0x103F
|
||||
#define XF_REG_TEX0_ID 0x1040
|
||||
#define XF_REG_TEX1_ID 0x1041
|
||||
#define XF_REG_TEX2_ID 0x1042
|
||||
#define XF_REG_TEX3_ID 0x1043
|
||||
#define XF_REG_TEX4_ID 0x1044
|
||||
#define XF_REG_TEX5_ID 0x1045
|
||||
#define XF_REG_TEX6_ID 0x1046
|
||||
#define XF_REG_TEX7_ID 0x1047
|
||||
#define XF_REG_DUALTEX0_ID 0x1050
|
||||
#define XF_REG_DUALTEX1_ID 0x1051
|
||||
#define XF_REG_DUALTEX2_ID 0x1052
|
||||
#define XF_REG_DUALTEX3_ID 0x1053
|
||||
#define XF_REG_DUALTEX4_ID 0x1054
|
||||
#define XF_REG_DUALTEX5_ID 0x1055
|
||||
#define XF_REG_DUALTEX6_ID 0x1056
|
||||
#define XF_REG_DUALTEX7_ID 0x1057
|
||||
|
||||
#define XF_REG_INVTXSPEC(ncols, nnorms, ntexs) \
|
||||
( \
|
||||
(ncols) << 0 | \
|
||||
(nnorms) << 2 | \
|
||||
(ntexs) << 4 \
|
||||
)
|
||||
|
||||
#define XF_REG_TEX(proj, form, tgType, row, embossRow, embossLit) \
|
||||
( \
|
||||
(proj) << 1 | \
|
||||
(form) << 2 | \
|
||||
(tgType) << 4 | \
|
||||
(row) << 7 | \
|
||||
(embossRow) << 12 | \
|
||||
(embossLit) << 15 \
|
||||
)
|
||||
|
||||
#define XF_REG_DUALTEX(mtx, normalize) \
|
||||
( \
|
||||
(mtx) << 0 | \
|
||||
(normalize) << 8 \
|
||||
)
|
||||
|
||||
#define BP_GEN_MODE(nTexGens, nChans, nTevs, p4, nInds) \
|
||||
( \
|
||||
(u32)(nTexGens) << 0 | \
|
||||
(u32)(nChans) << 4 | \
|
||||
(u32)(nTevs) << 10 | \
|
||||
(u32)(p4) << 14 | \
|
||||
(u32)(nInds) << 16 \
|
||||
)
|
||||
|
||||
#define BP_LP_SIZE(lineWidth, pointSize, lineOffset, pointOffset, lineHalfAspect, p5) \
|
||||
( \
|
||||
(u32)(lineWidth) << 0 | \
|
||||
(u32)(pointSize) << 8 | \
|
||||
(u32)(lineOffset) << 16 | \
|
||||
(u32)(pointOffset) << 19 | \
|
||||
(u32)(lineHalfAspect) << 22 | \
|
||||
(u32)(p5) << 24 \
|
||||
)
|
||||
|
||||
void GDSetVtxDescv(const GXVtxDescList* attrPtr);
|
||||
void GDSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList* list);
|
||||
void GDSetArraySized(GXAttr attr, void* base_ptr, u32 size, u8 stride, bool le);
|
||||
void GDSetArray(GXAttr attr, void* base_ptr, u8 stride);
|
||||
void GDSetArrayRaw(GXAttr attr, u32 base_ptr_raw, u8 stride);
|
||||
void GDPatchArrayPtr(void* base_ptr);
|
||||
void GDSetTexCoordGen(GXTexCoordID dst_coord, GXTexGenType func, GXTexGenSrc src_param, u8 normalize, u32 postmtx);
|
||||
void GDSetCullMode(GXCullMode mode);
|
||||
void GDSetGenMode(u8 nTexGens, u8 nChans, u8 nTevs);
|
||||
void GDSetGenMode2(u8 nTexGens, u8 nChans, u8 nTevs, u8 nInds, GXCullMode cm);
|
||||
void GDSetLPSize(u8 lineWidth, u8 pointSize, GXTexOffset lineOffset, GXTexOffset pointOffset, u8 lineHalfAspect);
|
||||
void GDSetCoPlanar(u8 enable);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,91 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_INDIRECT_H_
|
||||
#define _DOLPHIN_GD_INDIRECT_H_
|
||||
|
||||
#include <dolphin/types.h>
|
||||
#include <dolphin/gx/GXEnum.h>
|
||||
#include <dolphin/mtx.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BP_TEV_INDIRECT(ind_stage, format, bias_sel, alpha_sel, mtx_sel, wrap_s, wrap_t, utc_lod, add_prev, id) \
|
||||
( \
|
||||
(u32)(ind_stage) << 0 | \
|
||||
(u32)(format) << 2 | \
|
||||
(u32)(bias_sel) << 4 | \
|
||||
(u32)(alpha_sel) << 7 | \
|
||||
(u32)(mtx_sel) << 9 | \
|
||||
(u32)(wrap_s) << 13 | \
|
||||
(u32)(wrap_t) << 16 | \
|
||||
(u32)(utc_lod) << 19 | \
|
||||
(u32)(add_prev) << 20 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_IND_MTX(m0, m1, scale_exp, id) \
|
||||
( \
|
||||
(u32)(m0) << 0 | \
|
||||
(u32)(m1) << 11 | \
|
||||
(u32)(scale_exp) << 22 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_IND_TEXCOORD_SCALE(scaleS0, scaleT0, scaleS1, scaleT1, id) \
|
||||
( \
|
||||
(u32)(scaleS0) << 0 | \
|
||||
(u32)(scaleT0) << 4 | \
|
||||
(u32)(scaleS1) << 8 | \
|
||||
(u32)(scaleT1) << 12 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_IND_TEX_ORDER(map0, coord0, map1, coord1, map2, coord2, map3, coord3, id) \
|
||||
( \
|
||||
(u32)(map0) << 0 | \
|
||||
(u32)(coord0) << 3 | \
|
||||
(u32)(map1) << 6 | \
|
||||
(u32)(coord1) << 9 | \
|
||||
(u32)(map2) << 12 | \
|
||||
(u32)(coord2) << 15 | \
|
||||
(u32)(map3) << 18 | \
|
||||
(u32)(coord3) << 21 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_IND_MASK(mask, id) \
|
||||
( \
|
||||
(u32)(mask) << 0 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
void GDSetTevIndirect(GXTevStageID tev_stage, GXIndTexStageID ind_stage,
|
||||
GXIndTexFormat format, GXIndTexBiasSel bias_sel,
|
||||
GXIndTexMtxID matrix_sel, GXIndTexWrap wrap_s,
|
||||
GXIndTexWrap wrap_t, u8 add_prev, u8 utc_lod,
|
||||
GXIndTexAlphaSel alpha_sel);
|
||||
void GDSetIndTexMtx(GXIndTexMtxID mtx_id, const f32 offset[2][3], s8 scale_exp);
|
||||
void GDSetIndTexCoordScale(GXIndTexStageID indStageEven, GXIndTexScale scaleS0,
|
||||
GXIndTexScale scaleT0, GXIndTexScale scaleS1,
|
||||
GXIndTexScale scaleT1);
|
||||
void GDSetIndTexOrder(GXTexCoordID texCoord0, GXTexMapID texMap0,
|
||||
GXTexCoordID texCoord1, GXTexMapID texMap1,
|
||||
GXTexCoordID texCoord2, GXTexMapID texMap2,
|
||||
GXTexCoordID texCoord3, GXTexMapID texMap3);
|
||||
void GDSetTevDirect(GXTevStageID tev_stage);
|
||||
void GDSetTevIndWarp(GXTevStageID tev_stage, GXIndTexStageID ind_stage, u8 signed_offset, u8 replace_mode, GXIndTexMtxID matrix_sel);
|
||||
void GDSetTevIndTile(GXTevStageID tev_stage, GXIndTexStageID ind_stage,
|
||||
u16 tilesize_s, u16 tilesize_t, u16 tilespacing_s,
|
||||
u16 tilespacing_t, GXIndTexFormat format,
|
||||
GXIndTexMtxID matrix_sel, GXIndTexBiasSel bias_sel,
|
||||
GXIndTexAlphaSel alpha_sel);
|
||||
void GDSetTevIndBumpST(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel);
|
||||
void GDSetTevIndBumpXYZ(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel);
|
||||
void GDSetTevIndRepeat(GXTevStageID tev_stage);
|
||||
void __GDSetIndTexMask(u32 mask);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,65 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_LIGHT_H_
|
||||
#define _DOLPHIN_GD_LIGHT_H_
|
||||
|
||||
#include <dolphin/gx/GXEnum.h>
|
||||
#include <dolphin/gx/GXStruct.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define XF_LIGHT_ID 0x0600
|
||||
#define XF_LIGHT_COLOR_ID 0x0603
|
||||
#define XF_LIGHT_ATTN_ID 0x0604
|
||||
#define XF_LIGHT_DISTATTN_ID 0x0607
|
||||
#define XF_LIGHT_POS_ID 0x060A
|
||||
#define XF_LIGHT_SPEC_DIR_ID 0x060A
|
||||
#define XF_LIGHT_DIR_ID 0x060D
|
||||
|
||||
#define XF_REG_AMBIENT0_ID 0x100A
|
||||
#define XF_REG_AMBIENT1_ID 0x100B
|
||||
#define XF_REG_MATERIAL0_ID 0x100C
|
||||
#define XF_REG_MATERIAL1_ID 0x100D
|
||||
#define XF_REG_COLOR0CNTRL_ID 0x100E
|
||||
#define XF_REG_COLOR1CNTRL_ID 0x100F
|
||||
#define XF_REG_ALPHA0CNTRL_ID 0x1010
|
||||
#define XF_REG_ALPHA1CNTRL_ID 0x1011
|
||||
|
||||
#define XF_REG_CHAN_CTRL(matsrc, enable, lightmask0, ambsrc, diff_fn, p5, p6, lightmask4) \
|
||||
( \
|
||||
(u32)(matsrc) << 0 | \
|
||||
(u32)(enable) << 1 | \
|
||||
(u32)(lightmask0) << 2 | \
|
||||
(u32)(ambsrc) << 6 | \
|
||||
(u32)(diff_fn) << 7 | \
|
||||
(u32)(p5) << 9 | \
|
||||
(u32)(p6) << 10 | \
|
||||
(u32)(lightmask4) << 11 \
|
||||
)
|
||||
|
||||
void GDSetLightAttn(GXLightID light, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2);
|
||||
void GDSetLightSpot(GXLightID light, f32 cutoff, GXSpotFn spot_func);
|
||||
void GDSetLightDistAttn(GXLightID light, f32 ref_dist, f32 ref_br, GXDistAttnFn dist_func);
|
||||
void GDSetLightColor(GXLightID light, GXColor color);
|
||||
void GDSetLightPos(GXLightID light, f32 x, f32 y, f32 z);
|
||||
void GDSetLightDir(GXLightID light, f32 nx, f32 ny, f32 nz);
|
||||
void GDSetSpecularDirHA(GXLightID light, f32 nx, f32 ny, f32 nz, f32 hx, f32 hy, f32 hz);
|
||||
void GDSetSpecularDir(GXLightID light, f32 nx, f32 ny, f32 nz);
|
||||
void GDLoadLightObjIndx(u32 lt_obj_indx, GXLightID light);
|
||||
void GDSetChanAmbColor(GXChannelID chan, GXColor color);
|
||||
void GDSetChanMatColor(GXChannelID chan, GXColor color);
|
||||
void GDSetChanCtrl(GXChannelID chan, u8 enable, GXColorSrc amb_src,
|
||||
GXColorSrc mat_src, u32 light_mask, GXDiffuseFn diff_fn,
|
||||
GXAttnFn attn_fn);
|
||||
|
||||
u16 __GDLightID2Index(GXLightID id);
|
||||
|
||||
inline static u16 __GDLightID2Offset(GXLightID id) {
|
||||
return __GDLightID2Index(id) * 16;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_PIXEL_H
|
||||
#define _DOLPHIN_GD_PIXEL_H
|
||||
|
||||
#include <dolphin/gx/GXEnum.h>
|
||||
#include <dolphin/gx/GXStruct.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BP_FOG_UNK0(a, id) \
|
||||
( \
|
||||
(u32)(a) << 0 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_FOG_UNK1(b_m, id) \
|
||||
( \
|
||||
(u32)(b_m) << 0 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_FOG_UNK2(b_expn, id) \
|
||||
( \
|
||||
(u32)(b_expn) << 0 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_FOG_UNK3(c, proj, fsel, id) \
|
||||
( \
|
||||
(u32)(c) << 0 | \
|
||||
(u32)(proj) << 20 | \
|
||||
(u32)(fsel) << 21 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_FOG_COLOR(r, g, b, id) \
|
||||
( \
|
||||
(u32)(b) << 0 | \
|
||||
(u32)(g) << 8 | \
|
||||
(u32)(r) << 16 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_BLEND_MODE(enable, enable_logic, enable_dither, enable_color_update, enable_alpha_update, dst_factor, src_factor, blend_sub, logic_op, id) \
|
||||
( \
|
||||
(u32)(enable) << 0 | \
|
||||
(u32)(enable_logic) << 1 | \
|
||||
(u32)(enable_dither) << 2 | \
|
||||
(u32)(enable_color_update) << 3 | \
|
||||
(u32)(enable_alpha_update) << 4 | \
|
||||
(u32)(dst_factor) << 5 | \
|
||||
(u32)(src_factor) << 8 | \
|
||||
(u32)(blend_sub) << 11 | \
|
||||
(u32)(logic_op) << 12 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_Z_MODE(enable_compare, compare_fn, enable_update, id) \
|
||||
( \
|
||||
(u32)(enable_compare) << 0 | \
|
||||
(u32)(compare_fn) << 1 | \
|
||||
(u32)(enable_update) << 4 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_DST_ALPHA(alpha, enable, id) \
|
||||
( \
|
||||
(u32)(alpha) << 0 | \
|
||||
(u32)(enable) << 8 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TOKEN(token, id) \
|
||||
( \
|
||||
(u32)(token) << 0 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
void GDSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color);
|
||||
void GDSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp logic_op);
|
||||
void GDSetBlendModeEtc(GXBlendMode type, GXBlendFactor src_factor,
|
||||
GXBlendFactor dst_factor, GXLogicOp logic_op,
|
||||
u8 color_update_enable,
|
||||
u8 alpha_update_enable,
|
||||
u8 dither_enable);
|
||||
void GDSetZMode(u8 compare_enable, GXCompare func, u8 update_enable);
|
||||
void GDSetDstAlpha(u8 enable, u8 alpha);
|
||||
void GDSetDrawSync(u16 token);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,133 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_TEV_H
|
||||
#define _DOLPHIN_GD_TEV_H
|
||||
|
||||
#include <dolphin/gx/GXEnum.h>
|
||||
#include <dolphin/gx/GXStruct.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BP_TEV_COLOR(d, c, b, a, bias, op, clamp, scale, out, id) \
|
||||
( \
|
||||
(u32)(d) << 0 | \
|
||||
(u32)(c) << 4 | \
|
||||
(u32)(b) << 8 | \
|
||||
(u32)(a) << 12 | \
|
||||
(u32)(bias) << 16 | \
|
||||
(u32)(op) << 18 | \
|
||||
(u32)(clamp) << 19 | \
|
||||
(u32)(scale) << 20 | \
|
||||
(u32)(out) << 22 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEV_ALPHA(ras_sel, tex_sel, d, c, b, a, bias, op, clamp, scale, out, id) \
|
||||
( \
|
||||
(u32)(ras_sel) << 0 | \
|
||||
(u32)(tex_sel) << 2 | \
|
||||
(u32)(d) << 4 | \
|
||||
(u32)(c) << 7 | \
|
||||
(u32)(b) << 10 | \
|
||||
(u32)(a) << 13 | \
|
||||
(u32)(bias) << 16 | \
|
||||
(u32)(op) << 18 | \
|
||||
(u32)(clamp) << 19 | \
|
||||
(u32)(scale) << 20 | \
|
||||
(u32)(out) << 22 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEV_COLOR_REG_RA(r, a, reg, id) \
|
||||
( \
|
||||
(u32)(r) << 0 | \
|
||||
(u32)(a) << 12 | \
|
||||
(u32)(reg) << 23 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEV_COLOR_REG_BG(b, g, reg, id) \
|
||||
( \
|
||||
(u32)(b) << 0 | \
|
||||
(u32)(g) << 12 | \
|
||||
(u32)(reg) << 23 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEV_KSEL(rb, ga, kcsel0, kasel0, kcsel1, kasel1, id) \
|
||||
( \
|
||||
(u32)(rb) << 0 | \
|
||||
(u32)(ga) << 2 | \
|
||||
(u32)(kcsel0) << 4 | \
|
||||
(u32)(kasel0) << 9 | \
|
||||
(u32)(kcsel1) << 14 | \
|
||||
(u32)(kasel1) << 19 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_ALPHA_COMPARE(ref0, ref1, comp0, comp1, op, id) \
|
||||
( \
|
||||
(u32)(ref0) << 0 | \
|
||||
(u32)(ref1) << 8 | \
|
||||
(u32)(comp0) << 16 | \
|
||||
(u32)(comp1) << 19 | \
|
||||
(u32)(op) << 22 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_ZTEX_PARAMS_0(bias, id) \
|
||||
( \
|
||||
(u32)(bias) << 0 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_ZTEX_PARAMS_1(zfmt, op, id) \
|
||||
( \
|
||||
(u32)(zfmt) << 0 | \
|
||||
(u32)(op) << 2 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEV_ORDER(map0, coord0, enable0, color0, map1, coord1, enable1, color1, id) \
|
||||
( \
|
||||
(u32)(map0) << 0 | \
|
||||
(u32)(coord0) << 3 | \
|
||||
(u32)(enable0) << 6 | \
|
||||
(u32)(color0) << 7 | \
|
||||
(u32)(map1) << 12 | \
|
||||
(u32)(coord1) << 15 | \
|
||||
(u32)(enable1) << 18 | \
|
||||
(u32)(color1) << 19 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
void GDSetTevOp(GXTevStageID stage, GXTevMode mode);
|
||||
void GDSetTevColorCalc(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b,
|
||||
GXTevColorArg c, GXTevColorArg d, GXTevOp op,
|
||||
GXTevBias bias, GXTevScale scale, u8 clamp,
|
||||
GXTevRegID out_reg);
|
||||
void GDSetTevAlphaCalcAndSwap(GXTevStageID stage, GXTevAlphaArg a,
|
||||
GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d,
|
||||
GXTevOp op, GXTevBias bias, GXTevScale scale,
|
||||
u8 clamp, GXTevRegID out_reg,
|
||||
GXTevSwapSel ras_sel, GXTevSwapSel tex_sel);
|
||||
void GDSetTevColor(GXTevRegID reg, GXColor color);
|
||||
void GDSetTevColorS10(GXTevRegID reg, GXColorS10 color);
|
||||
void GDSetTevKColor(GXTevKColorID reg, GXColor color);
|
||||
void GDSetTevKonstantSel(GXTevStageID evenStage, GXTevKColorSel kcsel0,
|
||||
GXTevKAlphaSel kasel0, GXTevKColorSel kcsel1,
|
||||
GXTevKAlphaSel kasel1);
|
||||
void GDSetTevSwapModeTable(GXTevSwapSel table, GXTevColorChan red,
|
||||
GXTevColorChan green, GXTevColorChan blue,
|
||||
GXTevColorChan alpha);
|
||||
void GDSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1);
|
||||
void GDSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias);
|
||||
void GDSetTevOrder(GXTevStageID evenStage, GXTexCoordID coord0, GXTexMapID map0,
|
||||
GXChannelID color0, GXTexCoordID coord1, GXTexMapID map1,
|
||||
GXChannelID color1);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,127 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_TEXTURE_H
|
||||
#define _DOLPHIN_GD_TEXTURE_H
|
||||
|
||||
#include <dolphin/types.h>
|
||||
#include <dolphin/gx/GXEnum.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BP_TEX_MODE0(wrap_s, wrap_t, mag_filt, min_filt, edge_lod, lod_bias, max_aniso, bias_clamp, id) \
|
||||
( \
|
||||
(u32)(wrap_s) << 0 | \
|
||||
(u32)(wrap_t) << 2 | \
|
||||
(u32)(mag_filt) << 4 | \
|
||||
(u32)(min_filt) << 5 | \
|
||||
(u32)(edge_lod) << 8 | \
|
||||
(u32)(lod_bias) << 9 | \
|
||||
(u32)(max_aniso) << 19 | \
|
||||
(u32)(bias_clamp) << 21 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEX_MODE1(min_lod, max_lod, id) \
|
||||
( \
|
||||
(u32)(min_lod) << 0 | \
|
||||
(u32)(max_lod) << 8 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_IMAGE_ATTR(width, height, format, id) \
|
||||
( \
|
||||
(u32)(width) << 0 | \
|
||||
(u32)(height) << 10 | \
|
||||
(u32)(format) << 20 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_IMAGE_PTR(ptr, id) \
|
||||
( \
|
||||
(u32)(ptr) << 0 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEX_CACHE_EVEN(tmem, size0, size1, type, id) \
|
||||
( \
|
||||
(u32)(tmem) << 0 | \
|
||||
(u32)(size0) << 15 | \
|
||||
(u32)(size1) << 18 | \
|
||||
(u32)(type) << 21 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEX_CACHE_ODD(tmem, size0, size1, id) \
|
||||
( \
|
||||
(u32)(tmem) << 0 | \
|
||||
(u32)(size0) << 15 | \
|
||||
(u32)(size1) << 18 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEX_TLUT(tmem, format, id) \
|
||||
( \
|
||||
(u32)(tmem) << 0 | \
|
||||
(u32)(format) << 10 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEXCOORD_S_SCALE(s_scale, s_bias, s_wrap, line_offset, point_offset, id) \
|
||||
( \
|
||||
(u32)(s_scale) << 0 | \
|
||||
(u32)(s_bias) << 16 | \
|
||||
(u32)(s_wrap) << 17 | \
|
||||
(u32)(line_offset) << 18 | \
|
||||
(u32)(point_offset) << 19 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_TEXCOORD_T_SCALE(t_scale, t_bias, t_wrap, id) \
|
||||
( \
|
||||
(u32)(t_scale) << 0 | \
|
||||
(u32)(t_bias) << 16 | \
|
||||
(u32)(t_wrap) << 17 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_LOAD_TLUT0(ptr, id) \
|
||||
( \
|
||||
(u32)(ptr) << 0 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
#define BP_LOAD_TLUT1(ptr, size, id) \
|
||||
( \
|
||||
(u32)(ptr) << 0 | \
|
||||
(u32)(size) << 10 | \
|
||||
(u32)(id) << 24 \
|
||||
)
|
||||
|
||||
void GDSetTexLookupMode(GXTexMapID id, GXTexWrapMode wrap_s,
|
||||
GXTexWrapMode wrap_t, GXTexFilter min_filt,
|
||||
GXTexFilter mag_filt, f32 min_lod, f32 max_lod,
|
||||
f32 lod_bias, u8 bias_clamp, u8 do_edge_lod,
|
||||
GXAnisotropy max_aniso);
|
||||
|
||||
void GDSetTexImgAttr(GXTexMapID id, u16 width, u16 height, GXTexFmt format);
|
||||
void GDSetTexImgPtr(GXTexMapID id, void* image_ptr);
|
||||
void GDSetTexImgPtrRaw(GXTexMapID id, u32 image_ptr_raw);
|
||||
void GDPatchTexImgPtr(void* image_ptr);
|
||||
void GDSetTexCached(GXTexMapID id, u32 tmem_even, GXTexCacheSize size_even,
|
||||
u32 tmem_odd, GXTexCacheSize size_odd);
|
||||
void GDSetTexPreLoaded(GXTexMapID id, u32 tmem_even, u32 tmem_odd);
|
||||
void GDSetTexTlut(GXTexMapID id, u32 tmem_addr, GXTlutFmt format);
|
||||
void GDSetTexCoordScale(GXTexCoordID coord, u16 s_scale, u16 t_scale);
|
||||
void GDSetTexCoordScale2(GXTexCoordID coord, u16 s_scale, u8 s_bias,
|
||||
u8 s_wrap, u16 t_scale, u8 t_bias, u8 t_wrap);
|
||||
void GDSetTexCoordScaleAndTOEs(GXTexCoordID coord, u16 s_scale, u8 s_bias,
|
||||
u8 s_wrap, u16 t_scale, u8 t_bias, u8 t_wrap,
|
||||
u8 line_offset, u8 point_offset);
|
||||
void GDLoadTlut(void* tlut_ptr, u32 tmem_addr, GXTlutSize size);
|
||||
void GDLoadTlutRaw(u32 tlut_ptr_raw, u32 tmem_addr, GXTlutSize size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef _DOLPHIN_GD_TRANSFORM_H_
|
||||
#define _DOLPHIN_GD_TRANSFORM_H_
|
||||
|
||||
#include <dolphin/types.h>
|
||||
#include <dolphin/gx/GXEnum.h>
|
||||
#include <dolphin/mtx.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CP_MTX_REG_A_ID 0x30
|
||||
#define CP_MTX_REG_B_ID 0x40
|
||||
|
||||
#define XF_REG_MATRIXINDEX0_ID 0x1018
|
||||
#define XF_REG_MATRIXINDEX1_ID 0x1019
|
||||
#define XF_REG_PROJECTIONA_ID 0x1020
|
||||
#define XF_REG_PROJECTIONB_ID 0x1021
|
||||
#define XF_REG_PROJECTIONC_ID 0x1022
|
||||
#define XF_REG_PROJECTIOND_ID 0x1023
|
||||
#define XF_REG_PROJECTIONE_ID 0x1024
|
||||
#define XF_REG_PROJECTIONF_ID 0x1025
|
||||
#define XF_REG_PROJECTORTHO_ID 0x1026
|
||||
|
||||
#define CP_MTX_REG_A(pn, t0, t1, t2, t3) \
|
||||
( \
|
||||
(u32)(pn) << 0 | \
|
||||
(u32)(t0) << 6 | \
|
||||
(u32)(t1) << 12 | \
|
||||
(u32)(t2) << 18 | \
|
||||
(u32)(t3) << 24 \
|
||||
)
|
||||
|
||||
#define CP_MTX_REG_B(t4, t5, t6, t7) \
|
||||
( \
|
||||
(u32)(t4) << 0 | \
|
||||
(u32)(t5) << 6 | \
|
||||
(u32)(t6) << 12 | \
|
||||
(u32)(t7) << 18 \
|
||||
)
|
||||
|
||||
void GDLoadPosMtxImm(const Mtx mtx, u32 id);
|
||||
void GDLoadPosMtxIndx(u16 mtx_indx, u32 id);
|
||||
void GDLoadNrmMtxImm(const Mtx mtx, u32 id);
|
||||
void GDLoadNrmMtxImm3x3(const f32 mtx[3][3], u32 id);
|
||||
void GDLoadNrmMtxIndx3x3(u16 mtx_indx, u32 id);
|
||||
void GDLoadTexMtxImm(const Mtx mtx, u32 id, GXTexMtxType type);
|
||||
void GDLoadTexMtxIndx(u16 mtx_indx, u32 id, GXTexMtxType type);
|
||||
void GDSetCurrentMtx(u32 pn, u32 t0, u32 t1, u32 t2, u32 t3, u32 t4, u32 t5, u32 t6, u32 t7);
|
||||
void GDSetProjection(const Mtx44 mtx, GXProjectionType type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef _DOLPHIN_GF_H_
|
||||
#define _DOLPHIN_GF_H_
|
||||
|
||||
#include <dolphin/gf/GFGeometry.h>
|
||||
#include <dolphin/gf/GFLight.h>
|
||||
#include <dolphin/gf/GFPixel.h>
|
||||
#include <dolphin/gf/GFTev.h>
|
||||
|
||||
#endif
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef _DOLPHIN_GF_GFGEOMETRY_H_
|
||||
#define _DOLPHIN_GF_GFGEOMETRY_H_
|
||||
|
||||
#include <dolphin/gx.h>
|
||||
|
||||
#define GF_GEN_MODE(nTexGens, nChans, nTevs, cm, nInds) \
|
||||
( \
|
||||
(u32)(nTexGens) << 0 | \
|
||||
(u32)(nChans) << 4 | \
|
||||
(u32)(nTevs) << 10 | \
|
||||
(u32)(cm) << 14 | \
|
||||
(u32)(nInds) << 16 \
|
||||
)
|
||||
|
||||
static inline void GFWrite_u8(u8 data) {
|
||||
GXCmd1u8(data);
|
||||
}
|
||||
|
||||
static inline void GFWrite_u32(u32 data) {
|
||||
GXCmd1u32(data);
|
||||
}
|
||||
|
||||
static inline void GFWrite_u16(u16 data) {
|
||||
GXCmd1u16(data);
|
||||
}
|
||||
|
||||
static inline void GFWriteBPCmd(u32 regval) {
|
||||
GFWrite_u8(GX_LOAD_BP_REG);
|
||||
GFWrite_u32(regval);
|
||||
}
|
||||
|
||||
static inline void GFWriteXFCmd(u16 addr, u32 val) {
|
||||
GFWrite_u8(GX_LOAD_XF_REG);
|
||||
GFWrite_u16(0);
|
||||
GFWrite_u16(addr);
|
||||
GFWrite_u32(val);
|
||||
}
|
||||
|
||||
void GFSetGenMode2(u8 nTexGens, u8 nChans, u8 nTevs, u8 nInds, GXCullMode cm);
|
||||
|
||||
#endif /* _DOLPHIN_GF_GFGEOMETRY_H_ */
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef _DOLPHIN_GF_GFLIGHT_H
|
||||
#define _DOLPHIN_GF_GFLIGHT_H
|
||||
|
||||
#include <dolphin/gx.h>
|
||||
|
||||
void GFSetChanAmbColor(GXChannelID chan, GXColor color);
|
||||
|
||||
#endif /* _DOLPHIN_GF_GFLIGHT_H */
|
||||
@@ -1,13 +0,0 @@
|
||||
#ifndef _DOLPHIN_GF_GFPIXEL_H
|
||||
#define _DOLPHIN_GF_GFPIXEL_H
|
||||
|
||||
#include <dolphin/gx.h>
|
||||
|
||||
void GFSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color);
|
||||
void GFSetBlendModeEtc(GXBlendMode type, GXBlendFactor src_factor,
|
||||
GXBlendFactor dst_factor, GXLogicOp logic_op,
|
||||
u8 color_update_enable, u8 alpha_update_enable,
|
||||
u8 dither_enable);
|
||||
void GFSetZMode(u8 compare_enable, GXCompare func, u8 update_enable);
|
||||
|
||||
#endif /* _DOLPHIN_GF_GFPIXEL_H */
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef _DOLPHIN_GF_GFTEV_H
|
||||
#define _DOLPHIN_GF_GFTEV_H
|
||||
|
||||
#include <dolphin/gx.h>
|
||||
|
||||
void GFSetTevColorS10(GXTevRegID reg, GXColorS10 color);
|
||||
|
||||
#endif /* _DOLPHIN_GF_GFTEV_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user