mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-10-28 08:06:19 -04:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b23d38e241 | |||
| 954c43127c | |||
| 7d048d604b | |||
| 4ae883ec84 | |||
| 252d00f697 |
@@ -4,9 +4,3 @@
|
|||||||
# Patch files must stay LF: git apply matches context bytes against LF upstream sources
|
# Patch files must stay LF: git apply matches context bytes against LF upstream sources
|
||||||
*.patch -text
|
*.patch -text
|
||||||
translator/tests/Translator.Tests/TestAssets/**/*.bin binary
|
translator/tests/Translator.Tests/TestAssets/**/*.bin binary
|
||||||
|
|
||||||
# Region tables
|
|
||||||
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_versions.inc linguist-generated=true
|
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ jobs:
|
|||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Test macOS app dependency packaging
|
- name: Test macOS app dependency packaging
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -102,7 +101,6 @@ jobs:
|
|||||||
mkw_nand_settings_tests \
|
mkw_nand_settings_tests \
|
||||||
mkw_sc_serial_tests \
|
mkw_sc_serial_tests \
|
||||||
mkw_input_expr_tests \
|
mkw_input_expr_tests \
|
||||||
mkw_bluetooth_controller_tests \
|
|
||||||
mkw_macos_native_compile \
|
mkw_macos_native_compile \
|
||||||
mkw_macos_context_abi_tests \
|
mkw_macos_context_abi_tests \
|
||||||
mkw_macos_host_context_tests \
|
mkw_macos_host_context_tests \
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ jobs:
|
|||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v6
|
- uses: actions/setup-dotnet@v6
|
||||||
with:
|
with:
|
||||||
@@ -80,7 +79,6 @@ jobs:
|
|||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v6
|
- uses: actions/setup-dotnet@v6
|
||||||
with:
|
with:
|
||||||
@@ -104,7 +102,6 @@ jobs:
|
|||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v6
|
- uses: actions/setup-dotnet@v6
|
||||||
with:
|
with:
|
||||||
@@ -238,7 +235,6 @@ jobs:
|
|||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
# Wheel Wizard runs the downloaded setup with --version and refuses it when the reported
|
# 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
|
# version differs from the release tag, so a tag that was pushed without bumping the pinned
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ jobs:
|
|||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v6
|
- uses: actions/setup-dotnet@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
+1
-2
@@ -66,8 +66,7 @@ project.lock.json
|
|||||||
/.vs/
|
/.vs/
|
||||||
/.vscode/
|
/.vscode/
|
||||||
/.idea/
|
/.idea/
|
||||||
/tools/*
|
/tools/
|
||||||
__pycache__/
|
|
||||||
/TEMP/
|
/TEMP/
|
||||||
/tmp/
|
/tmp/
|
||||||
/test_output/
|
/test_output/
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
[submodule "aurora-main"]
|
|
||||||
path = aurora-main
|
|
||||||
url = https://github.com/patchzyy/aurora-wiicompiled.git
|
|
||||||
branch = main
|
|
||||||
@@ -23,23 +23,12 @@ $publish = Join-Path $workRoot 'publish'
|
|||||||
$payloadRoot = Join-Path $workRoot 'payload'
|
$payloadRoot = Join-Path $workRoot 'payload'
|
||||||
$setupProject = Join-Path $PSScriptRoot 'WiiCompiled.Setup.Windows\WiiCompiled.Setup.Windows.csproj'
|
$setupProject = Join-Path $PSScriptRoot 'WiiCompiled.Setup.Windows\WiiCompiled.Setup.Windows.csproj'
|
||||||
$translatorProject = Join-Path $repoRoot 'translator\src\Translator.Cli\Translator.Cli.csproj'
|
$translatorProject = Join-Path $repoRoot 'translator\src\Translator.Cli\Translator.Cli.csproj'
|
||||||
|
$projectFile = Join-Path $repoRoot 'projects\mkwii\recomp.yml'
|
||||||
|
|
||||||
# Every supported release is one projects/<name>/recomp.yml. Everything Mario-Kart-specific in the
|
# Everything Mario-Kart-specific in the manifest below is read from the project file rather than
|
||||||
# manifest below is read from those files rather than restated here, and Test-PinnedFacts.ps1
|
# restated here, and Test-PinnedFacts.ps1 checks the copies that cannot read it (the C++ entry
|
||||||
# checks the copies that cannot read them (the C++ entry address, the C# Retro-WFC table, the
|
# address, the C# endpoint constant, the lists this script and the installed host both carry).
|
||||||
# lists this script and the installed host both carry).
|
$pins = Get-MkwProjectPins $projectFile
|
||||||
$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
|
# The audit reports by throwing, which aborts this run; nothing native has been invoked yet, so
|
||||||
# there is no exit code to inspect.
|
# there is no exit code to inspect.
|
||||||
& (Join-Path $PSScriptRoot 'Test-PinnedFacts.ps1') -RepositoryRoot $repoRoot
|
& (Join-Path $PSScriptRoot 'Test-PinnedFacts.ps1') -RepositoryRoot $repoRoot
|
||||||
@@ -84,16 +73,7 @@ function Resolve-VcRuntimeDirectory([string]$RequestedPath) {
|
|||||||
function Copy-Directory([string]$Source, [string]$Destination) {
|
function Copy-Directory([string]$Source, [string]$Destination) {
|
||||||
Assert-Directory $Source "Source directory"
|
Assert-Directory $Source "Source directory"
|
||||||
[IO.Directory]::CreateDirectory($Destination) | Out-Null
|
[IO.Directory]::CreateDirectory($Destination) | Out-Null
|
||||||
# Source payloads are materialized trees, independent of Git checkout metadata.
|
Copy-Item -Path (Join-Path $Source '*') -Destination $Destination -Recurse -Force
|
||||||
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) {
|
function Compress-Zip([string]$Source, [string]$Destination, [string[]]$Entries) {
|
||||||
$tar = Join-Path $env:SystemRoot 'System32\tar.exe'
|
$tar = Join-Path $env:SystemRoot 'System32\tar.exe'
|
||||||
@@ -254,9 +234,7 @@ if (Test-Path -LiteralPath $runtimeDeveloperBuild) {
|
|||||||
}
|
}
|
||||||
$auroraExtern = Join-Path $workspace 'aurora-main\extern'
|
$auroraExtern = Join-Path $workspace 'aurora-main\extern'
|
||||||
Get-ChildItem -LiteralPath $auroraExtern -Directory -Force | Remove-Item -Recurse -Force
|
Get-ChildItem -LiteralPath $auroraExtern -Directory -Force | Remove-Item -Recurse -Force
|
||||||
foreach ($releaseProject in $releaseProjects) {
|
Copy-Directory (Join-Path $repoRoot 'projects\mkwii') (Join-Path $workspace 'projects\mkwii')
|
||||||
Copy-Directory $releaseProject.FullName (Join-Path $workspace "projects\$($releaseProject.Name)")
|
|
||||||
}
|
|
||||||
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'LocalBuild.ps1') -Destination (Join-Path $workspace 'LocalBuild.ps1')
|
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.
|
# 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')
|
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'NativeBuildFlags.ps1') -Destination (Join-Path $workspace 'NativeBuildFlags.ps1')
|
||||||
@@ -266,8 +244,7 @@ foreach ($name in $requiredDependencies) { Copy-Directory (Join-Path $dependency
|
|||||||
# The translation identity covers the runtime's native registrations through this index (see
|
# The translation identity covers the runtime's native registrations through this index (see
|
||||||
# ToolkitFingerprint), so it is extracted from exactly the staged runtime sources.
|
# ToolkitFingerprint), so it is extracted from exactly the staged runtime sources.
|
||||||
$nativeIndex = Join-Path $workspace 'runtime\native-index.json'
|
$nativeIndex = Join-Path $workspace 'runtime\native-index.json'
|
||||||
# The payload has no game inputs, so the project file (which validates them) cannot be loaded here.
|
& $translator emit-native-index --project (Join-Path $workspace 'projects\mkwii\recomp.yml') --out $nativeIndex
|
||||||
& $translator emit-native-index --native-source-dir (Join-Path $workspace 'runtime\src') --out $nativeIndex
|
|
||||||
if ($LASTEXITCODE -ne 0) { throw "Native index extraction failed with exit code $LASTEXITCODE." }
|
if ($LASTEXITCODE -ne 0) { throw "Native index extraction failed with exit code $LASTEXITCODE." }
|
||||||
Assert-File $nativeIndex 'Runtime native index'
|
Assert-File $nativeIndex 'Runtime native index'
|
||||||
# A staged runtime that fingerprints differently from the shipped archive would make every
|
# A staged runtime that fingerprints differently from the shipped archive would make every
|
||||||
@@ -339,20 +316,22 @@ foreach ($required in @('ToolkitFingerprint','TranslationFingerprint','NativeToo
|
|||||||
$productVersion = ((& $setupHost --version) -join '').Trim()
|
$productVersion = ((& $setupHost --version) -join '').Trim()
|
||||||
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($productVersion)) { throw 'The setup host did not report its version.' }
|
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]@{
|
$manifest = [ordered]@{
|
||||||
SchemaVersion = 3
|
SchemaVersion = 2
|
||||||
ProductVersion = $productVersion
|
ProductVersion = $productVersion
|
||||||
SupportedReleases = $supportedReleases
|
ExpectedGameId = $pins.GameId
|
||||||
|
ExpectedDolSha256 = $pins.DolSha256
|
||||||
|
ExpectedRelSha256 = $pins.RelSha256
|
||||||
ToolkitReleaseTag = if ($ToolkitReleaseTag) { $ToolkitReleaseTag } else { '' }
|
ToolkitReleaseTag = if ($ToolkitReleaseTag) { $ToolkitReleaseTag } else { '' }
|
||||||
BuildModel = 'local-translation-and-compilation'
|
BuildModel = 'local-translation-and-compilation'
|
||||||
|
RetroWfcPayloadUri = $pins.RetroWfcPayloadUri
|
||||||
ToolkitFingerprint = $identities.ToolkitFingerprint
|
ToolkitFingerprint = $identities.ToolkitFingerprint
|
||||||
ToolkitPackageFingerprint = $identities.ToolkitPackageFingerprint
|
ToolkitPackageFingerprint = $identities.ToolkitPackageFingerprint
|
||||||
RuntimeAssetsFingerprint = $identities.RuntimeAssetsFingerprint
|
RuntimeAssetsFingerprint = $identities.RuntimeAssetsFingerprint
|
||||||
TranslationFingerprint = $identities.TranslationFingerprint
|
TranslationFingerprint = $identities.TranslationFingerprint
|
||||||
NativeToolchainFingerprint = $identities.NativeToolchainFingerprint
|
NativeToolchainFingerprint = $identities.NativeToolchainFingerprint
|
||||||
}
|
}
|
||||||
$manifest | ConvertTo-Json -Depth 4 | Set-Content (Join-Path $payloadRoot 'payload-manifest.json') -Encoding UTF8
|
$manifest | ConvertTo-Json | Set-Content (Join-Path $payloadRoot 'payload-manifest.json') -Encoding UTF8
|
||||||
|
|
||||||
Write-Host '[4/6] Enforcing the copyright and generated-code boundary...'
|
Write-Host '[4/6] Enforcing the copyright and generated-code boundary...'
|
||||||
# Both audits are PowerShell scripts that throw directly on failure (Test-PayloadBoundary.ps1
|
# Both audits are PowerShell scripts that throw directly on failure (Test-PayloadBoundary.ps1
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!-- The one product version. Release tags must match it. -->
|
<!-- The one product version. Release tags must match it. -->
|
||||||
<Version>0.2.35</Version>
|
<Version>0.2.34</Version>
|
||||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+12
-16
@@ -166,6 +166,7 @@ $toolchainBin = Join-Path $toolchain 'llvm-mingw\bin'
|
|||||||
$cc = Join-Path $toolchainBin 'x86_64-w64-mingw32-clang.exe'
|
$cc = Join-Path $toolchainBin 'x86_64-w64-mingw32-clang.exe'
|
||||||
$cxx = 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'
|
$windres = Join-Path $toolchainBin 'x86_64-w64-mingw32-windres.exe'
|
||||||
|
$project = Join-Path $Workspace 'projects\mkwii\recomp.yml'
|
||||||
$assets = Join-Path $Workspace 'Assets'
|
$assets = Join-Path $Workspace 'Assets'
|
||||||
$generated = Join-Path $Workspace 'generated'
|
$generated = Join-Path $Workspace 'generated'
|
||||||
$functions = Join-Path $generated 'functions'
|
$functions = Join-Path $generated 'functions'
|
||||||
@@ -182,18 +183,14 @@ $retroRoot = if ([string]::IsNullOrWhiteSpace($RetroRewindPackageDirectory)) {
|
|||||||
|
|
||||||
foreach ($required in @(
|
foreach ($required in @(
|
||||||
@($translator, 'Bundled translator'), @($cmake, 'Bundled CMake'), @($ninja, 'Bundled Ninja'),
|
@($translator, 'Bundled translator'), @($cmake, 'Bundled CMake'), @($ninja, 'Bundled Ninja'),
|
||||||
@($cc, 'Bundled C compiler'), @($cxx, 'Bundled C++ compiler'), @($windres, 'Bundled resource compiler'),
|
@($cc, 'Bundled C compiler'), @($cxx, 'Bundled C++ compiler'), @($windres, 'Bundled resource compiler'), @($project, 'Translation project'),
|
||||||
@((Join-Path $assets 'main.dol'), 'Extracted main.dol'), @((Join-Path $assets 'StaticR.rel'), 'Extracted StaticR.rel')
|
@((Join-Path $assets 'main.dol'), 'Extracted main.dol'), @((Join-Path $assets 'StaticR.rel'), 'Extracted StaticR.rel')
|
||||||
)) { Assert-File $required[0] $required[1] }
|
)) { Assert-File $required[0] $required[1] }
|
||||||
|
|
||||||
# Everything Mario-Kart-specific this script needs is read from the project file rather than
|
# 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
|
# 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. The project is
|
# translator loads itself) the module guest/link bases the mod translation uses.
|
||||||
# the one pinned to the extracted main.dol, which decides the region.
|
$pins = Get-MkwProjectPins $project
|
||||||
$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
|
# 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
|
# one heap that barely moves with thread count, so clamping it only slows translation), $translatedJobs
|
||||||
@@ -246,8 +243,7 @@ try {
|
|||||||
# outputs plus --prune-stale mean Ninja only recompiles shards whose bytes actually moved.
|
# outputs plus --prune-stale mean Ninja only recompiles shards whose bytes actually moved.
|
||||||
$reuseBase = $false
|
$reuseBase = $false
|
||||||
if (-not $ForceCleanBuild -and -not [string]::IsNullOrWhiteSpace($TranslationFingerprint) -and
|
if (-not $ForceCleanBuild -and -not [string]::IsNullOrWhiteSpace($TranslationFingerprint) -and
|
||||||
(Get-RecordedFingerprint $translationProvenance 'TranslationFingerprint') -eq $TranslationFingerprint -and
|
(Get-RecordedFingerprint $translationProvenance 'TranslationFingerprint') -eq $TranslationFingerprint) {
|
||||||
(Get-RecordedFingerprint $translationProvenance 'DolSha256') -eq $pins.DolSha256) {
|
|
||||||
$artifacts = @($baseMetadata, $baseManifest, (Join-Path $generated 'base_translation_sources.bin'),
|
$artifacts = @($baseMetadata, $baseManifest, (Join-Path $generated 'base_translation_sources.bin'),
|
||||||
(Join-Path $generated 'base_translation_mod_awareness.json'))
|
(Join-Path $generated 'base_translation_mod_awareness.json'))
|
||||||
$reuseBase = -not ($artifacts | Where-Object { -not (Test-Path -LiteralPath $_ -PathType Leaf) })
|
$reuseBase = -not ($artifacts | Where-Object { -not (Test-Path -LiteralPath $_ -PathType Leaf) })
|
||||||
@@ -316,11 +312,11 @@ try {
|
|||||||
|
|
||||||
Invoke-Checked $translator @(
|
Invoke-Checked $translator @(
|
||||||
'emit-base-manifest', '--project', $project, '--out', $baseManifestDir,
|
'emit-base-manifest', '--project', $project, '--out', $baseManifestDir,
|
||||||
'--functions-dir', $functions, '--translation-output-metadata', $baseMetadata, '--region', $pins.Region
|
'--functions-dir', $functions, '--translation-output-metadata', $baseMetadata, '--region', 'P'
|
||||||
) 'Creating the local base translation manifest' -StepId 'emit-base-manifest'
|
) 'Creating the local base translation manifest' -StepId 'emit-base-manifest'
|
||||||
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($TranslationFingerprint)) {
|
if (-not [string]::IsNullOrWhiteSpace($TranslationFingerprint)) {
|
||||||
[ordered]@{ SchemaVersion = 1; TranslationFingerprint = $TranslationFingerprint; DolSha256 = $pins.DolSha256 } |
|
[ordered]@{ SchemaVersion = 1; TranslationFingerprint = $TranslationFingerprint } |
|
||||||
ConvertTo-Json | Set-Content -LiteralPath $translationProvenance -Encoding UTF8
|
ConvertTo-Json | Set-Content -LiteralPath $translationProvenance -Encoding UTF8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,14 +329,14 @@ try {
|
|||||||
'translate-mod', '--project', $project, '--profile', 'retro-rewind',
|
'translate-mod', '--project', $project, '--profile', 'retro-rewind',
|
||||||
'--base-manifest', $baseManifest, '--base-translation-output-metadata', $baseMetadata,
|
'--base-manifest', $baseManifest, '--base-translation-output-metadata', $baseMetadata,
|
||||||
'--code-pul', $codePul, '--mod-root', $retroRoot, '--mod-name', 'Retro Rewind',
|
'--code-pul', $codePul, '--mod-root', $retroRoot, '--mod-name', 'Retro Rewind',
|
||||||
'--region', $pins.Region, '--out', $retroOut, '--prefer-cached-inputs', '--emit-cpp',
|
'--region', 'P', '--out', $retroOut, '--prefer-cached-inputs', '--emit-cpp',
|
||||||
'--threads', $translatorThreads
|
'--threads', $translatorThreads
|
||||||
)
|
)
|
||||||
if ($SkipRetroWfcPayload) {
|
if ($SkipRetroWfcPayload) {
|
||||||
$translateModArguments += '--skip-retro-wfc'
|
$translateModArguments += '--skip-retro-wfc'
|
||||||
} elseif (-not [string]::IsNullOrWhiteSpace($RetroWfcOfflineDirectory)) {
|
} elseif (-not [string]::IsNullOrWhiteSpace($RetroWfcOfflineDirectory)) {
|
||||||
$offlineRoot = [IO.Path]::GetFullPath($RetroWfcOfflineDirectory)
|
$offlineRoot = [IO.Path]::GetFullPath($RetroWfcOfflineDirectory)
|
||||||
$offlinePayload = Join-Path $offlineRoot $retroWfcPayloadFile
|
$offlinePayload = Join-Path $offlineRoot 'binary\payload.RMCPD00.bin'
|
||||||
Assert-File $offlinePayload 'Offline Retro-WFC shared payload'
|
Assert-File $offlinePayload 'Offline Retro-WFC shared payload'
|
||||||
$translateModArguments += @('--retro-wfc-payload', $offlinePayload)
|
$translateModArguments += @('--retro-wfc-payload', $offlinePayload)
|
||||||
} else {
|
} else {
|
||||||
@@ -427,7 +423,7 @@ try {
|
|||||||
$exe = Join-Path $build "$Target.exe"
|
$exe = Join-Path $build "$Target.exe"
|
||||||
Assert-File $exe 'Locally compiled game executable'
|
Assert-File $exe 'Locally compiled game executable'
|
||||||
Copy-Item -LiteralPath $exe -Destination (Join-Path $Destination "$Target.exe")
|
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','libzlib1.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','SDL3.dll','sqlite3.dll','webgpu_dawn.dll','z.dll','noshaders.zip','dsp_coef.bin','initial_pipeline_cache.db')) {
|
||||||
$file = Join-Path $build $name
|
$file = Join-Path $build $name
|
||||||
if (Test-Path -LiteralPath $file -PathType Leaf) { Copy-Item -LiteralPath $file -Destination $Destination }
|
if (Test-Path -LiteralPath $file -PathType Leaf) { Copy-Item -LiteralPath $file -Destination $Destination }
|
||||||
}
|
}
|
||||||
@@ -451,8 +447,8 @@ try {
|
|||||||
RelSha256 = $relSha
|
RelSha256 = $relSha
|
||||||
CodePulSha256 = if ($isRetro) { Get-MkwFileSha256 (Join-Path $retroRoot 'Binaries\Code.pul') } else { $null }
|
CodePulSha256 = if ($isRetro) { Get-MkwFileSha256 (Join-Path $retroRoot 'Binaries\Code.pul') } else { $null }
|
||||||
RetroWfcPayloadMode = if (-not $isRetro) { $null } elseif ($SkipRetroWfcPayload) { 'skipped' } else { $RetroWfcPayloadOrigin }
|
RetroWfcPayloadMode = if (-not $isRetro) { $null } elseif ($SkipRetroWfcPayload) { 'skipped' } else { $RetroWfcPayloadOrigin }
|
||||||
RetroWfcPayloadSha256 = if ($isRetro -and -not $SkipRetroWfcPayload) { Get-MkwFileSha256 (Join-Path $RetroWfcOfflineDirectory $retroWfcPayloadFile) } else { $null }
|
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 $retroWfcPayloadFile)).Length } else { $null }
|
RetroWfcPayloadLength = if ($isRetro -and -not $SkipRetroWfcPayload) { (Get-Item -LiteralPath (Join-Path $RetroWfcOfflineDirectory 'binary\payload.RMCPD00.bin')).Length } else { $null }
|
||||||
Compiler = "llvm-mingw clang-22 sha256:$compilerSha"
|
Compiler = "llvm-mingw clang-22 sha256:$compilerSha"
|
||||||
}
|
}
|
||||||
$provenance | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $Destination 'local-build.json') -Encoding UTF8
|
$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) {
|
function Get-MkwProjectPins([string]$ProjectFile) {
|
||||||
<#
|
<#
|
||||||
The Mario Kart Wii facts pinned by a projects/*/recomp.yml (game identity, clean input
|
The Mario Kart Wii facts pinned by projects/mkwii/recomp.yml (game identity, clean input
|
||||||
digests, translation entry point, Retro-WFC endpoint), read from one place instead of being
|
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#
|
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
|
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'
|
Assert-File $ProjectFile 'Translation project file'
|
||||||
$pins = [ordered]@{
|
$pins = [ordered]@{
|
||||||
GameId = ''; Region = ''; DolSha256 = ''; RelSha256 = ''; EntryPoint = ''; RetroWfcPayloadUri = ''
|
GameId = ''; DolSha256 = ''; RelSha256 = ''; EntryPoint = ''; RetroWfcPayloadUri = ''
|
||||||
}
|
}
|
||||||
$section = ''
|
$section = ''
|
||||||
$inputKey = ''
|
$inputKey = ''
|
||||||
@@ -112,8 +112,6 @@ 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 '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*$') {
|
if ($section -eq 'project' -and $line -match '^\s*game_id:\s*(\S+)\s*$') {
|
||||||
$pins.GameId = $Matches[1]
|
$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*$') {
|
} 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() }
|
if ($inputKey -eq 'dol') { $pins.DolSha256 = $Matches[1].ToLowerInvariant() }
|
||||||
elseif ($inputKey -eq 'rel') { $pins.RelSha256 = $Matches[1].ToLowerInvariant() }
|
elseif ($inputKey -eq 'rel') { $pins.RelSha256 = $Matches[1].ToLowerInvariant() }
|
||||||
@@ -132,30 +130,6 @@ function Get-MkwProjectPins([string]$ProjectFile) {
|
|||||||
return $pins
|
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,
|
function Invoke-Checked([string]$FilePath, [string[]]$Arguments, [string]$Description,
|
||||||
[string]$LogPrefix = 'MKWCBUILD', [string]$StepId = '', [bool]$WaitForProcessTree = $true) {
|
[string]$LogPrefix = 'MKWCBUILD', [string]$StepId = '', [bool]$WaitForProcessTree = $true) {
|
||||||
<#
|
<#
|
||||||
@@ -179,15 +153,8 @@ function Invoke-Checked([string]$FilePath, [string[]]$Arguments, [string]$Descri
|
|||||||
-NoNewWindow -Wait -PassThru
|
-NoNewWindow -Wait -PassThru
|
||||||
$exitCode = $process.ExitCode
|
$exitCode = $process.ExitCode
|
||||||
} else {
|
} else {
|
||||||
# Tools report progress on stderr (CMake message()); only the exit code decides failure.
|
& $FilePath @Arguments
|
||||||
$previousPreference = $ErrorActionPreference
|
$exitCode = $LASTEXITCODE
|
||||||
$ErrorActionPreference = 'Continue'
|
|
||||||
try {
|
|
||||||
& $FilePath @Arguments
|
|
||||||
$exitCode = $LASTEXITCODE
|
|
||||||
} finally {
|
|
||||||
$ErrorActionPreference = $previousPreference
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$global:LASTEXITCODE = $exitCode
|
$global:LASTEXITCODE = $exitCode
|
||||||
if ($exitCode -ne 0) { throw "$Description failed with exit code $exitCode." }
|
if ($exitCode -ne 0) { throw "$Description failed with exit code $exitCode." }
|
||||||
@@ -241,14 +208,13 @@ function Get-MkwThirdPartySourceFingerprint([string]$ThirdPartyDirectory) {
|
|||||||
SHA-256 over runtime/third_party, the vendored sources behind the prebuilt package. The
|
SHA-256 over runtime/third_party, the vendored sources behind the prebuilt package. The
|
||||||
precompiled Crypto++ archive is linked while first-party TUs compile against the same headers,
|
precompiled Crypto++ archive is linked while first-party TUs compile against the same headers,
|
||||||
so a workspace whose vendored tree moved on must not consume archives harvested from an older
|
so a workspace whose vendored tree moved on must not consume archives harvested from an older
|
||||||
one (same reasoning as the aurora fingerprint below), skipping dot-paths by name the same way.
|
one (same reasoning as the aurora fingerprint below). Unlike that scan this hashes hidden files
|
||||||
Returns '' when absent.
|
too, since Build-Installer stages this tree with Copy-Item -Force. Returns '' when absent.
|
||||||
#>
|
#>
|
||||||
if ([string]::IsNullOrWhiteSpace($ThirdPartyDirectory)) { return '' }
|
if ([string]::IsNullOrWhiteSpace($ThirdPartyDirectory)) { return '' }
|
||||||
if (-not (Test-Path -LiteralPath $ThirdPartyDirectory -PathType Container)) { return '' }
|
if (-not (Test-Path -LiteralPath $ThirdPartyDirectory -PathType Container)) { return '' }
|
||||||
$root = [IO.Path]::GetFullPath($ThirdPartyDirectory).TrimEnd('\')
|
$root = [IO.Path]::GetFullPath($ThirdPartyDirectory).TrimEnd('\')
|
||||||
$files = Get-ChildItem -LiteralPath $root -Recurse -File -Force |
|
$files = Get-ChildItem -LiteralPath $root -Recurse -File |
|
||||||
Where-Object { -not ($_.FullName.Substring($root.Length + 1) -split '\\' | Where-Object { $_.StartsWith('.') }) } |
|
|
||||||
Sort-Object { $_.FullName.Substring($root.Length + 1).Replace('\', '/') }
|
Sort-Object { $_.FullName.Substring($root.Length + 1).Replace('\', '/') }
|
||||||
$sha = [Security.Cryptography.SHA256]::Create()
|
$sha = [Security.Cryptography.SHA256]::Create()
|
||||||
try {
|
try {
|
||||||
@@ -279,13 +245,13 @@ function Get-MkwAuroraSourceFingerprint([string]$AuroraDirectory) {
|
|||||||
(Join-Path $root 'extern') + '\',
|
(Join-Path $root 'extern') + '\',
|
||||||
(Join-Path $root 'build') + '\'
|
(Join-Path $root 'build') + '\'
|
||||||
)
|
)
|
||||||
# Dot-paths (the submodule's .git pointer) are skipped by name, not by the hidden attribute:
|
# Hidden files are skipped deliberately: Build-Installer.ps1 stages this tree
|
||||||
# the payload zip drops that attribute, so the installed side would otherwise hash them.
|
# with Copy-Item -Recurse (no -Force), so they never reach the payload and
|
||||||
$files = Get-ChildItem -LiteralPath $root -Recurse -File -Force |
|
# hashing them would make the two sides disagree by construction.
|
||||||
|
$files = Get-ChildItem -LiteralPath $root -Recurse -File |
|
||||||
Where-Object {
|
Where-Object {
|
||||||
$full = $_.FullName
|
$full = $_.FullName
|
||||||
-not ($excludedPrefixes | Where-Object { $full.StartsWith($_, [StringComparison]::OrdinalIgnoreCase) }) -and
|
-not ($excludedPrefixes | Where-Object { $full.StartsWith($_, [StringComparison]::OrdinalIgnoreCase) })
|
||||||
-not ($full.Substring($root.Length + 1) -split '\\' | Where-Object { $_.StartsWith('.') })
|
|
||||||
} |
|
} |
|
||||||
Sort-Object { $_.FullName.Substring($root.Length + 1).Replace('\', '/') }
|
Sort-Object { $_.FullName.Substring($root.Length + 1).Replace('\', '/') }
|
||||||
$sha = [Security.Cryptography.SHA256]::Create()
|
$sha = [Security.Cryptography.SHA256]::Create()
|
||||||
|
|||||||
@@ -21,21 +21,16 @@ $auroraExtern = Join-Path $repoRoot 'aurora-main\extern\CMakeLists.txt'
|
|||||||
$auroraDawn = Join-Path $repoRoot 'aurora-main\cmake\AuroraDawnProvider.cmake'
|
$auroraDawn = Join-Path $repoRoot 'aurora-main\cmake\AuroraDawnProvider.cmake'
|
||||||
$auroraLibUsb = Join-Path $repoRoot 'aurora-main\cmake\AuroraLibUSB.cmake'
|
$auroraLibUsb = Join-Path $repoRoot 'aurora-main\cmake\AuroraLibUSB.cmake'
|
||||||
$auroraSdl = Join-Path $repoRoot 'aurora-main\cmake\AuroraSDL3Provider.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
|
# Name = directory under the destination; FetchContent maps it back through
|
||||||
# FETCHCONTENT_SOURCE_DIR_<UPPERCASE NAME> (NativeBuildFlags.ps1), so the names are the declared
|
# FETCHCONTENT_SOURCE_DIR_<UPPERCASE NAME> (NativeBuildFlags.ps1), so the names are the declared
|
||||||
# FetchContent names, not the upstream project names.
|
# FetchContent names, not the upstream project names.
|
||||||
$packages = @(
|
$packages = @(
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'SDL'; File = 'SDL3-3.4.10.tar.gz'
|
Name = 'SDL'; File = 'SDL3-3.4.4.tar.gz'
|
||||||
Uris = @('https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-3.4.10.tar.gz')
|
Uris = @('https://github.com/libsdl-org/SDL/releases/download/release-3.4.4/SDL3-3.4.4.tar.gz')
|
||||||
Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_SDL3_REF "refs/tags/release-3.4.10"' },
|
Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_SDL3_VERSION "3.4.4"' },
|
||||||
@{ File = $auroraSdl; Text = 'URL "https://github.com/libsdl-org/SDL/archive/${AURORA_SDL3_REF}.tar.gz"' })
|
@{ File = $auroraSdl; Text = 'releases/download/release-${AURORA_SDL3_VERSION}/SDL3-${AURORA_SDL3_VERSION}.tar.gz' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'abseil-cpp'; File = 'abseil-cpp-20240722.0.tar.gz'
|
Name = 'abseil-cpp'; File = 'abseil-cpp-20240722.0.tar.gz'
|
||||||
@@ -43,15 +38,15 @@ $packages = @(
|
|||||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz' })
|
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'dawn_prebuilt'; File = 'dawn-v20260807.225922-windows-amd64.tar.gz'
|
Name = 'dawn_prebuilt'; File = 'dawn-v20260603.191052-windows-amd64.tar.gz'
|
||||||
Uris = @('https://github.com/encounter/dawn/releases/download/v20260807.225922/dawn-windows-amd64.tar.gz')
|
Uris = @('https://github.com/theofficialgman/dawn-build/releases/download/v20260603.191052/dawn-windows-amd64.tar.gz')
|
||||||
Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_DAWN_VERSION "v20260807.225922"' },
|
Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_DAWN_VERSION "v20260603.191052"' },
|
||||||
@{ File = $auroraDawn; Text = 'SHA256=42a7a295c87b2e8a36312e2f84a5823aac63325e8e1d271bc7ced6f83bfb075f' })
|
@{ File = $auroraDawn; Text = 'SHA256=13be9cff8b9b179c42dcd16aeabb6effcc8f0dfdcc14463eda2a5caeda225142' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'fmt'; File = 'fmt-12.1.0.tar.gz'
|
Name = 'fmt'; File = 'fmt-11.1.4.tar.gz'
|
||||||
Uris = @('https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.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/12.1.0.tar.gz' })
|
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'freetype'; File = 'freetype-2.14.3.tar.gz'
|
Name = 'freetype'; File = 'freetype-2.14.3.tar.gz'
|
||||||
@@ -63,12 +58,12 @@ $packages = @(
|
|||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'imgui'; File = 'imgui-1.91.9b-docking.tar.gz'
|
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')
|
Uris = @('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' })
|
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'libusb'; File = 'libusb-1.0.30.tar.bz2'
|
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')
|
Uris = @('https://github.com/libusb/libusb/releases/download/v1.0.30/libusb-1.0.30.tar.bz2')
|
||||||
Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_LIBUSB_VERSION "1.0.30"' },
|
Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_LIBUSB_VERSION "1.0.30"' },
|
||||||
@{ File = $auroraLibUsb; Text = 'releases/download/v${AURORA_LIBUSB_VERSION}/libusb-${AURORA_LIBUSB_VERSION}.tar.bz2' })
|
@{ File = $auroraLibUsb; Text = 'releases/download/v${AURORA_LIBUSB_VERSION}/libusb-${AURORA_LIBUSB_VERSION}.tar.bz2' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
@@ -82,9 +77,9 @@ $packages = @(
|
|||||||
Pins = @(@{ File = $auroraExtern; Text = 'https://sqlite.org/2026/sqlite-amalgamation-3510300.zip' })
|
Pins = @(@{ File = $auroraExtern; Text = 'https://sqlite.org/2026/sqlite-amalgamation-3510300.zip' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'tracy'; File = 'tracy-0.14.1.zip'
|
Name = 'tracy'; File = 'tracy-a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz'
|
||||||
Uris = @('https://github.com/wolfpld/tracy/archive/refs/tags/v0.14.1.zip')
|
Uris = @('https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz')
|
||||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/wolfpld/tracy/archive/refs/tags/v0.14.1.zip' })
|
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'xxhash'; File = 'xxHash-0.8.4.tar.gz'
|
Name = 'xxhash'; File = 'xxHash-0.8.4.tar.gz'
|
||||||
@@ -92,9 +87,9 @@ $packages = @(
|
|||||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz' })
|
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'zlib'; File = 'zlib-ng-2.3.3.tar.gz'
|
Name = 'zlib'; File = 'zlib-1.3.2.tar.gz'
|
||||||
Uris = @('https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.3.3.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/zlib-ng/zlib-ng/archive/refs/tags/2.3.3.tar.gz' })
|
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz' })
|
||||||
},
|
},
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = 'zstd'; File = 'zstd-1.5.7.tar.gz'
|
Name = 'zstd'; File = 'zstd-1.5.7.tar.gz'
|
||||||
@@ -173,12 +168,8 @@ function Expand-Package([string]$Archive, [string]$Target) {
|
|||||||
foreach ($package in $packages) {
|
foreach ($package in $packages) {
|
||||||
Assert-Pinned $package
|
Assert-Pinned $package
|
||||||
$target = Join-Path $Destination $package.Name
|
$target = Join-Path $Destination $package.Name
|
||||||
# Records which archive a tree came from, so a pin change replaces a stale tree.
|
if (Test-Path -LiteralPath $target -PathType Container) { continue }
|
||||||
$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
|
Expand-Package (Get-Archive $package) $target
|
||||||
[IO.File]::WriteAllText($stamp, $package.File)
|
|
||||||
Write-Host "Prepared $($package.Name)"
|
Write-Host "Prepared $($package.Name)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ fingerprint_tree() {
|
|||||||
local root=$1; shift
|
local root=$1; shift
|
||||||
root=$(normalize "$root")
|
root=$(normalize "$root")
|
||||||
[[ -d "$root" ]] || return 0
|
[[ -d "$root" ]] || return 0
|
||||||
local find_args=("$root" -name .git -prune -o)
|
local find_args=("$root")
|
||||||
local ex
|
local ex
|
||||||
for ex in "$@"; do find_args+=(-path "$root/$ex" -prune -o); done
|
for ex in "$@"; do find_args+=(-path "$root/$ex" -prune -o); done
|
||||||
find_args+=(-type f -print)
|
find_args+=(-type f -print)
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
# Fails the release build when a fact duplicated across the repo stops agreeing with the copy
|
# Fails the release build when a fact duplicated across the repo stops agreeing with the copy
|
||||||
# that owns it (each projects/*/recomp.yml). Scripts read pinned facts through Get-MkwProjectPins
|
# that owns it (recomp.yml). Scripts read pinned facts through Get-MkwProjectPins, but three
|
||||||
# or build-cache.sh's mkw_project_pin, but some consumers can't read YAML (the C++ runtime header,
|
# consumers can't read YAML (the C++ runtime header, the C# constants, shell scripts, and hand-written lists on
|
||||||
# the C# Retro-WFC table, and hand-written lists on both sides of the C#/PowerShell boundary), so
|
# both sides of the C#/PowerShell boundary), so those are checked here instead.
|
||||||
# those are checked here instead.
|
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param([string]$RepositoryRoot)
|
param([string]$RepositoryRoot)
|
||||||
|
|
||||||
@@ -47,36 +46,32 @@ function Compare-Set([string[]]$Expected, [string[]]$Actual, [string]$ExpectedNa
|
|||||||
if ($extra.Count -gt 0) { Add-Failure "$ActualName has entries $ExpectedName does not: $($extra -join ', ')." }
|
if ($extra.Count -gt 0) { Add-Failure "$ActualName has entries $ExpectedName does not: $($extra -join ', ')." }
|
||||||
}
|
}
|
||||||
|
|
||||||
# Every supported release is one projects/<name>/recomp.yml, the same set Build-Installer.ps1 ships.
|
$pins = Get-MkwProjectPins (Join-Path $repoRoot 'projects\mkwii\recomp.yml')
|
||||||
$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 endpoints: each recomp.yml owns its release's; the host derives the same URL
|
# --- The Retro-WFC endpoint: recomp.yml owns it; the installer host pins the same string so a
|
||||||
# --- from its game table so a redirected or rewritten endpoint cannot be fetched from.
|
# --- 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.
|
||||||
$retroWfcPayload = Read-SourceFile (Join-Path $common 'RetroWfcPayload.cs') 'RetroWfcPayload.cs'
|
$retroWfcPayload = Read-SourceFile (Join-Path $common 'RetroWfcPayload.cs') 'RetroWfcPayload.cs'
|
||||||
$payloadGames = @{}
|
$hostUri = Get-CapturedValue $retroWfcPayload 'CurrentRetroWfcPayloadUri\s*=\s*"([^"]+)"' `
|
||||||
foreach ($entry in [regex]::Matches((Get-CapturedValue $retroWfcPayload `
|
'The host Retro-WFC endpoint constant'
|
||||||
'(?s)PayloadGames\s*=\s*new\([^)]*\)\s*\{(.*?)\};' 'The host Retro-WFC game table'),
|
if ($hostUri -cne $pins.RetroWfcPayloadUri) {
|
||||||
'\["([^"]+)"\]\s*=\s*"([^"]+)"')) {
|
Add-Failure "InputValidation.CurrentRetroWfcPayloadUri is '$hostUri' but recomp.yml pins '$($pins.RetroWfcPayloadUri)'."
|
||||||
$payloadGames[$entry.Groups[1].Value] = $entry.Groups[2].Value
|
|
||||||
}
|
}
|
||||||
$uriTemplate = Get-CapturedValue $retroWfcPayload 'PayloadUri\(string gameId\)\s*=>\s*\$"([^"]+)"' `
|
$macosSetup = Read-SourceFile (Join-Path $launcher 'macos\setup.command') 'macOS setup.command'
|
||||||
'The host Retro-WFC endpoint template'
|
$macosUri = Get-CapturedValue $macosSetup "'([^']*/api/wfc/payload\?g=RMCPD00)'" `
|
||||||
Compare-Set ([string[]]@($releases.GameId)) ([string[]]@($payloadGames.Keys)) `
|
'The macOS Retro-WFC endpoint'
|
||||||
'projects/*/recomp.yml' 'RetroWfcPayload.PayloadGames'
|
if ($macosUri -cne $pins.RetroWfcPayloadUri) {
|
||||||
foreach ($release in $releases) {
|
Add-Failure "macOS setup.command downloads '$macosUri' but recomp.yml pins '$($pins.RetroWfcPayloadUri)'."
|
||||||
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)'."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
foreach ($key in @('GameId', 'DolSha256')) {
|
|
||||||
foreach ($duplicate in @($releases | Group-Object $key | Where-Object Count -gt 1)) {
|
# --- The game identity: the manifest carries it, but the host also compiles a fallback for a
|
||||||
Add-Failure "Several projects pin the same $($key) $($duplicate.Name)."
|
# --- 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)'."
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- The translation entry point: the translator is told it by LocalBuild.ps1 (which reads
|
# --- The translation entry point: the translator is told it by LocalBuild.ps1 (which reads
|
||||||
@@ -84,10 +79,8 @@ foreach ($key in @('GameId', 'DolSha256')) {
|
|||||||
$systemBridge = Read-SourceFile (Join-Path $repoRoot 'runtime\include\system_bridge.h') 'system_bridge.h'
|
$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]+)' `
|
$runtimeEntry = (Get-CapturedValue $systemBridge 'kDefaultEntryAddress\s*=\s*(0[xX][0-9a-fA-F]+)' `
|
||||||
'The runtime default entry address').ToLowerInvariant()
|
'The runtime default entry address').ToLowerInvariant()
|
||||||
foreach ($release in $releases) {
|
if ($runtimeEntry -ne $pins.EntryPoint) {
|
||||||
if ($runtimeEntry -ne $release.EntryPoint) {
|
Add-Failure "system_bridge.h enters at $runtimeEntry but recomp.yml translates from $($pins.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.
|
# --- The pinned dependency set: Build-Installer.ps1 stages it, the installed host requires it.
|
||||||
@@ -144,6 +137,6 @@ Compare-Set $knownSteps $emittedSteps 'BuildStepIds' 'the steps LocalBuild.ps1 e
|
|||||||
if ($failures.Count -gt 0) {
|
if ($failures.Count -gt 0) {
|
||||||
throw "Pinned facts disagree between their copies:`n $($failures -join "`n ")"
|
throw "Pinned facts disagree between their copies:`n $($failures -join "`n ")"
|
||||||
}
|
}
|
||||||
Write-Host ("Pinned-fact audit passed: games {0}, entry {1}; Retro-WFC endpoint, dependency, runtime-asset, " -f
|
Write-Host ("Pinned-fact audit passed: game {0}, entry {1}, endpoint {2}; dependency, runtime-asset, " -f
|
||||||
($releases.GameId -join ', '), $runtimeEntry) -NoNewline
|
$pins.GameId, $pins.EntryPoint, $pins.RetroWfcPayloadUri) -NoNewline
|
||||||
Write-Host 'build-step, and build-script parameter contracts all agree.'
|
Write-Host 'build-step, and build-script parameter contracts all agree.'
|
||||||
|
|||||||
@@ -36,17 +36,8 @@ Write-Host "Synthetic recompilation workspace: $stage"
|
|||||||
|
|
||||||
# Copy current sources, including uncommitted edits, but no ignored build output.
|
# Copy current sources, including uncommitted edits, but no ignored build output.
|
||||||
# An isolated workspace preserves the developer's real generated/ directory.
|
# An isolated workspace preserves the developer's real generated/ directory.
|
||||||
$auroraRoot = Join-Path $repoRoot 'aurora-main'
|
$sourceFiles = & git -C $repoRoot -c core.quotepath=false ls-files --cached --others --exclude-standard -- runtime aurora-main
|
||||||
if (-not (Test-Path -LiteralPath (Join-Path $auroraRoot '.git'))) {
|
if ($LASTEXITCODE -ne 0) { throw 'Could not enumerate runtime and Aurora sources.' }
|
||||||
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) {
|
foreach ($relative in $sourceFiles | Sort-Object -Unique) {
|
||||||
$destination = Join-Path $stage $relative
|
$destination = Join-Path $stage $relative
|
||||||
[IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($destination)) | Out-Null
|
[IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($destination)) | Out-Null
|
||||||
@@ -54,10 +45,15 @@ foreach ($relative in $sourceFiles | Sort-Object -Unique) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# One synthetic text section: li r3,40; addi r3,r3,2; nop; blr.
|
# One synthetic text section: li r3,40; addi r3,r3,2; nop; blr.
|
||||||
# Guest functions the runtime calls directly resolve through the registry at run time, so the
|
# Native HLE wrappers also call these eight guest symbols directly. Give each
|
||||||
# product links without any game code.
|
# 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]$entry = 0x80001000L
|
||||||
$textSize = 0x10
|
[uint32[]]$guestCallbacks = @(
|
||||||
|
0x8012B830L, 0x801A0620L, 0x801A1ED8L, 0x801A961CL,
|
||||||
|
0x801AADE0L, 0x801D8D30L, 0x801D9E94L, 0x8055531CL
|
||||||
|
)
|
||||||
|
$textSize = [int]($guestCallbacks[-1] - $entry + 4)
|
||||||
$dataOffset = 0x100 + $textSize
|
$dataOffset = 0x100 + $textSize
|
||||||
$dol = [byte[]]::new($dataOffset + 4)
|
$dol = [byte[]]::new($dataOffset + 4)
|
||||||
function Write-BigEndian32([int]$Offset, [uint32]$Value) {
|
function Write-BigEndian32([int]$Offset, [uint32]$Value) {
|
||||||
@@ -68,7 +64,7 @@ function Write-BigEndian32([int]$Offset, [uint32]$Value) {
|
|||||||
}
|
}
|
||||||
Write-BigEndian32 0x00 0x100 # text[0] file offset
|
Write-BigEndian32 0x00 0x100 # text[0] file offset
|
||||||
Write-BigEndian32 0x48 $entry # text[0] guest address
|
Write-BigEndian32 0x48 $entry # text[0] guest address
|
||||||
Write-BigEndian32 0x90 $textSize # text[0] length
|
Write-BigEndian32 0x90 $textSize # text[0] length (unreachable gaps are zero)
|
||||||
Write-BigEndian32 0x1C $dataOffset # data[0] file offset
|
Write-BigEndian32 0x1C $dataOffset # data[0] file offset
|
||||||
Write-BigEndian32 0x64 0x80600000L # data[0] guest address
|
Write-BigEndian32 0x64 0x80600000L # data[0] guest address
|
||||||
Write-BigEndian32 0xAC 4 # data[0] length
|
Write-BigEndian32 0xAC 4 # data[0] length
|
||||||
@@ -79,10 +75,13 @@ Write-BigEndian32 0x100 0x38600028 # li r3,40
|
|||||||
Write-BigEndian32 0x104 0x38630002 # addi r3,r3,2
|
Write-BigEndian32 0x104 0x38630002 # addi r3,r3,2
|
||||||
Write-BigEndian32 0x108 0x60000000 # nop
|
Write-BigEndian32 0x108 0x60000000 # nop
|
||||||
Write-BigEndian32 0x10C 0x4E800020 # blr
|
Write-BigEndian32 0x10C 0x4E800020 # blr
|
||||||
|
foreach ($address in $guestCallbacks) {
|
||||||
|
Write-BigEndian32 ([int](0x100 + $address - $entry)) 0x4E800020
|
||||||
|
}
|
||||||
Write-BigEndian32 $dataOffset 0x12345678
|
Write-BigEndian32 $dataOffset 0x12345678
|
||||||
[IO.File]::WriteAllBytes((Join-Path $stage 'synthetic.dol'), $dol)
|
[IO.File]::WriteAllBytes((Join-Path $stage 'synthetic.dol'), $dol)
|
||||||
$entryPoints = '0x{0:X8}' -f $entry
|
$entryPoints = (@($entry) + $guestCallbacks | ForEach-Object { '0x{0:X8}' -f $_ }) -join ', '
|
||||||
$functionMap = '{0:X8} func_{0:X8}' -f $entry
|
$functionMap = (@($entry) + $guestCallbacks | ForEach-Object { '{0:X8} func_{0:X8}' -f $_ }) -join "`n"
|
||||||
[IO.File]::WriteAllText((Join-Path $stage 'synthetic-functions.txt'), $functionMap)
|
[IO.File]::WriteAllText((Join-Path $stage 'synthetic-functions.txt'), $functionMap)
|
||||||
$manifest = Join-Path $stage 'recomp.yml'
|
$manifest = Join-Path $stage 'recomp.yml'
|
||||||
[IO.File]::WriteAllText($manifest, @"
|
[IO.File]::WriteAllText($manifest, @"
|
||||||
@@ -120,7 +119,7 @@ Invoke-Checked $dotnet @($translator, 'translate-recursive', '0x80001000', '--pr
|
|||||||
'Translating the synthetic DOL'
|
'Translating the synthetic DOL'
|
||||||
# Function-map seeds can be skipped by discovery; do not accept a partial fixture.
|
# Function-map seeds can be skipped by discovery; do not accept a partial fixture.
|
||||||
$translated = Get-Content -LiteralPath $metadata -Raw | ConvertFrom-Json
|
$translated = Get-Content -LiteralPath $metadata -Raw | ConvertFrom-Json
|
||||||
foreach ($address in @($entry)) {
|
foreach ($address in @($entry) + $guestCallbacks) {
|
||||||
if ($address -notin $translated.functions.entryPoint) {
|
if ($address -notin $translated.functions.entryPoint) {
|
||||||
throw ('Synthetic function 0x{0:X8} was not translated.' -f $address)
|
throw ('Synthetic function 0x{0:X8} was not translated.' -f $address)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,39 +11,22 @@ namespace WiiCompiled.Setup.Common;
|
|||||||
public sealed record RetroWfcPayloadSnapshot(string Directory, string Sha256, long ByteLength);
|
public sealed record RetroWfcPayloadSnapshot(string Directory, string Sha256, long ByteLength);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Downloads and verifies the Retro-WFC payload (a small, RSA-signed blob served from one fixed
|
/// Downloads and verifies the Retro-WFC payload (a small, RSA-signed blob served from a single
|
||||||
/// endpoint per game release). Shared by both installers and the translator.
|
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class RetroWfcPayload
|
public static class RetroWfcPayload
|
||||||
{
|
{
|
||||||
private const long MaximumRetroWfcPayloadBytes = 16L * 1024 * 1024;
|
private const long MaximumRetroWfcPayloadBytes = 16L * 1024 * 1024;
|
||||||
// The payload is tens of kilobytes from a fixed regional endpoint; allow 30 seconds.
|
// The payload is tens of kilobytes from a single fixed endpoint 30s is good.
|
||||||
private static readonly TimeSpan RetroWfcDownloadTimeout = TimeSpan.FromSeconds(30);
|
private static readonly TimeSpan RetroWfcDownloadTimeout = TimeSpan.FromSeconds(30);
|
||||||
private static readonly TimeSpan RetroWfcRetryDelay = TimeSpan.FromSeconds(1);
|
private static readonly TimeSpan RetroWfcRetryDelay = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
/// <summary>
|
public const string CurrentRetroWfcPayloadUri = "https://rwfc.net/api/wfc/payload?g=RMCPD00";
|
||||||
/// Base game id to Retro-WFC payload game. Test-PinnedFacts.ps1 checks this table against the
|
private static readonly string RetroWfcOfflinePayloadFile =
|
||||||
/// retro_wfc_payload every projects/*/recomp.yml pins.
|
Path.Combine("binary", "payload.RMCPD00.bin");
|
||||||
/// </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
|
/// <summary>Retro-WFC production payload signing key (PROD PayloadPublicKey). Verifies
|
||||||
/// the payload past the 0x110 header; on-console stage1 pins the same key, so
|
/// the payload past the 0x110 header; on-console stage1 pins the same key, so
|
||||||
@@ -62,48 +45,47 @@ public static class RetroWfcPayload
|
|||||||
private const int RetroWfcPayloadSignatureOffset = 0x10;
|
private const int RetroWfcPayloadSignatureOffset = 0x10;
|
||||||
private const int RetroWfcPayloadMinimumBytes = 0x130;
|
private const int RetroWfcPayloadMinimumBytes = 0x130;
|
||||||
|
|
||||||
public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory, string gameId,
|
public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory,
|
||||||
RSAParameters? signingKey = null)
|
RSAParameters? signingKey = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(stagedDirectory))
|
if (string.IsNullOrWhiteSpace(stagedDirectory))
|
||||||
throw new InvalidDataException("The staged Retro-WFC payload directory is missing.");
|
throw new InvalidDataException("The staged Retro-WFC payload directory is missing.");
|
||||||
|
|
||||||
var root = Path.GetFullPath(stagedDirectory);
|
var root = Path.GetFullPath(stagedDirectory);
|
||||||
var relativePath = PayloadRelativePath(gameId);
|
var payload = Path.Combine(root, RetroWfcOfflinePayloadFile);
|
||||||
var payload = Path.Combine(root, relativePath);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ((File.GetAttributes(payload) & FileAttributes.Directory) != 0)
|
if ((File.GetAttributes(payload) & FileAttributes.Directory) != 0)
|
||||||
throw new InvalidDataException(
|
throw new InvalidDataException(
|
||||||
$"The staged Retro-WFC payload directory does not contain {relativePath}.");
|
"The staged Retro-WFC payload directory does not contain binary\\payload.RMCPD00.bin.");
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException)
|
catch (FileNotFoundException)
|
||||||
{
|
{
|
||||||
throw new InvalidDataException(
|
throw new InvalidDataException(
|
||||||
$"The staged Retro-WFC payload directory does not contain {relativePath}.");
|
"The staged Retro-WFC payload directory does not contain binary\\payload.RMCPD00.bin.");
|
||||||
}
|
}
|
||||||
catch (DirectoryNotFoundException)
|
catch (DirectoryNotFoundException)
|
||||||
{
|
{
|
||||||
throw new InvalidDataException(
|
throw new InvalidDataException(
|
||||||
$"The staged Retro-WFC payload directory does not contain {relativePath}.");
|
"The staged Retro-WFC payload directory does not contain binary\\payload.RMCPD00.bin.");
|
||||||
}
|
}
|
||||||
ValidateRetroWfcPayloadFile(payload, PayloadGame(gameId), signingKey);
|
ValidateRetroWfcPayloadFile(payload, signingKey);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ResolveRetroWfcPayloadFile(string stagedDirectory, string gameId,
|
public static string ResolveRetroWfcPayloadFile(string stagedDirectory,
|
||||||
RSAParameters? signingKey = null) =>
|
RSAParameters? signingKey = null) =>
|
||||||
Path.Combine(ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, gameId, signingKey),
|
Path.Combine(ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, signingKey),
|
||||||
PayloadRelativePath(gameId));
|
RetroWfcOfflinePayloadFile);
|
||||||
|
|
||||||
public static string ComputeRetroWfcPayloadSha256(string stagedDirectory, string gameId,
|
public static string ComputeRetroWfcPayloadSha256(string stagedDirectory,
|
||||||
RSAParameters? signingKey = null) =>
|
RSAParameters? signingKey = null) =>
|
||||||
Sha256File(ResolveRetroWfcPayloadFile(stagedDirectory, gameId, signingKey));
|
Sha256File(ResolveRetroWfcPayloadFile(stagedDirectory, signingKey));
|
||||||
|
|
||||||
public static void ValidateRetroWfcPayloadUri(string uriText)
|
public static void ValidateRetroWfcPayloadUri(string uriText)
|
||||||
{
|
{
|
||||||
if (!PayloadGames.Keys.Any(gameId => string.Equals(uriText, PayloadUri(gameId), StringComparison.Ordinal)))
|
if (!string.Equals(uriText, CurrentRetroWfcPayloadUri, StringComparison.Ordinal))
|
||||||
throw new InvalidDataException("The installer does not define this fixed Retro-WFC payload endpoint.");
|
throw new InvalidDataException("The installer does not define the fixed Retro-WFC payload endpoint.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<RetroWfcPayloadSnapshot> DownloadRetroWfcPayloadAsync(string uriText,
|
public static async Task<RetroWfcPayloadSnapshot> DownloadRetroWfcPayloadAsync(string uriText,
|
||||||
@@ -114,8 +96,7 @@ public static class RetroWfcPayload
|
|||||||
var uri = new Uri(uriText, UriKind.Absolute);
|
var uri = new Uri(uriText, UriKind.Absolute);
|
||||||
|
|
||||||
var root = Path.GetFullPath(destinationDirectory);
|
var root = Path.GetFullPath(destinationDirectory);
|
||||||
var payloadGame = uri.Query[3..]; // ValidateRetroWfcPayloadUri accepts only the exact ?g= form.
|
var destination = Path.Combine(root, RetroWfcOfflinePayloadFile);
|
||||||
var destination = Path.Combine(root, "binary", $"payload.{payloadGame}.bin");
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(destination)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(destination)!);
|
||||||
using var handler = new HttpClientHandler { AllowAutoRedirect = false };
|
using var handler = new HttpClientHandler { AllowAutoRedirect = false };
|
||||||
using var client = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
|
using var client = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
|
||||||
@@ -173,7 +154,7 @@ public static class RetroWfcPayload
|
|||||||
}
|
}
|
||||||
actualSha256 = Convert.ToHexString(hash.GetHashAndReset()).ToLowerInvariant();
|
actualSha256 = Convert.ToHexString(hash.GetHashAndReset()).ToLowerInvariant();
|
||||||
}
|
}
|
||||||
ValidateRetroWfcPayloadFile(temporary, uri.Query[3..]);
|
ValidateRetroWfcPayloadFile(temporary);
|
||||||
File.Move(temporary, destination, overwrite: true);
|
File.Move(temporary, destination, overwrite: true);
|
||||||
return new RetroWfcPayloadSnapshot(root, actualSha256, total);
|
return new RetroWfcPayloadSnapshot(root, actualSha256, total);
|
||||||
}
|
}
|
||||||
@@ -200,8 +181,7 @@ public static class RetroWfcPayload
|
|||||||
request.StatusCode is { } status && (int)status >= 500;
|
request.StatusCode is { } status && (int)status >= 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidateRetroWfcPayloadFile(string payload, string expectedGame,
|
private static void ValidateRetroWfcPayloadFile(string payload, RSAParameters? signingKey = null)
|
||||||
RSAParameters? signingKey = null)
|
|
||||||
{
|
{
|
||||||
byte[] image;
|
byte[] image;
|
||||||
using (var stream = File.OpenRead(payload))
|
using (var stream = File.OpenRead(payload))
|
||||||
@@ -221,10 +201,6 @@ public static class RetroWfcPayload
|
|||||||
throw new InvalidDataException(
|
throw new InvalidDataException(
|
||||||
$"The Retro-WFC payload declares {declaredSize} bytes but contains {image.Length}.");
|
$"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();
|
using var rsa = RSA.Create();
|
||||||
rsa.ImportParameters(signingKey ?? new RSAParameters
|
rsa.ImportParameters(signingKey ?? new RSAParameters
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,30 +11,29 @@ namespace WiiCompiled.Setup.Linux;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class DiscTool
|
internal static class DiscTool
|
||||||
{
|
{
|
||||||
/// <summary>Validates and extracts the disc, returning the supported release it is.</summary>
|
public static async Task ValidateAndExtractAsync(
|
||||||
public static async Task<ProjectManifest> ValidateAndExtractAsync(
|
string isoPath, ProjectManifest manifest, string assetsDirectory, string workspace,
|
||||||
string isoPath, IReadOnlyList<ProjectManifest> releases, string assetsDirectory, string workspace,
|
|
||||||
string? nodToolBin, IInstallReporter reporter, CancellationToken cancellationToken)
|
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);
|
var nodTool = nodToolBin ?? await NodToolProvider.ResolveAsync(workspace, cancellationToken);
|
||||||
|
|
||||||
// `nodtool info` only decodes the disc/partition headers (milliseconds); `nodtool extract`
|
// `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
|
// copies the whole data partition to disk (tens of seconds for a custom-track-heavy MKWii
|
||||||
// ISO). The game ID picks the release, so a wrong disc fails fast and an existing
|
// ISO). Checking the game ID first, before extracting, means a wrong disc fails fast -
|
||||||
// extraction is only reused for the same release.
|
// matching the original dolphin-tool `header` step this replaces.
|
||||||
reporter.Progress(InstallStages.ExtractDisc, "Reading the disc header", 2);
|
reporter.Progress(InstallStages.ExtractDisc, "Reading the disc header", 2);
|
||||||
var info = NodToolInfoParser.Parse(await RunInfoAsync(nodTool, isoPath, cancellationToken));
|
var info = NodToolInfoParser.Parse(await RunInfoAsync(nodTool, isoPath, cancellationToken));
|
||||||
var manifest = releases.FirstOrDefault(release =>
|
if (!string.Equals(info.GameId, manifest.GameId, StringComparison.Ordinal))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
reporter.Progress(InstallStages.ExtractDisc, "Reusing the verified extracted disc", 6);
|
throw new InvalidOperationException(
|
||||||
return manifest;
|
$"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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extracted straight into Assets/DATA (kept, not a scratch dir) - the runtime reads course/
|
// Extracted straight into Assets/DATA (kept, not a scratch dir) - the runtime reads course/
|
||||||
@@ -72,22 +71,6 @@ internal static class DiscTool
|
|||||||
File.Copy(relPath, Path.Combine(assetsDirectory, "StaticR.rel"), overwrite: true);
|
File.Copy(relPath, Path.Combine(assetsDirectory, "StaticR.rel"), overwrite: true);
|
||||||
File.WriteAllText(Path.Combine(assetsDirectory, ExtractionMarker), ExtractionRecord(dolSha, dataDir));
|
File.WriteAllText(Path.Combine(assetsDirectory, ExtractionMarker), ExtractionRecord(dolSha, dataDir));
|
||||||
reporter.Progress(InstallStages.ExtractDisc, "Disc validated and extracted", 6);
|
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)
|
private static async Task<string> RunInfoAsync(string nodTool, string isoPath, CancellationToken cancellationToken)
|
||||||
@@ -114,7 +97,7 @@ internal static class DiscTool
|
|||||||
|
|
||||||
private const string ExtractionMarker = ".disc-extracted";
|
private const string ExtractionMarker = ".disc-extracted";
|
||||||
|
|
||||||
// Each release has one accepted revision, so a completed, verified extraction is identical to a fresh one.
|
// Only one disc revision is accepted, so a completed, verified extraction is identical to a fresh one.
|
||||||
private static bool IsAlreadyExtracted(ProjectManifest manifest, string assetsDirectory)
|
private static bool IsAlreadyExtracted(ProjectManifest manifest, string assetsDirectory)
|
||||||
{
|
{
|
||||||
var marker = Path.Combine(assetsDirectory, ExtractionMarker);
|
var marker = Path.Combine(assetsDirectory, ExtractionMarker);
|
||||||
|
|||||||
@@ -95,14 +95,13 @@ internal static class Program
|
|||||||
if (installsRetro) retroDir = RetroRewindSource.ResolveRetroRewind6(retroDir!);
|
if (installsRetro) retroDir = RetroRewindSource.ResolveRetroRewind6(retroDir!);
|
||||||
|
|
||||||
var workspace = flags.GetValueOrDefault("workspace") ?? WorkspaceLocator.FindFrom(AppContext.BaseDirectory);
|
var workspace = flags.GetValueOrDefault("workspace") ?? WorkspaceLocator.FindFrom(AppContext.BaseDirectory);
|
||||||
var releases = ProjectManifest.LoadAll(workspace);
|
var manifest = ProjectManifest.Load(Path.Combine(workspace, "projects", "mkwii", "recomp.yml"));
|
||||||
var assetsDir = Path.Combine(workspace, "Assets");
|
var assetsDir = Path.Combine(workspace, "Assets");
|
||||||
|
|
||||||
reporter.Progress(InstallStages.Validate, "Checking prerequisites", 1);
|
reporter.Progress(InstallStages.Validate, "Checking prerequisites", 1);
|
||||||
ProjectManifest release;
|
|
||||||
if (flags.TryGetValue("game", out var isoPath) && !string.IsNullOrEmpty(isoPath))
|
if (flags.TryGetValue("game", out var isoPath) && !string.IsNullOrEmpty(isoPath))
|
||||||
{
|
{
|
||||||
release = await DiscTool.ValidateAndExtractAsync(isoPath, releases, assetsDir, workspace,
|
await DiscTool.ValidateAndExtractAsync(isoPath, manifest, assetsDir, workspace,
|
||||||
flags.GetValueOrDefault("disc-tool-bin"), reporter, token);
|
flags.GetValueOrDefault("disc-tool-bin"), reporter, token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -115,7 +114,6 @@ internal static class Program
|
|||||||
"No --game ISO was given and Assets/main.dol + Assets/StaticR.rel are not already present. " +
|
"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).");
|
"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 };
|
var state = JsonState.TryRead<InstallState>(StatePath) ?? new InstallState { Workspace = workspace };
|
||||||
@@ -135,10 +133,10 @@ internal static class Program
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// A valid signature authenticates a payload, but does not prove it is the latest
|
// A valid signature authenticates a payload, but does not prove it is the latest
|
||||||
// signed revision. Always ask the release's fixed endpoint for the current snapshot;
|
// signed revision. Always ask the fixed endpoint for the current snapshot; the
|
||||||
// the downloader verifies it before atomically replacing the cache.
|
// downloader verifies it before atomically replacing the cache.
|
||||||
await RetroWfcPayload.DownloadRetroWfcPayloadAsync(
|
await RetroWfcPayload.DownloadRetroWfcPayloadAsync(
|
||||||
RetroWfcPayload.PayloadUri(release.GameId), cacheDir, token);
|
RetroWfcPayload.CurrentRetroWfcPayloadUri, cacheDir, token);
|
||||||
}
|
}
|
||||||
catch (Exception downloadFailure) when (!token.IsCancellationRequested &&
|
catch (Exception downloadFailure) when (!token.IsCancellationRequested &&
|
||||||
downloadFailure is HttpRequestException or TimeoutException
|
downloadFailure is HttpRequestException or TimeoutException
|
||||||
@@ -149,7 +147,7 @@ internal static class Program
|
|||||||
// that must remain a hard failure instead of hiding possible endpoint tampering.
|
// that must remain a hard failure instead of hiding possible endpoint tampering.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(cacheDir, gameId: release.GameId);
|
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(cacheDir);
|
||||||
}
|
}
|
||||||
catch (Exception cacheFailure) when (cacheFailure is IOException or
|
catch (Exception cacheFailure) when (cacheFailure is IOException or
|
||||||
UnauthorizedAccessException or InvalidDataException)
|
UnauthorizedAccessException or InvalidDataException)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Text.RegularExpressions;
|
|||||||
namespace WiiCompiled.Setup.Linux;
|
namespace WiiCompiled.Setup.Linux;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The handful of facts this tool needs out of a projects/*/recomp.yml. Parsed literally line by
|
/// The handful of facts this tool needs out of projects/mkwii/recomp.yml. Parsed literally line by
|
||||||
/// line - the same approach Launcher/NativeBuildFlags.ps1's Get-MkwProjectPins and
|
/// 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
|
/// Launcher/local-build.sh already use - rather than pulling in a YAML library, since the manifest
|
||||||
/// is machine-written with a fixed shape.
|
/// is machine-written with a fixed shape.
|
||||||
@@ -67,21 +67,4 @@ internal sealed class ProjectManifest
|
|||||||
|
|
||||||
return new ProjectManifest { GameId = gameId, Region = region, DolSha256 = dolSha, RelSha256 = relSha };
|
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,7 +64,9 @@ internal static class ConsoleCommands
|
|||||||
{
|
{
|
||||||
using var payload = PayloadArchive.OpenCurrent();
|
using var payload = PayloadArchive.OpenCurrent();
|
||||||
var manifest = payload.ReadManifest();
|
var manifest = payload.ReadManifest();
|
||||||
var tool = payload.ExtractDiscTool(temp);
|
var tool = Path.Combine(temp, "nodtool.exe");
|
||||||
|
payload.ExtractEntry(InstalledLayout.ToolkitEntryPrefix + "nodtool.exe", tool);
|
||||||
|
payload.ExtractDirectory(InstalledLayout.ToolkitEntryPrefix + "Redist", temp);
|
||||||
reporter?.Progress(InstallStages.Validate, "Checking the Wii disc image...", 10);
|
reporter?.Progress(InstallStages.Validate, "Checking the Wii disc image...", 10);
|
||||||
var header = InputValidation.ReadDiscHeaderAsync(tool, command.GamePath!).GetAwaiter().GetResult();
|
var header = InputValidation.ReadDiscHeaderAsync(tool, command.GamePath!).GetAwaiter().GetResult();
|
||||||
InputValidation.EnsureCompatibleDisc(header, manifest);
|
InputValidation.EnsureCompatibleDisc(header, manifest);
|
||||||
|
|||||||
@@ -54,29 +54,33 @@ internal static class InputValidation
|
|||||||
}
|
}
|
||||||
: "Unknown";
|
: "Unknown";
|
||||||
|
|
||||||
/// <summary>The supported release this disc is, or a clear rejection naming every supported one.</summary>
|
public static void EnsureCompatibleDisc(DiscHeader header, PayloadManifest manifest)
|
||||||
public static GameRelease EnsureCompatibleDisc(DiscHeader header, PayloadManifest manifest) =>
|
{
|
||||||
manifest.SupportedReleases.FirstOrDefault(release =>
|
if (!header.GameId.Equals(manifest.ExpectedGameId, StringComparison.OrdinalIgnoreCase))
|
||||||
release.GameId.Equals(header.GameId, StringComparison.OrdinalIgnoreCase))
|
{
|
||||||
?? throw new InvalidDataException(
|
throw new InvalidDataException(
|
||||||
"This build supports Mario Kart Wii " +
|
$"This build supports Mario Kart Wii PAL ({manifest.ExpectedGameId}). " +
|
||||||
string.Join(", ", manifest.SupportedReleases.Select(release =>
|
$"The selected image is {header.GameId} ({header.InternalName}, {header.Region}).");
|
||||||
$"{RegionFromGameId(release.GameId)} ({release.GameId})")) +
|
}
|
||||||
$". The selected image is {header.GameId} ({header.InternalName}, {header.Region}).");
|
}
|
||||||
|
|
||||||
// Forwarding wrappers over WiiCompiled.Setup.Common.RetroWfcPayload that require the game id,
|
// Thin forwarding wrappers: the actual download/RSA-verification logic lives in
|
||||||
// so no caller here can silently fall back to one region's payload.
|
// WiiCompiled.Setup.Common.RetroWfcPayload (shared with WiiCompiled.Setup.Linux) so there's one
|
||||||
public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory, string gameId,
|
// copy of it, not two. Kept under these names so every existing call site here
|
||||||
RSAParameters? signingKey = null) =>
|
// (ProductRepairService.cs, LocalBuildService.cs, Installation.cs, SelfTests.cs) is unchanged.
|
||||||
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, gameId, signingKey);
|
public const string CurrentRetroWfcPayloadUri = RetroWfcPayload.CurrentRetroWfcPayloadUri;
|
||||||
|
|
||||||
public static string ResolveRetroWfcPayloadFile(string stagedDirectory, string gameId,
|
public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory,
|
||||||
RSAParameters? signingKey = null) =>
|
RSAParameters? signingKey = null) =>
|
||||||
RetroWfcPayload.ResolveRetroWfcPayloadFile(stagedDirectory, gameId, signingKey);
|
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, signingKey);
|
||||||
|
|
||||||
public static string ComputeRetroWfcPayloadSha256(string stagedDirectory, string gameId,
|
public static string ResolveRetroWfcPayloadFile(string stagedDirectory,
|
||||||
RSAParameters? signingKey = null) =>
|
RSAParameters? signingKey = null) =>
|
||||||
RetroWfcPayload.ComputeRetroWfcPayloadSha256(stagedDirectory, gameId, signingKey);
|
RetroWfcPayload.ResolveRetroWfcPayloadFile(stagedDirectory, signingKey);
|
||||||
|
|
||||||
|
public static string ComputeRetroWfcPayloadSha256(string stagedDirectory,
|
||||||
|
RSAParameters? signingKey = null) =>
|
||||||
|
RetroWfcPayload.ComputeRetroWfcPayloadSha256(stagedDirectory, signingKey);
|
||||||
|
|
||||||
public static void ValidateRetroWfcPayloadUri(string uriText) =>
|
public static void ValidateRetroWfcPayloadUri(string uriText) =>
|
||||||
RetroWfcPayload.ValidateRetroWfcPayloadUri(uriText);
|
RetroWfcPayload.ValidateRetroWfcPayloadUri(uriText);
|
||||||
|
|||||||
@@ -131,8 +131,6 @@ internal sealed class Installation
|
|||||||
Workspace + "LocalBuild.ps1",
|
Workspace + "LocalBuild.ps1",
|
||||||
Workspace + "NativeBuildFlags.ps1",
|
Workspace + "NativeBuildFlags.ps1",
|
||||||
Workspace + @"projects\mkwii\recomp.yml",
|
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\CMakeLists.txt",
|
||||||
Workspace + @"runtime\assets\dsp\dsp_coef.bin"
|
Workspace + @"runtime\assets\dsp\dsp_coef.bin"
|
||||||
];
|
];
|
||||||
@@ -170,26 +168,6 @@ internal sealed class Installation
|
|||||||
|
|
||||||
public InstallState? ReadInstallState() => JsonState.TryRead<InstallState>(InstallStatePath);
|
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);
|
internal ToolkitState? ReadToolkitState() => JsonState.TryRead<ToolkitState>(ToolkitStatePath);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -418,7 +396,7 @@ internal sealed class Installation
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload, ReadGameId());
|
var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload);
|
||||||
if (!InputValidation.Sha256File(payload).Equals(fingerprint.RetroWfcPayloadSha256,
|
if (!InputValidation.Sha256File(payload).Equals(fingerprint.RetroWfcPayloadSha256,
|
||||||
StringComparison.OrdinalIgnoreCase) ||
|
StringComparison.OrdinalIgnoreCase) ||
|
||||||
new FileInfo(payload).Length != fingerprint.RetroWfcPayloadLength)
|
new FileInfo(payload).Length != fingerprint.RetroWfcPayloadLength)
|
||||||
@@ -603,7 +581,7 @@ internal sealed class Installation
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload, ReadGameId());
|
var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload);
|
||||||
return new FileInfo(payload).Length == snapshot.ByteLength &&
|
return new FileInfo(payload).Length == snapshot.ByteLength &&
|
||||||
InputValidation.Sha256File(payload).Equals(snapshot.Sha256, StringComparison.Ordinal);
|
InputValidation.Sha256File(payload).Equals(snapshot.Sha256, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,28 +40,6 @@ internal sealed class InstallerEngine
|
|||||||
var toolkit = InstalledLayout.Toolkit(staging);
|
var toolkit = InstalledLayout.Toolkit(staging);
|
||||||
var workspace = InstalledLayout.Workspace(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 candidateToolkitFingerprint = manifest.ToolkitFingerprint;
|
||||||
var candidateToolkitPackageFingerprint = manifest.ToolkitPackageFingerprint;
|
var candidateToolkitPackageFingerprint = manifest.ToolkitPackageFingerprint;
|
||||||
var candidateRuntimeAssetsFingerprint = manifest.RuntimeAssetsFingerprint;
|
var candidateRuntimeAssetsFingerprint = manifest.RuntimeAssetsFingerprint;
|
||||||
@@ -71,7 +49,7 @@ internal sealed class InstallerEngine
|
|||||||
var installedToolkitPackageFingerprint = existing.IsPresent
|
var installedToolkitPackageFingerprint = existing.IsPresent
|
||||||
? existing.ResolveToolkitPackageFingerprint()
|
? existing.ResolveToolkitPackageFingerprint()
|
||||||
: "";
|
: "";
|
||||||
var reusableGameAssets = FindReusableGameAssets(existing, release);
|
var reusableGameAssets = FindReusableGameAssets(existing, manifest);
|
||||||
|
|
||||||
var sameToolkit = existing.IsPresent && reusableGameAssets is not null &&
|
var sameToolkit = existing.IsPresent && reusableGameAssets is not null &&
|
||||||
installedToolkitFingerprint.Equals(candidateToolkitFingerprint,
|
installedToolkitFingerprint.Equals(candidateToolkitFingerprint,
|
||||||
@@ -90,7 +68,7 @@ internal sealed class InstallerEngine
|
|||||||
var extractWorkspace = !sameToolkit || !runtimeAssetsCurrent;
|
var extractWorkspace = !sameToolkit || !runtimeAssetsCurrent;
|
||||||
|
|
||||||
_reporter.Progress(InstallStages.ExtractToolkit,
|
_reporter.Progress(InstallStages.ExtractToolkit,
|
||||||
"Inspecting the release's local recompilation toolkit...", 4);
|
"Inspecting the release's local recompilation toolkit...", 1);
|
||||||
if (extractToolkit) payload.ExtractDirectory(InstalledLayout.ToolkitDirectoryName, toolkit);
|
if (extractToolkit) payload.ExtractDirectory(InstalledLayout.ToolkitDirectoryName, toolkit);
|
||||||
if (extractWorkspace)
|
if (extractWorkspace)
|
||||||
{
|
{
|
||||||
@@ -104,10 +82,30 @@ internal sealed class InstallerEngine
|
|||||||
payload.ExtractEntry(InstalledLayout.PayloadManifestFileName,
|
payload.ExtractEntry(InstalledLayout.PayloadManifestFileName,
|
||||||
Path.Combine(staging, 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)
|
if (sameToolkit)
|
||||||
{
|
{
|
||||||
var desiredInputDrift = ProductRepairService.FindDesiredInputDrift(existing,
|
var desiredInputDrift = ProductRepairService.FindDesiredInputDrift(existing,
|
||||||
candidateToolkitFingerprint, release.DolSha256, release.RelSha256);
|
candidateToolkitFingerprint, manifest.ExpectedDolSha256, manifest.ExpectedRelSha256);
|
||||||
if (desiredInputDrift.Retro && retroCompileInputs is null)
|
if (desiredInputDrift.Retro && retroCompileInputs is null)
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"This release changes the clean game inputs used by the installed Retro Rewind product. " +
|
"This release changes the clean game inputs used by the installed Retro Rewind product. " +
|
||||||
@@ -115,7 +113,7 @@ internal sealed class InstallerEngine
|
|||||||
|
|
||||||
var reconciliation = await ReconcileSameToolkitAsync(existing, retroCompileInputs,
|
var reconciliation = await ReconcileSameToolkitAsync(existing, retroCompileInputs,
|
||||||
canonicalRetroRoot, options.RetroWfcPayloadMode, Path.Combine(staging, "repair"),
|
canonicalRetroRoot, options.RetroWfcPayloadMode, Path.Combine(staging, "repair"),
|
||||||
release.DolSha256, release.RelSha256, cancellationToken);
|
manifest.ExpectedDolSha256, manifest.ExpectedRelSha256, cancellationToken);
|
||||||
var remainingCancellation = reconciliation.PublicationCommitted
|
var remainingCancellation = reconciliation.PublicationCommitted
|
||||||
? CancellationToken.None
|
? CancellationToken.None
|
||||||
: cancellationToken;
|
: cancellationToken;
|
||||||
@@ -127,10 +125,11 @@ internal sealed class InstallerEngine
|
|||||||
|
|
||||||
remainingCancellation.ThrowIfCancellationRequested();
|
remainingCancellation.ThrowIfCancellationRequested();
|
||||||
EnsureReconciliationCurrent(existing, candidateToolkitFingerprint, retroCompileInputs,
|
EnsureReconciliationCurrent(existing, candidateToolkitFingerprint, retroCompileInputs,
|
||||||
release.DolSha256, release.RelSha256, reconciliation.CachedRetroWfcPayloadMatches);
|
manifest.ExpectedDolSha256, manifest.ExpectedRelSha256,
|
||||||
|
reconciliation.CachedRetroWfcPayloadMatches);
|
||||||
|
|
||||||
var updatedState = BuildInstallState(existing.ReadInstallState(), installDirectory, manifest,
|
var updatedState = BuildInstallState(existing.ReadInstallState(), installDirectory, manifest,
|
||||||
release, retroCompileInputs, canonicalRetroRoot, options.RetroWfcPayloadMode);
|
retroCompileInputs, canonicalRetroRoot, options.RetroWfcPayloadMode);
|
||||||
PrepareMetadata(staging, manifest, updatedState);
|
PrepareMetadata(staging, manifest, updatedState);
|
||||||
remainingCancellation.ThrowIfCancellationRequested();
|
remainingCancellation.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
@@ -160,11 +159,11 @@ internal sealed class InstallerEngine
|
|||||||
if (reusableGameAssets is null)
|
if (reusableGameAssets is null)
|
||||||
{
|
{
|
||||||
await ExtractGameAssetsAsync(nodTool, options.GamePath,
|
await ExtractGameAssetsAsync(nodTool, options.GamePath,
|
||||||
Path.Combine(staging, "GameAssets"), release, cancellationToken);
|
Path.Combine(staging, "GameAssets"), manifest, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
await PublishToolkitAndReconcileProductsAsync(existing, staging, workspace, manifest,
|
await PublishToolkitAndReconcileProductsAsync(existing, staging, workspace, manifest,
|
||||||
release, previousState, options, canonicalRetroRoot, retroCompileInputs,
|
previousState, options, canonicalRetroRoot, retroCompileInputs,
|
||||||
publishGameAssets: reusableGameAssets is null, createShortcuts: firstInstall,
|
publishGameAssets: reusableGameAssets is null, createShortcuts: firstInstall,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
@@ -188,7 +187,7 @@ internal sealed class InstallerEngine
|
|||||||
["generated", "build", "native-build", "Assets", "PulsarPacks"];
|
["generated", "build", "native-build", "Assets", "PulsarPacks"];
|
||||||
|
|
||||||
private async Task PublishToolkitAndReconcileProductsAsync(Installation existing, string staging,
|
private async Task PublishToolkitAndReconcileProductsAsync(Installation existing, string staging,
|
||||||
string stagedWorkspace, PayloadManifest manifest, GameRelease release, InstallState? previousState,
|
string stagedWorkspace, PayloadManifest manifest, InstallState? previousState,
|
||||||
InstallOptions options, string? canonicalRetroRoot,
|
InstallOptions options, string? canonicalRetroRoot,
|
||||||
RetroRewindCompileInputs? retroCompileInputs,
|
RetroRewindCompileInputs? retroCompileInputs,
|
||||||
bool publishGameAssets, bool createShortcuts, CancellationToken cancellationToken)
|
bool publishGameAssets, bool createShortcuts, CancellationToken cancellationToken)
|
||||||
@@ -207,7 +206,7 @@ internal sealed class InstallerEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var state = BuildInstallState(previousState, installDirectory, manifest, release,
|
var state = BuildInstallState(previousState, installDirectory, manifest,
|
||||||
compileInputs: null, canonicalRetroRoot, options.RetroWfcPayloadMode);
|
compileInputs: null, canonicalRetroRoot, options.RetroWfcPayloadMode);
|
||||||
PrepareMetadata(staging, manifest, state);
|
PrepareMetadata(staging, manifest, state);
|
||||||
|
|
||||||
@@ -227,9 +226,10 @@ internal sealed class InstallerEngine
|
|||||||
|
|
||||||
var reconciliation = await ReconcileSameToolkitAsync(existing, retroCompileInputs,
|
var reconciliation = await ReconcileSameToolkitAsync(existing, retroCompileInputs,
|
||||||
canonicalRetroRoot, options.RetroWfcPayloadMode, repairScratch: null,
|
canonicalRetroRoot, options.RetroWfcPayloadMode, repairScratch: null,
|
||||||
release.DolSha256, release.RelSha256, cancellationToken);
|
manifest.ExpectedDolSha256, manifest.ExpectedRelSha256, cancellationToken);
|
||||||
EnsureReconciliationCurrent(existing, manifest.ToolkitFingerprint, retroCompileInputs,
|
EnsureReconciliationCurrent(existing, manifest.ToolkitFingerprint, retroCompileInputs,
|
||||||
release.DolSha256, release.RelSha256, reconciliation.CachedRetroWfcPayloadMatches);
|
manifest.ExpectedDolSha256, manifest.ExpectedRelSha256,
|
||||||
|
reconciliation.CachedRetroWfcPayloadMatches);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<ProductRepairService.ReconciliationResult> ReconcileSameToolkitAsync(Installation existing,
|
private Task<ProductRepairService.ReconciliationResult> ReconcileSameToolkitAsync(Installation existing,
|
||||||
@@ -354,8 +354,7 @@ internal sealed class InstallerEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static InstallState BuildInstallState(InstallState? previousState, string installDirectory,
|
private static InstallState BuildInstallState(InstallState? previousState, string installDirectory,
|
||||||
PayloadManifest manifest, GameRelease release, RetroRewindCompileInputs? compileInputs,
|
PayloadManifest manifest, RetroRewindCompileInputs? compileInputs, string? canonicalRetroRoot,
|
||||||
string? canonicalRetroRoot,
|
|
||||||
RetroWfcPayloadMode payloadMode,
|
RetroWfcPayloadMode payloadMode,
|
||||||
RetroWfcPayloadSnapshot? retroWfcPayloadSnapshot = null)
|
RetroWfcPayloadSnapshot? retroWfcPayloadSnapshot = null)
|
||||||
{
|
{
|
||||||
@@ -369,8 +368,8 @@ internal sealed class InstallerEngine
|
|||||||
InstalledUtc = previousState?.InstalledUtc ?? DateTime.UtcNow,
|
InstalledUtc = previousState?.InstalledUtc ?? DateTime.UtcNow,
|
||||||
RetroRewindInstalled = previousState?.RetroRewindInstalled ?? false,
|
RetroRewindInstalled = previousState?.RetroRewindInstalled ?? false,
|
||||||
ToolkitReleaseTag = manifest.ToolkitReleaseTag,
|
ToolkitReleaseTag = manifest.ToolkitReleaseTag,
|
||||||
DolSha256 = release.DolSha256,
|
DolSha256 = manifest.ExpectedDolSha256,
|
||||||
RelSha256 = release.RelSha256,
|
RelSha256 = manifest.ExpectedRelSha256,
|
||||||
RetroRewindCodePulSha256 = previousState?.RetroRewindCodePulSha256 ?? "",
|
RetroRewindCodePulSha256 = previousState?.RetroRewindCodePulSha256 ?? "",
|
||||||
RetroRewindCompileInputsSha256 = previousState?.RetroRewindCompileInputsSha256 ?? "",
|
RetroRewindCompileInputsSha256 = previousState?.RetroRewindCompileInputsSha256 ?? "",
|
||||||
RetroWfcPayloadMode = previousState?.RetroWfcPayloadMode ?? "",
|
RetroWfcPayloadMode = previousState?.RetroWfcPayloadMode ?? "",
|
||||||
@@ -445,7 +444,8 @@ internal sealed class InstallerEngine
|
|||||||
Path.Combine(InstalledLayout.Workspace(installDirectory), "runtime", "assets")));
|
Path.Combine(InstalledLayout.Workspace(installDirectory), "runtime", "assets")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidateRetroOptions(string? canonicalRetroRoot, RetroWfcPayloadMode mode)
|
private static void ValidateRetroOptions(string? canonicalRetroRoot, RetroWfcPayloadMode mode,
|
||||||
|
PayloadManifest manifest)
|
||||||
{
|
{
|
||||||
if (canonicalRetroRoot is null && mode != RetroWfcPayloadMode.NotApplicable)
|
if (canonicalRetroRoot is null && mode != RetroWfcPayloadMode.NotApplicable)
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
@@ -453,9 +453,11 @@ internal sealed class InstallerEngine
|
|||||||
if (canonicalRetroRoot is not null && mode == RetroWfcPayloadMode.NotApplicable)
|
if (canonicalRetroRoot is not null && mode == RetroWfcPayloadMode.NotApplicable)
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"Download the Retro-WFC payload, or explicitly skip the optional payload.");
|
"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, GameRelease release)
|
private string? FindReusableGameAssets(Installation existing, PayloadManifest manifest)
|
||||||
{
|
{
|
||||||
var dataRoot = existing.GameDataDirectory;
|
var dataRoot = existing.GameDataDirectory;
|
||||||
// No fst.bin simply means nothing was extracted here before; anything past that gate is an
|
// No fst.bin simply means nothing was extracted here before; anything past that gate is an
|
||||||
@@ -464,7 +466,7 @@ internal sealed class InstallerEngine
|
|||||||
if (!File.Exists(Path.Combine(dataRoot, "sys", "fst.bin"))) return null;
|
if (!File.Exists(Path.Combine(dataRoot, "sys", "fst.bin"))) return null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ValidateExtractedGame(dataRoot, release);
|
ValidateExtractedGame(dataRoot, manifest);
|
||||||
return dataRoot;
|
return dataRoot;
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or InvalidDataException)
|
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or InvalidDataException)
|
||||||
@@ -476,7 +478,7 @@ internal sealed class InstallerEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExtractGameAssetsAsync(string nodTool, string gamePath, string destination,
|
private async Task ExtractGameAssetsAsync(string nodTool, string gamePath, string destination,
|
||||||
GameRelease release, CancellationToken cancellationToken)
|
PayloadManifest manifest, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_reporter.Progress(InstallStages.ExtractDisc,
|
_reporter.Progress(InstallStages.ExtractDisc,
|
||||||
"Extracting the game disc. This is the longest preparation step...", 6);
|
"Extracting the game disc. This is the longest preparation step...", 6);
|
||||||
@@ -491,16 +493,15 @@ internal sealed class InstallerEngine
|
|||||||
cancellationToken);
|
cancellationToken);
|
||||||
if (extraction.ExitCode != 0)
|
if (extraction.ExitCode != 0)
|
||||||
throw new InvalidDataException("Game extraction failed. " + extraction.CombinedOutput.Trim());
|
throw new InvalidDataException("Game extraction failed. " + extraction.CombinedOutput.Trim());
|
||||||
ValidateExtractedGame(dataRoot, release);
|
ValidateExtractedGame(dataRoot, manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void ValidateExtractedGame(string dataRoot, GameRelease release)
|
private static void ValidateExtractedGame(string dataRoot, PayloadManifest manifest)
|
||||||
{
|
{
|
||||||
var dol = Path.Combine(dataRoot, "sys", "main.dol");
|
var dol = Path.Combine(dataRoot, "sys", "main.dol");
|
||||||
var rel = Path.Combine(dataRoot, "files", "rel", "StaticR.rel");
|
var rel = Path.Combine(dataRoot, "files", "rel", "StaticR.rel");
|
||||||
var fst = Path.Combine(dataRoot, "sys", "fst.bin");
|
var fst = Path.Combine(dataRoot, "sys", "fst.bin");
|
||||||
var boot = Path.Combine(dataRoot, "sys", "boot.bin");
|
var missing = new[] { dol, rel, fst }.Where(path => !File.Exists(path))
|
||||||
var missing = new[] { dol, rel, fst, boot }.Where(path => !File.Exists(path))
|
|
||||||
.Select(path => Path.GetRelativePath(dataRoot, path)).ToList();
|
.Select(path => Path.GetRelativePath(dataRoot, path)).ToList();
|
||||||
if (missing.Count > 0)
|
if (missing.Count > 0)
|
||||||
throw new InvalidDataException(
|
throw new InvalidDataException(
|
||||||
@@ -508,13 +509,10 @@ internal sealed class InstallerEngine
|
|||||||
string.Join(", ", missing) + ".");
|
string.Join(", ", missing) + ".");
|
||||||
|
|
||||||
var mismatches = new List<string>();
|
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[]
|
foreach (var (name, path, expected) in new[]
|
||||||
{
|
{
|
||||||
("main.dol", dol, release.DolSha256),
|
("main.dol", dol, manifest.ExpectedDolSha256),
|
||||||
("StaticR.rel", rel, release.RelSha256)
|
("StaticR.rel", rel, manifest.ExpectedRelSha256)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
var actual = InputValidation.Sha256File(path);
|
var actual = InputValidation.Sha256File(path);
|
||||||
@@ -525,7 +523,7 @@ internal sealed class InstallerEngine
|
|||||||
|
|
||||||
if (mismatches.Count > 0)
|
if (mismatches.Count > 0)
|
||||||
throw new InvalidDataException(
|
throw new InvalidDataException(
|
||||||
$"The disc is {release.GameId} but its game data does not match the supported clean revision: " +
|
"The disc is RMCP01 but its game code does not match the supported clean PAL revision: " +
|
||||||
string.Join("; ", mismatches) + ". " +
|
string.Join("; ", mismatches) + ". " +
|
||||||
"Patched or otherwise modified game code cannot be installed safely.");
|
"Patched or otherwise modified game code cannot be installed safely.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ internal sealed class LocalBuildService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task BuildAsync(string installStaging, BuildProfile profile, string outputDirectory,
|
public async Task BuildAsync(string installStaging, BuildProfile profile, string outputDirectory,
|
||||||
RetroWfcPayloadMode retroWfcPayloadMode, string? retroWfcOfflinePayloadDirectory,
|
RetroWfcPayloadMode retroWfcPayloadMode, string? retroWfcOfflinePayloadDirectory,
|
||||||
string? retroWfcGameId, CancellationToken cancellationToken,
|
CancellationToken cancellationToken, ToolkitFingerprintComponents? toolkitComponents = null,
|
||||||
ToolkitFingerprintComponents? toolkitComponents = null,
|
|
||||||
bool forceCleanBuild = false, BuildProgressWindow? progress = null,
|
bool forceCleanBuild = false, BuildProgressWindow? progress = null,
|
||||||
string? retroRewindPackageDirectory = null, string? baseOutputDirectory = null)
|
string? retroRewindPackageDirectory = null, string? baseOutputDirectory = null)
|
||||||
{
|
{
|
||||||
@@ -46,9 +45,8 @@ internal sealed class LocalBuildService
|
|||||||
retroRewindPackageDirectory = RetroRewindSource.ResolveRetroRewind6(
|
retroRewindPackageDirectory = RetroRewindSource.ResolveRetroRewind6(
|
||||||
retroRewindPackageDirectory);
|
retroRewindPackageDirectory);
|
||||||
if (retroWfcPayloadMode == RetroWfcPayloadMode.Online)
|
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>
|
var arguments = new List<string>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,23 +33,16 @@ internal sealed class InstallOptions
|
|||||||
public bool HasRetroRewind => RetroDirectoryPath is not null;
|
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
|
internal sealed class PayloadManifest
|
||||||
{
|
{
|
||||||
public const int CurrentSchemaVersion = 3;
|
|
||||||
|
|
||||||
public int SchemaVersion { get; set; }
|
public int SchemaVersion { get; set; }
|
||||||
public string ProductVersion { get; set; } = "";
|
public string ProductVersion { get; set; } = "";
|
||||||
public List<GameRelease> SupportedReleases { get; set; } = [];
|
public string ExpectedGameId { get; set; } = "RMCP01";
|
||||||
|
public string ExpectedDolSha256 { get; set; } = "";
|
||||||
|
public string ExpectedRelSha256 { get; set; } = "";
|
||||||
public string ToolkitReleaseTag { get; set; } = "";
|
public string ToolkitReleaseTag { get; set; } = "";
|
||||||
public string BuildModel { get; set; } = "";
|
public string BuildModel { get; set; } = "";
|
||||||
|
public string RetroWfcPayloadUri { get; set; } = "";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Content identities computed once at release-build time (<c>Build-Installer.ps1 --emit-payload-identities</c>)
|
/// Content identities computed once at release-build time (<c>Build-Installer.ps1 --emit-payload-identities</c>)
|
||||||
|
|||||||
@@ -54,21 +54,10 @@ internal sealed class PayloadArchive : IDisposable
|
|||||||
var entry = FindEntry(InstalledLayout.PayloadManifestFileName)
|
var entry = FindEntry(InstalledLayout.PayloadManifestFileName)
|
||||||
?? throw new InvalidDataException("The payload manifest is missing.");
|
?? throw new InvalidDataException("The payload manifest is missing.");
|
||||||
using var stream = entry.Open();
|
using var stream = entry.Open();
|
||||||
return ParseManifest(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static PayloadManifest ParseManifest(Stream stream)
|
|
||||||
{
|
|
||||||
var manifest = JsonSerializer.Deserialize<PayloadManifest>(stream,
|
var manifest = JsonSerializer.Deserialize<PayloadManifest>(stream,
|
||||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true })
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true })
|
||||||
?? throw new InvalidDataException("The payload manifest is invalid.");
|
?? throw new InvalidDataException("The payload manifest is invalid.");
|
||||||
ValidateManifest(manifest);
|
if (manifest.SchemaVersion != 2)
|
||||||
return manifest;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void ValidateManifest(PayloadManifest manifest)
|
|
||||||
{
|
|
||||||
if (manifest.SchemaVersion != PayloadManifest.CurrentSchemaVersion)
|
|
||||||
throw new InvalidDataException($"Unsupported payload schema {manifest.SchemaVersion}.");
|
throw new InvalidDataException($"Unsupported payload schema {manifest.SchemaVersion}.");
|
||||||
// The payload identities are the release-computed replacement for hashing the whole
|
// 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.
|
// toolkit on the user's machine; a payload without them was packaged incorrectly.
|
||||||
@@ -76,30 +65,8 @@ internal sealed class PayloadArchive : IDisposable
|
|||||||
string.IsNullOrWhiteSpace(manifest.ToolkitPackageFingerprint) ||
|
string.IsNullOrWhiteSpace(manifest.ToolkitPackageFingerprint) ||
|
||||||
string.IsNullOrWhiteSpace(manifest.RuntimeAssetsFingerprint))
|
string.IsNullOrWhiteSpace(manifest.RuntimeAssetsFingerprint))
|
||||||
throw new InvalidDataException("The payload manifest is missing its content identities.");
|
throw new InvalidDataException("The payload manifest is missing its content identities.");
|
||||||
if (manifest.SupportedReleases is not { Count: > 0 })
|
InputValidation.ValidateRetroWfcPayloadUri(manifest.RetroWfcPayloadUri);
|
||||||
throw new InvalidDataException("The payload manifest names no supported game release.");
|
return manifest;
|
||||||
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)
|
public void ExtractEntry(string entryName, string destination)
|
||||||
|
|||||||
@@ -99,11 +99,7 @@ internal sealed class ProductRepairService
|
|||||||
Directory.CreateDirectory(scratchRoot);
|
Directory.CreateDirectory(scratchRoot);
|
||||||
|
|
||||||
RetroWfcPayloadSnapshot? payloadSnapshot = null;
|
RetroWfcPayloadSnapshot? payloadSnapshot = null;
|
||||||
// The installed disc's region decides which Retro-WFC payload the product embeds.
|
if (requestedPayloadMode == RetroWfcPayloadMode.Online)
|
||||||
var payloadGameId = requestedPayloadMode == RetroWfcPayloadMode.Online
|
|
||||||
? _installation.ReadGameId()
|
|
||||||
: null;
|
|
||||||
if (payloadGameId is not null)
|
|
||||||
{
|
{
|
||||||
_reporter.Progress(InstallStages.PrepareRetro,
|
_reporter.Progress(InstallStages.PrepareRetro,
|
||||||
"Downloading the current shared Retro-WFC payload snapshot...", 3);
|
"Downloading the current shared Retro-WFC payload snapshot...", 3);
|
||||||
@@ -111,12 +107,12 @@ internal sealed class ProductRepairService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
payloadSnapshot = await InputValidation.DownloadRetroWfcPayloadAsync(
|
payloadSnapshot = await InputValidation.DownloadRetroWfcPayloadAsync(
|
||||||
RetroWfcPayload.PayloadUri(payloadGameId), payloadScratch, cancellationToken);
|
InputValidation.CurrentRetroWfcPayloadUri, payloadScratch, cancellationToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!cancellationToken.IsCancellationRequested &&
|
catch (Exception ex) when (!cancellationToken.IsCancellationRequested &&
|
||||||
ex is HttpRequestException or TimeoutException or IOException)
|
ex is HttpRequestException or TimeoutException or IOException)
|
||||||
{
|
{
|
||||||
payloadSnapshot = RecoverInstalledRetroWfcPayload(toolkitFingerprint, payloadGameId,
|
payloadSnapshot = RecoverInstalledRetroWfcPayload(toolkitFingerprint,
|
||||||
Path.Combine(scratchRoot, "retro-wfc-payload-recovered"), ex, cancellationToken);
|
Path.Combine(scratchRoot, "retro-wfc-payload-recovered"), ex, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,7 +236,7 @@ internal sealed class ProductRepairService
|
|||||||
"Recompiling Mario Kart Wii and Retro Rewind with the installed toolkit...", 5);
|
"Recompiling Mario Kart Wii and Retro Rewind with the installed toolkit...", 5);
|
||||||
await BuildWithCleanRetryAsync(forceCleanBuild, clean =>
|
await BuildWithCleanRetryAsync(forceCleanBuild, clean =>
|
||||||
builder.BuildAsync(_installation.Root, BuildProfile.Both, retroOutput,
|
builder.BuildAsync(_installation.Root, BuildProfile.Both, retroOutput,
|
||||||
requestedPayloadMode, payloadSnapshot?.Directory, payloadGameId, cancellationToken,
|
requestedPayloadMode, payloadSnapshot?.Directory, cancellationToken,
|
||||||
toolkitComponents, clean,
|
toolkitComponents, clean,
|
||||||
progress: new BuildProgressWindow(_reporter, InstallStages.BuildBase, 5, 92),
|
progress: new BuildProgressWindow(_reporter, InstallStages.BuildBase, 5, 92),
|
||||||
retroRewindPackageDirectory: compileInputs.RetroRewindRoot,
|
retroRewindPackageDirectory: compileInputs.RetroRewindRoot,
|
||||||
@@ -259,7 +255,7 @@ internal sealed class ProductRepairService
|
|||||||
"Recompiling Mario Kart Wii with the installed toolkit...", 5);
|
"Recompiling Mario Kart Wii with the installed toolkit...", 5);
|
||||||
await BuildWithCleanRetryAsync(forceCleanBuild, clean =>
|
await BuildWithCleanRetryAsync(forceCleanBuild, clean =>
|
||||||
builder.BuildAsync(_installation.Root, BuildProfile.Base, baseOutput,
|
builder.BuildAsync(_installation.Root, BuildProfile.Base, baseOutput,
|
||||||
RetroWfcPayloadMode.NotApplicable, null, null, cancellationToken,
|
RetroWfcPayloadMode.NotApplicable, null, cancellationToken,
|
||||||
toolkitComponents, clean,
|
toolkitComponents, clean,
|
||||||
progress: new BuildProgressWindow(_reporter, InstallStages.BuildBase, 5, 92)));
|
progress: new BuildProgressWindow(_reporter, InstallStages.BuildBase, 5, 92)));
|
||||||
LocalBuildService.WriteFingerprint(baseOutput, BuildProfile.Base, toolkitFingerprint,
|
LocalBuildService.WriteFingerprint(baseOutput, BuildProfile.Base, toolkitFingerprint,
|
||||||
@@ -274,7 +270,7 @@ internal sealed class ProductRepairService
|
|||||||
"Recompiling Retro Rewind for the canonical Code.pul...", 5);
|
"Recompiling Retro Rewind for the canonical Code.pul...", 5);
|
||||||
await BuildWithCleanRetryAsync(forceCleanBuild, clean =>
|
await BuildWithCleanRetryAsync(forceCleanBuild, clean =>
|
||||||
builder.BuildAsync(_installation.Root, BuildProfile.RetroRewind, retroOutput,
|
builder.BuildAsync(_installation.Root, BuildProfile.RetroRewind, retroOutput,
|
||||||
requestedPayloadMode, payloadSnapshot?.Directory, payloadGameId, cancellationToken,
|
requestedPayloadMode, payloadSnapshot?.Directory, cancellationToken,
|
||||||
toolkitComponents, clean,
|
toolkitComponents, clean,
|
||||||
progress: new BuildProgressWindow(_reporter, InstallStages.BuildRetro, 5, 92),
|
progress: new BuildProgressWindow(_reporter, InstallStages.BuildRetro, 5, 92),
|
||||||
retroRewindPackageDirectory: compileInputs.RetroRewindRoot));
|
retroRewindPackageDirectory: compileInputs.RetroRewindRoot));
|
||||||
@@ -314,8 +310,7 @@ internal sealed class ProductRepairService
|
|||||||
|
|
||||||
|
|
||||||
private RetroWfcPayloadSnapshot RecoverInstalledRetroWfcPayload(string toolkitFingerprint,
|
private RetroWfcPayloadSnapshot RecoverInstalledRetroWfcPayload(string toolkitFingerprint,
|
||||||
string gameId, string destinationDirectory, Exception downloadFailure,
|
string destinationDirectory, Exception downloadFailure, CancellationToken cancellationToken)
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
InvalidOperationException Unavailable(string reason) => new(
|
InvalidOperationException Unavailable(string reason) => new(
|
||||||
"The Retro-WFC payload service is unavailable" +
|
"The Retro-WFC payload service is unavailable" +
|
||||||
@@ -339,7 +334,7 @@ internal sealed class ProductRepairService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
cachedFile = InputValidation.ResolveRetroWfcPayloadFile(
|
cachedFile = InputValidation.ResolveRetroWfcPayloadFile(
|
||||||
_installation.WorkspaceRetroWfcPayload, gameId);
|
_installation.WorkspaceRetroWfcPayload);
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
if (new FileInfo(cachedFile).Length != fingerprint.RetroWfcPayloadLength ||
|
if (new FileInfo(cachedFile).Length != fingerprint.RetroWfcPayloadLength ||
|
||||||
!InputValidation.Sha256File(cachedFile).Equals(fingerprint.RetroWfcPayloadSha256,
|
!InputValidation.Sha256File(cachedFile).Equals(fingerprint.RetroWfcPayloadSha256,
|
||||||
@@ -348,11 +343,11 @@ internal sealed class ProductRepairService
|
|||||||
throw Unavailable("the installed payload snapshot no longer matches its recorded identity.");
|
throw Unavailable("the installed payload snapshot no longer matches its recorded identity.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var destination = Path.Combine(Path.GetFullPath(destinationDirectory),
|
var destination = Path.Combine(Path.GetFullPath(destinationDirectory), "binary",
|
||||||
RetroWfcPayload.PayloadRelativePath(gameId));
|
"payload.RMCPD00.bin");
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(destination)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(destination)!);
|
||||||
File.Copy(cachedFile, destination, overwrite: true);
|
File.Copy(cachedFile, destination, overwrite: true);
|
||||||
var root = InputValidation.ValidateStagedRetroWfcPayloadDirectory(destinationDirectory, gameId);
|
var root = InputValidation.ValidateStagedRetroWfcPayloadDirectory(destinationDirectory);
|
||||||
_reporter.Diagnostic(
|
_reporter.Diagnostic(
|
||||||
"The Retro-WFC payload service is unavailable; reusing the installation's verified " +
|
"The Retro-WFC payload service is unavailable; reusing the installation's verified " +
|
||||||
$"payload snapshot (sha256 {fingerprint.RetroWfcPayloadSha256[..12]}..., " +
|
$"payload snapshot (sha256 {fingerprint.RetroWfcPayloadSha256[..12]}..., " +
|
||||||
|
|||||||
@@ -28,9 +28,19 @@ internal static class SelfTests
|
|||||||
}
|
}
|
||||||
finally { File.Delete(path); }
|
finally { File.Delete(path); }
|
||||||
}, failures);
|
}, failures);
|
||||||
Test("Disc compatibility", TestDiscCompatibility, failures);
|
Test("Disc compatibility", () =>
|
||||||
Test("Payload manifest releases", TestPayloadManifestReleases, failures);
|
InputValidation.EnsureCompatibleDisc(new DiscHeader { GameId = "RMCP01" },
|
||||||
Test("Extracted game release validation", TestExtractedGameRelease, failures);
|
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("Payload timestamp normalization", TestPayloadTimestampNormalization, failures);
|
Test("Payload timestamp normalization", TestPayloadTimestampNormalization, failures);
|
||||||
Test("Workspace timestamp reconciliation", TestWorkspaceTimestampReconciliation, failures);
|
Test("Workspace timestamp reconciliation", TestWorkspaceTimestampReconciliation, failures);
|
||||||
Test("Toolkit accompanies the workspace", TestToolkitRefreshDecision, failures);
|
Test("Toolkit accompanies the workspace", TestToolkitRefreshDecision, failures);
|
||||||
@@ -67,152 +77,6 @@ internal static class SelfTests
|
|||||||
return failures.Count == 0 ? 0 : 1;
|
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)
|
private static void TestAcceptedExtension(string extension)
|
||||||
{
|
{
|
||||||
var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + extension);
|
var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + extension);
|
||||||
@@ -830,91 +694,42 @@ internal static class SelfTests
|
|||||||
|
|
||||||
private static void TestRetroWfcPayloadSnapshotReconciliation()
|
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";
|
const string shaB = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
|
||||||
var root = Path.Combine(Path.GetTempPath(), "mkwc-wfc-snapshot-" + Guid.NewGuid().ToString("N"));
|
var root = Path.Combine(Path.GetTempPath(), "mkwc-wfc-snapshot-" + Guid.NewGuid().ToString("N"));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var signingRsa = RSA.Create(2048);
|
InputValidation.ValidateRetroWfcPayloadUri(endpoint);
|
||||||
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
|
try
|
||||||
{
|
{
|
||||||
_ = RetroWfcPayload.PayloadUri("RMCK01");
|
InputValidation.ValidateRetroWfcPayloadUri(endpoint + "&extra=1");
|
||||||
throw new Exception("An unsupported release has a Retro-WFC endpoint.");
|
throw new Exception("A non-canonical Retro-WFC endpoint was accepted.");
|
||||||
}
|
}
|
||||||
catch (InvalidDataException) { }
|
catch (InvalidDataException) { }
|
||||||
|
|
||||||
const string gameUnderTest = "RMCE01";
|
|
||||||
var installation = new Installation(root);
|
var installation = new Installation(root);
|
||||||
Directory.CreateDirectory(installation.RetroDirectory);
|
Directory.CreateDirectory(installation.RetroDirectory);
|
||||||
var payloadRoot = Path.Combine(root, "download");
|
var payloadRoot = Path.Combine(root, "download");
|
||||||
var payloadPath = Path.Combine(payloadRoot, RetroWfcPayload.PayloadRelativePath(gameUnderTest));
|
var payloadPath = Path.Combine(payloadRoot, "binary", "payload.RMCPD00.bin");
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(payloadPath)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(payloadPath)!);
|
||||||
var bytes = SignedPayload(RetroWfcPayload.PayloadGame(gameUnderTest));
|
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));
|
||||||
File.WriteAllBytes(payloadPath, bytes);
|
File.WriteAllBytes(payloadPath, bytes);
|
||||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey);
|
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest);
|
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot);
|
||||||
throw new Exception("A payload signed by a foreign key passed the pinned production key.");
|
throw new Exception("A payload signed by a foreign key passed the pinned production key.");
|
||||||
}
|
}
|
||||||
catch (InvalidDataException) { }
|
catch (InvalidDataException) { }
|
||||||
var shaA = InputValidation.ComputeRetroWfcPayloadSha256(payloadRoot, gameUnderTest, signingKey);
|
var shaA = InputValidation.ComputeRetroWfcPayloadSha256(payloadRoot, signingKey);
|
||||||
var snapshot = new RetroWfcPayloadSnapshot(payloadRoot, shaA, bytes.Length);
|
var snapshot = new RetroWfcPayloadSnapshot(payloadRoot, shaA, bytes.Length);
|
||||||
JsonState.Write(Path.Combine(installation.RetroDirectory, ProductFingerprint.FileName),
|
JsonState.Write(Path.Combine(installation.RetroDirectory, ProductFingerprint.FileName),
|
||||||
new ProductFingerprint
|
new ProductFingerprint
|
||||||
@@ -949,7 +764,7 @@ internal static class SelfTests
|
|||||||
File.WriteAllBytes(payloadPath, bytes);
|
File.WriteAllBytes(payloadPath, bytes);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey);
|
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey);
|
||||||
throw new Exception("A payload with a malformed declared length was accepted.");
|
throw new Exception("A payload with a malformed declared length was accepted.");
|
||||||
}
|
}
|
||||||
catch (InvalidDataException) { }
|
catch (InvalidDataException) { }
|
||||||
@@ -959,7 +774,7 @@ internal static class SelfTests
|
|||||||
File.WriteAllBytes(payloadPath, bytes);
|
File.WriteAllBytes(payloadPath, bytes);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey);
|
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey);
|
||||||
throw new Exception("A payload with tampered signed content was accepted.");
|
throw new Exception("A payload with tampered signed content was accepted.");
|
||||||
}
|
}
|
||||||
catch (InvalidDataException) { }
|
catch (InvalidDataException) { }
|
||||||
@@ -969,7 +784,7 @@ internal static class SelfTests
|
|||||||
File.WriteAllBytes(payloadPath, bytes);
|
File.WriteAllBytes(payloadPath, bytes);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey);
|
_ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey);
|
||||||
throw new Exception("A payload with a malformed header was accepted.");
|
throw new Exception("A payload with a malformed header was accepted.");
|
||||||
}
|
}
|
||||||
catch (InvalidDataException) { }
|
catch (InvalidDataException) { }
|
||||||
@@ -1446,8 +1261,7 @@ internal static class SelfTests
|
|||||||
Directory.CreateDirectory(Path.Combine(root, "Toolkit", "CMake", "bin"));
|
Directory.CreateDirectory(Path.Combine(root, "Toolkit", "CMake", "bin"));
|
||||||
Directory.CreateDirectory(Path.Combine(root, "Toolkit", "Ninja"));
|
Directory.CreateDirectory(Path.Combine(root, "Toolkit", "Ninja"));
|
||||||
Directory.CreateDirectory(Path.Combine(root, "Toolkit", "llvm-mingw", "bin"));
|
Directory.CreateDirectory(Path.Combine(root, "Toolkit", "llvm-mingw", "bin"));
|
||||||
foreach (var project in new[] { "mkwii", "mkwii-ntsc-u", "mkwii-ntsc-j" })
|
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "projects", "mkwii"));
|
||||||
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "projects", project));
|
|
||||||
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "runtime", "src"));
|
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "runtime", "src"));
|
||||||
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "runtime", "assets", "wii", "shared2",
|
Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "runtime", "assets", "wii", "shared2",
|
||||||
"wc24"));
|
"wc24"));
|
||||||
@@ -1474,8 +1288,7 @@ internal static class SelfTests
|
|||||||
File.WriteAllText(Path.Combine(root, "Toolkit", "nodtool.exe"), "tool");
|
File.WriteAllText(Path.Combine(root, "Toolkit", "nodtool.exe"), "tool");
|
||||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "LocalBuild.ps1"), "# build");
|
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "LocalBuild.ps1"), "# build");
|
||||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "NativeBuildFlags.ps1"), "# flags");
|
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "NativeBuildFlags.ps1"), "# flags");
|
||||||
foreach (var project in new[] { "mkwii", "mkwii-ntsc-u", "mkwii-ntsc-j" })
|
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "projects", "mkwii", "recomp.yml"), "profiles: {}");
|
||||||
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", "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", "src", "main.cpp"), "int main();");
|
||||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "runtime", "assets", "wii", "shared2", "wc24",
|
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.
|
// 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;
|
// 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.
|
// v3 replaced it with the native index extracted from it, whenever that index is current.
|
||||||
private const string Version = "mkwc-toolkit-compile-v7";
|
private const string Version = "mkwc-toolkit-compile-v6";
|
||||||
private const string TranslationVersion = "mkwc-toolkit-translation-v4";
|
private const string TranslationVersion = "mkwc-toolkit-translation-v3";
|
||||||
private const string NativeToolchainVersion = "mkwc-toolkit-native-toolchain-v2";
|
private const string NativeToolchainVersion = "mkwc-toolkit-native-toolchain-v2";
|
||||||
private const string PackageVersion = "mkwc-toolkit-package-v1";
|
private const string PackageVersion = "mkwc-toolkit-package-v1";
|
||||||
private const string RuntimeAssetsVersion = "mkwc-product-runtime-assets-v3";
|
private const string RuntimeAssetsVersion = "mkwc-product-runtime-assets-v3";
|
||||||
private const string RuntimeAssetsDescription = "The product runtime assets";
|
private const string RuntimeAssetsDescription = "The product runtime assets";
|
||||||
|
|
||||||
private static readonly string[] SourceExtensions =
|
private static readonly string[] SourceExtensions =
|
||||||
[".c", ".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".inl", ".inc", ".s", ".asm",
|
[".c", ".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".inl", ".s", ".asm",
|
||||||
".cmake", ".txt", ".yml", ".yaml", ".toml", ".json", ".ps1", ".in", ".def", ".patch"];
|
".cmake", ".txt", ".yml", ".yaml", ".toml", ".json", ".ps1", ".in", ".def", ".patch"];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -40,11 +40,7 @@ internal static class ToolkitFingerprint
|
|||||||
];
|
];
|
||||||
|
|
||||||
private static readonly string[] TranslationFiles =
|
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_versions.inc"
|
|
||||||
];
|
|
||||||
|
|
||||||
private const string NativeSourcePrefix = InstalledLayout.WorkspaceEntryPrefix + "runtime/src/";
|
private const string NativeSourcePrefix = InstalledLayout.WorkspaceEntryPrefix + "runtime/src/";
|
||||||
private const string NativeIndexEntry = InstalledLayout.WorkspaceEntryPrefix + "runtime/native-index.json";
|
private const string NativeIndexEntry = InstalledLayout.WorkspaceEntryPrefix + "runtime/native-index.json";
|
||||||
|
|||||||
@@ -169,8 +169,6 @@ echo "Staging the bundled workspace snapshot..."
|
|||||||
for dir in runtime aurora-main projects; do
|
for dir in runtime aurora-main projects; do
|
||||||
cp -r "$workspace/$dir" "$appdir/workspace/$dir"
|
cp -r "$workspace/$dir" "$appdir/workspace/$dir"
|
||||||
done
|
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
|
# 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*
|
# 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
|
# a developer's local checkout accumulated under extern/ is stale/large build output, not a
|
||||||
@@ -184,7 +182,7 @@ cp "$workspace/Launcher/local-build.sh" "$workspace/Launcher/build-cache.sh" "$a
|
|||||||
# index, so it is extracted from exactly the bundled runtime sources.
|
# index, so it is extracted from exactly the bundled runtime sources.
|
||||||
echo "Extracting the runtime native index..."
|
echo "Extracting the runtime native index..."
|
||||||
"$appdir/usr/bin/translator-cli" emit-native-index \
|
"$appdir/usr/bin/translator-cli" emit-native-index \
|
||||||
--native-source-dir "$appdir/workspace/runtime/src" \
|
--project "$appdir/workspace/projects/mkwii/recomp.yml" \
|
||||||
--out "$appdir/workspace/runtime/native-index.json"
|
--out "$appdir/workspace/runtime/native-index.json"
|
||||||
[[ -f "$appdir/workspace/runtime/native-index.json" ]] || { echo "build-appimage.sh: the native index was not written" >&2; exit 1; }
|
[[ -f "$appdir/workspace/runtime/native-index.json" ]] || { echo "build-appimage.sh: the native index was not written" >&2; exit 1; }
|
||||||
|
|
||||||
|
|||||||
+2
-65
@@ -1,6 +1,5 @@
|
|||||||
# Shared incremental-build and release-selection logic for the Unix setups (Linux AppImage and
|
# Shared incremental-build logic for the Unix setups (Linux AppImage and macOS), sourced by
|
||||||
# macOS), sourced by local-build.sh, local-build-macos.command, macos/extract-disc.command, the
|
# local-build.sh, local-build-macos.command, the AppImage's AppRun and macos/setup.command.
|
||||||
# AppImage's AppRun and macos/setup.command.
|
|
||||||
# Mirrors the Windows installer's translation/toolchain identities and timestamp preservation.
|
# Mirrors the Windows installer's translation/toolchain identities and timestamp preservation.
|
||||||
# Must stay compatible with macOS's bash 3.2.
|
# Must stay compatible with macOS's bash 3.2.
|
||||||
|
|
||||||
@@ -77,7 +76,6 @@ mkw_translation_identity() {
|
|||||||
printf 'rel %s\n' "$(mkw_digest_path "$workspace/Assets/StaticR.rel")"
|
printf 'rel %s\n' "$(mkw_digest_path "$workspace/Assets/StaticR.rel")"
|
||||||
printf 'translator %s\n' "$(mkw_digest_path "$translator")"
|
printf 'translator %s\n' "$(mkw_digest_path "$translator")"
|
||||||
printf 'script %s\n' "$(mkw_digest_path "$script")"
|
printf 'script %s\n' "$(mkw_digest_path "$script")"
|
||||||
printf 'regions %s\n' "$(mkw_digest_path "$workspace/runtime/include/guest_abi/guest_versions.inc")"
|
|
||||||
mkw_digest_tree "$workspace" projects
|
mkw_digest_tree "$workspace" projects
|
||||||
mkw_native_index_identity "$workspace"
|
mkw_native_index_identity "$workspace"
|
||||||
} | mkw_sha256
|
} | mkw_sha256
|
||||||
@@ -101,67 +99,6 @@ mkw_toolchain_identity() {
|
|||||||
} | mkw_sha256
|
} | 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.
|
# $1 = JSON file, $2 = key. Prints the recorded string value, or nothing.
|
||||||
mkw_read_identity() {
|
mkw_read_identity() {
|
||||||
[[ -f "$1" ]] || return 0
|
[[ -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)
|
--profile {base|retro-rewind|both} Product to build (default: base)
|
||||||
--output-dir DIR Output .app directory (required; Retro Rewind for both)
|
--output-dir DIR Output .app directory (required; Retro Rewind for both)
|
||||||
--base-output-dir DIR Base .app directory (required with --profile both)
|
--base-output-dir DIR Base .app directory (required with --profile both)
|
||||||
--game IMAGE --nodtool PATH Extract and verify a clean supported disc image first
|
--game IMAGE --nodtool PATH Extract and verify a clean PAL RMCP01 disc image first
|
||||||
--retro-rewind-package-dir DIR RetroRewind6 directory (required for Retro Rewind)
|
--retro-rewind-package-dir DIR RetroRewind6 directory (required for Retro Rewind)
|
||||||
--retro-wfc-offline-dir DIR Directory containing the release's binary/payload.<game>.bin
|
--retro-wfc-offline-dir DIR Directory containing binary/payload.RMCPD00.bin
|
||||||
--skip-retro-wfc-payload Build Retro Rewind without the shared Retro-WFC payload
|
--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
|
--force-clean-build Delete local generated and current-architecture native build caches
|
||||||
--parallel N Pin translation and build parallelism
|
--parallel N Pin translation and build parallelism
|
||||||
@@ -82,15 +82,13 @@ if (( builds_retro )); then
|
|||||||
fi
|
fi
|
||||||
for tool in "$cmake_bin" "$ninja_bin" clang clang++ shasum; do command -v "$tool" >/dev/null || fail "required tool not found: $tool"; done
|
for tool in "$cmake_bin" "$ninja_bin" clang clang++ shasum; do command -v "$tool" >/dev/null || fail "required tool not found: $tool"; done
|
||||||
|
|
||||||
assets="$workspace/Assets"; generated="$workspace/generated"
|
project="$workspace/projects/mkwii/recomp.yml"; assets="$workspace/Assets"; generated="$workspace/generated"
|
||||||
functions="$generated/functions"; metadata="$generated/base_translation_output.json"; manifest_dir="$workspace/build/base"
|
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"
|
manifest="$manifest_dir/mkwii_base_manifest.json"; shards="$generated/build_shards"
|
||||||
native_build="$workspace/native-build-macos-$macos_arch"
|
native_build="$workspace/native-build-macos-$macos_arch"
|
||||||
if [[ -n "$game" ]]; then "$script_dir/macos/extract-disc.command" --workspace "$workspace" --game "$game" --assets-dir "$assets" --nodtool "$nodtool"; fi
|
assert_file "$project" 'translation project'
|
||||||
|
if [[ -n "$game" ]]; then "$script_dir/macos/extract-disc.command" --game "$game" --assets-dir "$assets" --nodtool "$nodtool"; fi
|
||||||
assert_file "$assets/main.dol" 'extracted main.dol'; assert_file "$assets/StaticR.rel" 'extracted StaticR.rel'
|
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
|
if (( force_clean )); then
|
||||||
step force-clean 'Discarding translation and native build caches'
|
step force-clean 'Discarding translation and native build caches'
|
||||||
@@ -150,12 +148,12 @@ else
|
|||||||
step translate-base 'Translating the user-owned base game'
|
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"
|
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'
|
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 "$region"
|
translator emit-base-manifest --project "$project" --out "$manifest_dir" --functions-dir "$functions" --translation-output-metadata "$metadata" --region P
|
||||||
mkw_write_identity "$translation_provenance" TranslationFingerprint "$translation_fingerprint"
|
mkw_write_identity "$translation_provenance" TranslationFingerprint "$translation_fingerprint"
|
||||||
fi
|
fi
|
||||||
if (( builds_retro )); then
|
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 "$region" --out "$mod_out" --prefer-cached-inputs --emit-cpp --threads "$translator_threads")
|
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 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
|
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
|
||||||
step translate-mod 'Translating Retro Rewind'; translator "${args[@]}"
|
step translate-mod 'Translating Retro Rewind'; translator "${args[@]}"
|
||||||
fi
|
fi
|
||||||
step generate-data-init 'Generating local game data initialization'; translator generate-data-init --project "$project"
|
step generate-data-init 'Generating local game data initialization'; translator generate-data-init --project "$project"
|
||||||
|
|||||||
+6
-34
@@ -69,7 +69,6 @@ fuse_ld_override=""
|
|||||||
native_prebuilt_dir=""
|
native_prebuilt_dir=""
|
||||||
sysroot=""
|
sysroot=""
|
||||||
setup_version=""
|
setup_version=""
|
||||||
x86_cpu_profile=auto
|
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
@@ -96,8 +95,6 @@ Usage: local-build.sh --output-dir DIR [options]
|
|||||||
standard headers/startup files
|
standard headers/startup files
|
||||||
--setup-version VERSION Version recorded in the runtime log (default: <Version> in
|
--setup-version VERSION Version recorded in the runtime log (default: <Version> in
|
||||||
Launcher/Directory.Build.props when present)
|
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
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +120,6 @@ while [[ $# -gt 0 ]]; do
|
|||||||
--native-prebuilt-dir) native_prebuilt_dir=$2; shift 2 ;;
|
--native-prebuilt-dir) native_prebuilt_dir=$2; shift 2 ;;
|
||||||
--sysroot) sysroot=$2; shift 2 ;;
|
--sysroot) sysroot=$2; shift 2 ;;
|
||||||
--setup-version) setup_version=$2; shift 2 ;;
|
--setup-version) setup_version=$2; shift 2 ;;
|
||||||
--x86-cpu-profile) x86_cpu_profile=$2; shift 2 ;;
|
|
||||||
-h|--help) usage; exit 0 ;;
|
-h|--help) usage; exit 0 ;;
|
||||||
*) fail "unknown argument: $1" ;;
|
*) fail "unknown argument: $1" ;;
|
||||||
esac
|
esac
|
||||||
@@ -139,10 +135,6 @@ case "$profile" in
|
|||||||
base|retro-rewind|both) ;;
|
base|retro-rewind|both) ;;
|
||||||
*) fail "--profile must be base, retro-rewind, or both" ;;
|
*) fail "--profile must be base, retro-rewind, or both" ;;
|
||||||
esac
|
esac
|
||||||
case "$x86_cpu_profile" in
|
|
||||||
auto|v2|v3) ;;
|
|
||||||
*) fail "--x86-cpu-profile must be auto, v2, or v3" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
builds_retro=0
|
builds_retro=0
|
||||||
[[ "$profile" == "retro-rewind" || "$profile" == "both" ]] && builds_retro=1
|
[[ "$profile" == "retro-rewind" || "$profile" == "both" ]] && builds_retro=1
|
||||||
@@ -192,22 +184,7 @@ if [[ -n "$native_prebuilt_dir" ]]; then
|
|||||||
assert_file "$native_prebuilt_dir/native_prebuilt.cmake" "Native prebuilt package"
|
assert_file "$native_prebuilt_dir/native_prebuilt.cmake" "Native prebuilt package"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
host_supports_x86_64_v3() {
|
project=$workspace/projects/mkwii/recomp.yml
|
||||||
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
|
assets=$workspace/Assets
|
||||||
generated=$workspace/generated
|
generated=$workspace/generated
|
||||||
functions=$generated/functions
|
functions=$generated/functions
|
||||||
@@ -220,12 +197,9 @@ translation_provenance=$generated/translation-provenance.json
|
|||||||
toolchain_provenance=$build/toolchain-provenance.json
|
toolchain_provenance=$build/toolchain-provenance.json
|
||||||
retro_root=${retro_rewind_package_dir:-$workspace/PulsarPacks/completed/RetroRewind/RetroRewind6}
|
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/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)"
|
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
|
# 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
|
# still come from the host. Check them before the expensive translation so a missing
|
||||||
@@ -364,7 +338,7 @@ else
|
|||||||
|
|
||||||
log_step emit-base-manifest "Creating the local base translation manifest"
|
log_step emit-base-manifest "Creating the local base translation manifest"
|
||||||
translator emit-base-manifest --project "$project" --out "$base_manifest_dir" \
|
translator emit-base-manifest --project "$project" --out "$base_manifest_dir" \
|
||||||
--functions-dir "$functions" --translation-output-metadata "$base_metadata" --region "$region"
|
--functions-dir "$functions" --translation-output-metadata "$base_metadata" --region P
|
||||||
|
|
||||||
mkw_write_identity "$translation_provenance" TranslationFingerprint "$translation_fingerprint"
|
mkw_write_identity "$translation_provenance" TranslationFingerprint "$translation_fingerprint"
|
||||||
fi
|
fi
|
||||||
@@ -376,13 +350,12 @@ if (( builds_retro )); then
|
|||||||
translate_mod_args=(translate-mod --project "$project" --profile retro-rewind
|
translate_mod_args=(translate-mod --project "$project" --profile retro-rewind
|
||||||
--base-manifest "$base_manifest" --base-translation-output-metadata "$base_metadata"
|
--base-manifest "$base_manifest" --base-translation-output-metadata "$base_metadata"
|
||||||
--code-pul "$code_pul" --mod-root "$retro_root" --mod-name "Retro Rewind"
|
--code-pul "$code_pul" --mod-root "$retro_root" --mod-name "Retro Rewind"
|
||||||
--region "$region" --out "$retro_out" --prefer-cached-inputs --emit-cpp
|
--region P --out "$retro_out" --prefer-cached-inputs --emit-cpp
|
||||||
--threads "$translator_threads")
|
--threads "$translator_threads")
|
||||||
if (( skip_retro_wfc_payload )); then
|
if (( skip_retro_wfc_payload )); then
|
||||||
translate_mod_args+=(--skip-retro-wfc)
|
translate_mod_args+=(--skip-retro-wfc)
|
||||||
else
|
else
|
||||||
payload_file=$(mkw_retro_wfc_payload_file "$project") || fail "$project pins no Retro-WFC payload"
|
offline_payload=$retro_wfc_offline_dir/binary/payload.RMCPD00.bin
|
||||||
offline_payload=$retro_wfc_offline_dir/$payload_file
|
|
||||||
assert_file "$offline_payload" "Offline Retro-WFC shared payload"
|
assert_file "$offline_payload" "Offline Retro-WFC shared payload"
|
||||||
translate_mod_args+=(--retro-wfc-payload "$offline_payload")
|
translate_mod_args+=(--retro-wfc-payload "$offline_payload")
|
||||||
fi
|
fi
|
||||||
@@ -461,8 +434,7 @@ configure_args=(-S "$workspace/runtime" -B "$build" -G Ninja
|
|||||||
-DCMAKE_C_COMPILER="$cc_bin" -DCMAKE_CXX_COMPILER="$cxx_bin"
|
-DCMAKE_C_COMPILER="$cc_bin" -DCMAKE_CXX_COMPILER="$cxx_bin"
|
||||||
-DCMAKE_MAKE_PROGRAM="$ninja_bin"
|
-DCMAKE_MAKE_PROGRAM="$ninja_bin"
|
||||||
-DMKW_TRANSLATED_COMPILE_JOBS="$translated_jobs"
|
-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
|
# 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
|
# 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
|
# current mount every launch - see build-appimage.sh). CMAKE_AR/RANLIB/LINKER/ASM_COMPILER do NOT
|
||||||
|
|||||||
@@ -148,16 +148,12 @@ copy_clean "$script_dir/setup.command" "$resources/setup.command"; chmod +x "$re
|
|||||||
mkdir -p "$resources/workspace"
|
mkdir -p "$resources/workspace"
|
||||||
for source in aurora-main projects runtime translator; do
|
for source in aurora-main projects runtime translator; do
|
||||||
[[ -d "$workspace/$source" ]] || fail "required workspace directory is missing: $source"
|
[[ -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"
|
copy_clean "$workspace/$source" "$resources/workspace/$source"
|
||||||
done
|
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
|
# 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.
|
# 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
|
if [[ "$host_arch" == arm64 ]]; then host_translator=$translator_arm64; else host_translator=$translator_x86_64; fi
|
||||||
"$host_translator" emit-native-index --native-source-dir "$resources/workspace/runtime/src" \
|
"$host_translator" emit-native-index --project "$resources/workspace/projects/mkwii/recomp.yml" \
|
||||||
--out "$resources/workspace/runtime/native-index.json" || fail 'the runtime native index could not be extracted'
|
--out "$resources/workspace/runtime/native-index.json" || fail 'the runtime native index could not be extracted'
|
||||||
[[ -f "$resources/workspace/runtime/native-index.json" ]] || fail 'the runtime native index was not written'
|
[[ -f "$resources/workspace/runtime/native-index.json" ]] || fail 'the runtime native index was not written'
|
||||||
mkdir -p "$resources/workspace/Launcher/macos"
|
mkdir -p "$resources/workspace/Launcher/macos"
|
||||||
|
|||||||
@@ -1,35 +1,30 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Extract a user-owned Mario Kart Wii disc image of a supported release for a local build.
|
# Extract a user-owned Mario Kart Wii PAL (RMCP01) disc image for a local build.
|
||||||
# This script deliberately contains no game data and is intended for the macOS
|
# This script deliberately contains no game data and is intended for the macOS
|
||||||
# setup application and for maintainers testing that setup path.
|
# setup application and for maintainers testing that setup path.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
readonly EXPECTED_DOL_SHA256=80d18895b39c63bd80f457398bfcbb91b7d16ac116a41a88967e954080155b05
|
||||||
# shellcheck source=../build-cache.sh
|
readonly EXPECTED_REL_SHA256=16d9d146112541fefea701ecb5bc1a496f9d50e4a752fbb5b6778e7c6399f67d
|
||||||
source "$script_dir/../build-cache.sh"
|
|
||||||
|
|
||||||
fail() { printf 'extract-disc.command: error: %s\n' "$*" >&2; exit 1; }
|
fail() { printf 'extract-disc.command: error: %s\n' "$*" >&2; exit 1; }
|
||||||
sha256() { shasum -a 256 "$1" | awk '{ print $1 }'; }
|
sha256() { shasum -a 256 "$1" | awk '{ print $1 }'; }
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
Usage: extract-disc.command --game IMAGE --assets-dir DIR --nodtool PATH [--workspace DIR]
|
Usage: extract-disc.command --game IMAGE --assets-dir DIR --nodtool PATH
|
||||||
|
|
||||||
Extracts a user-owned Mario Kart Wii image into DIR. The image must be a release
|
Extracts a user-owned Mario Kart Wii PAL RMCP01 image into DIR. The final
|
||||||
a projects/*/recomp.yml in the workspace (default: this script's repository)
|
layout is DIR/main.dol, DIR/StaticR.rel, and DIR/DATA. Existing data is left
|
||||||
pins. The final layout is DIR/main.dol, DIR/StaticR.rel, and DIR/DATA. Existing
|
untouched unless the complete new extraction passes both content hash checks.
|
||||||
data is left untouched unless the complete new extraction passes both content
|
|
||||||
hash checks.
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
game=""
|
game=""
|
||||||
assets_dir=""
|
assets_dir=""
|
||||||
nodtool=""
|
nodtool=""
|
||||||
workspace=$(cd "$script_dir/../.." && pwd)
|
|
||||||
while (($#)); do
|
while (($#)); do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--workspace) workspace=${2:-}; shift 2 ;;
|
|
||||||
--game) game=${2:-}; shift 2 ;;
|
--game) game=${2:-}; shift 2 ;;
|
||||||
--assets-dir) assets_dir=${2:-}; shift 2 ;;
|
--assets-dir) assets_dir=${2:-}; shift 2 ;;
|
||||||
--nodtool) nodtool=${2:-}; shift 2 ;;
|
--nodtool) nodtool=${2:-}; shift 2 ;;
|
||||||
@@ -44,21 +39,11 @@ done
|
|||||||
|
|
||||||
assets_dir=$(mkdir -p "$assets_dir" && cd "$assets_dir" && pwd)
|
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.
|
# 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'); }
|
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" ]] && \
|
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
|
[[ "$(data_manifest "$assets_dir/DATA")" == "$(cat "$assets_dir/.data-manifest")" ]]; then
|
||||||
printf 'MKWCBUILD:STEP:disc-ready Reusing the verified extracted game assets\n'
|
printf 'MKWCBUILD:STEP:disc-ready Reusing the verified extracted game assets\n'
|
||||||
exit 0
|
exit 0
|
||||||
@@ -67,6 +52,8 @@ scratch=$(mktemp -d "${TMPDIR:-/tmp}/wiicompiled-disc.XXXXXX")
|
|||||||
cleanup() { rm -rf "$scratch"; }
|
cleanup() { rm -rf "$scratch"; }
|
||||||
trap cleanup EXIT
|
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'
|
printf 'MKWCBUILD:STEP:extract-disc Extracting the user-owned disc image\n'
|
||||||
"$nodtool" extract "$game" "$scratch/extracted"
|
"$nodtool" extract "$game" "$scratch/extracted"
|
||||||
|
|
||||||
@@ -76,8 +63,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'
|
[[ -n "$rel" ]] || fail 'nodtool extraction did not contain files/rel/StaticR.rel'
|
||||||
dol_sha=$(sha256 "$dol")
|
dol_sha=$(sha256 "$dol")
|
||||||
rel_sha=$(sha256 "$rel")
|
rel_sha=$(sha256 "$rel")
|
||||||
[[ $dol_sha == "$expected_dol_sha256" ]] || fail "main.dol does not match the clean $game_id image (expected $expected_dol_sha256, got $dol_sha)"
|
[[ $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 $game_id image (expected $expected_rel_sha256, got $rel_sha)"
|
[[ $rel_sha == "$EXPECTED_REL_SHA256" ]] || fail "StaticR.rel does not match the clean PAL RMCP01 image (expected $EXPECTED_REL_SHA256, got $rel_sha)"
|
||||||
|
|
||||||
data_root=$(dirname "$(dirname "$dol")")
|
data_root=$(dirname "$(dirname "$dol")")
|
||||||
[[ -d "$data_root/files" ]] || fail 'nodtool extraction did not contain the Wii files directory'
|
[[ -d "$data_root/files" ]] || fail 'nodtool extraction did not contain the Wii files directory'
|
||||||
@@ -105,4 +92,4 @@ mv "$stage/StaticR.rel" "$assets_dir/StaticR.rel"
|
|||||||
rmdir "$stage"
|
rmdir "$stage"
|
||||||
rm -rf "$backup"
|
rm -rf "$backup"
|
||||||
|
|
||||||
printf 'MKWCBUILD:STEP:disc-ready Verified and extracted clean %s game assets\n' "$game_id"
|
printf 'MKWCBUILD:STEP:disc-ready Verified and extracted clean PAL RMCP01 game assets\n'
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ ninja_bin="$host_tools/ninja"
|
|||||||
|
|
||||||
if [[ -z "$game" ]]; then
|
if [[ -z "$game" ]]; then
|
||||||
game=$(/usr/bin/osascript <<'APPLESCRIPT'
|
game=$(/usr/bin/osascript <<'APPLESCRIPT'
|
||||||
set selectedFile to choose file with prompt "Choose your clean Mario Kart Wii disc image"
|
set selectedFile to choose file with prompt "Choose your clean Mario Kart Wii PAL (RMCP01) disc image"
|
||||||
POSIX path of selectedFile
|
POSIX path of selectedFile
|
||||||
APPLESCRIPT
|
APPLESCRIPT
|
||||||
) || exit 0
|
) || exit 0
|
||||||
@@ -100,28 +100,18 @@ if (( needs_workspace_refresh )); then
|
|||||||
fi
|
fi
|
||||||
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
|
profile=base
|
||||||
build_args=(--workspace "$workspace" --output-dir "$products")
|
build_args=(--workspace "$workspace" --game "$game" --nodtool "$nodtool" --output-dir "$products")
|
||||||
if [[ -n "$retro_dir" ]]; then
|
if [[ -n "$retro_dir" ]]; then
|
||||||
profile=both
|
profile=both
|
||||||
# Online play needs the shared Retro-WFC payload. Keep it in the per-user
|
# 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
|
# support directory rather than the packaged app or build workspace, then
|
||||||
# verify its pinned signature before publishing it into the local cache.
|
# 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_dir="$support_root/RetroWfcPayload"
|
||||||
retro_wfc_payload="$retro_wfc_dir/$payload_file"
|
retro_wfc_payload="$retro_wfc_dir/binary/payload.RMCPD00.bin"
|
||||||
cached_payload_valid=0
|
cached_payload_valid=0
|
||||||
if [[ -f "$retro_wfc_payload" ]]; then
|
if [[ -f "$retro_wfc_payload" ]]; then
|
||||||
if "$translator" validate-retro-wfc-payload --directory "$retro_wfc_dir" --game-id "$game_id"; then
|
if "$translator" validate-retro-wfc-payload --directory "$retro_wfc_dir"; then
|
||||||
cached_payload_valid=1
|
cached_payload_valid=1
|
||||||
else
|
else
|
||||||
printf 'Discarding an invalid cached Retro-WFC payload...\n' >&2
|
printf 'Discarding an invalid cached Retro-WFC payload...\n' >&2
|
||||||
@@ -135,14 +125,15 @@ if [[ -n "$retro_dir" ]]; then
|
|||||||
printf 'Downloading the current Retro-WFC payload needed for online play...\n'
|
printf 'Downloading the current Retro-WFC payload needed for online play...\n'
|
||||||
mkdir -p "$retro_wfc_dir"
|
mkdir -p "$retro_wfc_dir"
|
||||||
payload_stage=$(mktemp -d "$retro_wfc_dir/.payload-download.XXXXXX")
|
payload_stage=$(mktemp -d "$retro_wfc_dir/.payload-download.XXXXXX")
|
||||||
temporary_payload="$payload_stage/$payload_file"
|
temporary_payload="$payload_stage/binary/payload.RMCPD00.bin"
|
||||||
mkdir -p "$(dirname "$temporary_payload")"
|
mkdir -p "$(dirname "$temporary_payload")"
|
||||||
trap 'rm -rf "$payload_stage"' EXIT
|
trap 'rm -rf "$payload_stage"' EXIT
|
||||||
if /usr/bin/curl --fail --silent --show-error --connect-timeout 10 --max-time 30 \
|
if /usr/bin/curl --fail --silent --show-error --connect-timeout 10 --max-time 30 \
|
||||||
--retry 1 --output "$temporary_payload" "$payload_uri"; then
|
--retry 1 --output "$temporary_payload" \
|
||||||
"$translator" validate-retro-wfc-payload --directory "$payload_stage" --game-id "$game_id" || \
|
'https://rwfc.net/api/wfc/payload?g=RMCPD00'; then
|
||||||
|
"$translator" validate-retro-wfc-payload --directory "$payload_stage" || \
|
||||||
fail 'downloaded Retro-WFC payload failed signature validation'
|
fail 'downloaded Retro-WFC payload failed signature validation'
|
||||||
mkdir -p "$(dirname "$retro_wfc_payload")"
|
mkdir -p "$retro_wfc_dir/binary"
|
||||||
mv "$temporary_payload" "$retro_wfc_payload"
|
mv "$temporary_payload" "$retro_wfc_payload"
|
||||||
rmdir "$payload_stage/binary" "$payload_stage"
|
rmdir "$payload_stage/binary" "$payload_stage"
|
||||||
trap - EXIT
|
trap - EXIT
|
||||||
|
|||||||
-1
Submodule aurora-main deleted from ff0b617a92
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
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
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
.buildcache/
|
||||||
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
.cache/
|
||||||
|
.vscode/
|
||||||
|
.vs/
|
||||||
|
build/
|
||||||
|
cmake-build-*/
|
||||||
|
CMakeUserPresets.json
|
||||||
|
out/
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
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 ()
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
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.
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<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.
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,57 @@
|
|||||||
|
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()
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
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 ()
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# 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)
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
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 ()
|
||||||
@@ -0,0 +1,385 @@
|
|||||||
|
# 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));
|
||||||
|
|
||||||
|
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 ()
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
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 ()
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
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 ()
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
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})
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/* 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)))
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# 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
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
if (AURORA_ENABLE_GX)
|
||||||
|
add_executable(simple simple.c)
|
||||||
|
target_link_libraries(simple PRIVATE aurora::core aurora::gx aurora::main aurora::vi)
|
||||||
|
endif ()
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#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
@@ -0,0 +1,360 @@
|
|||||||
|
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 ()
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#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);
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,542 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,340 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#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_
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,525 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#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_ */
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#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 */
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#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 */
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user