Superman Returns Recomp

Superman Returns Recomp is a native PC port of Superman Returns for Windows that allows playing the game with Direct3D 12 or Vulkan.

README

Superman Returns Recomp

Projeto experimental de recompilação estática da versão Xbox 360 de Superman Returns para PC com ReXGlue v0.10.0. O código-fonte C++ é gerado localmente a partir do default.xex fornecido pelo usuário. O renderer nativo já chega à gameplay (ainda sem validação completa de imagem e de todas as fases), então o projeto está em estágio experimental, não finalizado.

Versão analisada

  • Xbox 360 Title ID: 454107ED; Media ID: 64A4002A; versão do XEX: 0.0.0.1.
  • SHA-256 de default.xex: C8F243ACD99DE9A91F5AE4F409721C0E954E3D5EB96861419D3DA07B8106DB2B.
  • A ISO contém default.xex e 12 arquivos .AST em DATA/. Os arquivos do jogo ficam em game/, ignorados pelo Git.

Estado atual

O objetivo do projeto é um renderizador nativo próprio (sr_renderer=native, o padrão), com dois backends: Direct3D 12 e Vulkan (--sr_native_api=d3d12|vulkan). Ele intercepta as chamadas Direct3D do XDK e desenha direto na GPU do PC, sem emular a GPU Xenos do Xbox 360. O jogo compila, chega à gameplay com áudio, e o renderer nativo desenha a cidade, o Superman, o HUD e o minimapa. A imagem ainda não está validada em todas as fases, então o projeto continua experimental.

O backend Xenos (a emulação da GPU herdada do Xenia, plugin xenos) continua disponível só como compatibilidade, quando escolhido explicitamente (--sr_renderer=xenos ou "Xenos (compatibilidade)" no launcher). Opções desse backend, como render_target_path_d3d12 (RTV/ROV), não afetam o renderer nativo.

Marcos recentes:

  • 2026-10-05: backend Vulkan; correção da queda silenciosa para o Xenos quando o launcher mandava uma GPU em branco (o nativo nunca mais troca de backend sozinho).
  • 2026-10-27/28: limite interno de 30 Hz removido do padrão, correção da música que parava após a decolagem (último bloco do XMA), otimizações de CPU no D3D12 nativo, benchmark embutido e binds de Shift/Ctrl/Alt sozinhos no teclado.
  • 2026-10-29: trajes (Golden Age sem desbloquear e a skin Reino do Amanhã) e dump e troca de texturas.

Histórico e validações: gameplay nativa, Vulkan, pistas de desempenho de 28/10.

Correções específicas do jogo
  • Travamento do áudio / crash após 1–2 min em cenas 3D (port/src/xma_fixes.cpp): o mixer de áudio fica em espera ativa pelo decodificador XMA sem timeout. Sob a emulação de XMA do runtime alguns contextos nunca entregam amostras (contexto já liberado, ou buffer de saída marcado cheio), a thread de áudio travava, a fila de comandos de 1 MB (sub_8264C540) parava de ser esvaziada e transbordava sobre o heap. Um hook midasm em 0x826595B8 reativa o contexto e, se ele estiver liberado, se o kick não mudar nada (sem entrada ou buffer de saída cheio) ou se não entregar em 1 ms, faz o mixer seguir para o próximo stream.
  • Som engasgando quando o Jor-El começa a falar (mesmo hook): o XMAEnableContext do runtime decodifica na hora, então um contexto sem dados de entrada (a voz do Jor-El vem em stream do disco) não vai entregar nada enquanto o mixer espera. A versão anterior do hook esperava até 4 ms por stream em todo passe do mixer; com a voz dividida em vários contextos isso passava de um quadro de áudio (5,3 ms), o mixer ficava atrás do tempo real e só o som engasgava. Agora o hook desiste assim que um kick não faz progresso.

As dicas de limites de função estão em port/superman_returns_manifest.toml. A maior parte foi encontrada por tools/analysis/find_missing_funcs.py, que procura thunks de vtable e funções pequenas que a análise estática do ReXGlue não descobre. O código gerado não tem nenhum REX_FATAL.

Instalar sem compilar

Quem não quer compilar pode usar a página do instalador (GitHub Pages deste repositório): ela lê o seu ISO ou a sua pasta do jogo no navegador, confere o default.xex, baixa o build pré-compilado e grava tudo em uma pasta ou em um .zip. O pacote não contém dados do jogo nem shaders traduzidos: os shaders são traduzidos no seu PC na primeira execução e ficam em cache. Detalhes, limites e como gerar e publicar um build em docs/installer.md.

Como jogar

O launcher com GUI permite escolher a API gráfica (Direct3D 12, o padrão recomendado, ou Vulkan, experimental), GPU, resolução, controles e opções gráficas antes de iniciar. Preferências já salvas mantêm a API escolhida. Com Vulkan, escala interna, FXAA, MSAA, sombras e filtro anisotrópico ficam no padrão do jogo; essas opções só valem em Direct3D 12. Compile o launcher com powershell -File tools/build_launcher.ps1 e abra artifacts/launcher/SupermanReturnsLauncher.exe. A versão portátil inclui .NET; detalhes em launcher/README.md. O pacote de distribuição também inclui o launcher. A seleção de GPU exige o executável do jogo da mesma build.

Depois de compilar com build.cmd:

ScriptUso
run.cmdControle de Xbox (ou compatível com XInput/SDL). Conecte-o antes de abrir o jogo.
run_keyboard.cmdTeclado e mouse. O runtime emula um controle de Xbox 360 e o mouse move a câmera.

Os dois aceitam opções extras, por exemplo run.cmd --fullscreen. O log fica em logs/game.log. Para escolher a API fora do launcher, use --sr_native_api=d3d12 ou --sr_native_api=vulkan (o padrão do executável continua d3d12).

Benchmark

O botão BENCHMARK do launcher abre o jogo direto no sobrevoo da cidade da tela de título, sem logo nem menu, com as configurações escolhidas. Depois de 5 s de aquecimento, ele mede 60 s e mostra FPS médio, mínimo, 1% e 0,1% low, tempos de quadro e as configurações usadas. Esc ou Enter fecham o jogo. O resultado também é salvo em benchmarks\benchmark-AAAAMMDD-HHMMSS.json, com o tempo de cada quadro num .csv. Teclado e controle ficam desligados durante a rodada.

  • Por linha de comando: run.cmd --sr_benchmark=true. Com --sr_benchmark_exit=true, o jogo fecha sozinho depois de salvar, com código de saída 0 se a rodada for válida e 1 se não for.
  • Sem janela na tela (para scripts): --sr_benchmark_headless=true. A janela vai para fora da tela assim que o jogo começa a apresentar quadros, o foco do teclado volta para a janela que abriu o jogo, e ao fim o jogo fecha sozinho (como --sr_benchmark_exit) e escreve uma linha de resumo no stdout (redirecione a saída para lê-la). O jogo continua renderizando normalmente na GPU: ocultar ou minimizar a janela pararia a apresentação, por isso ela só é movida.
  • A rodada é marcada como inválida se a cena 3D parar ou se o vídeo de demonstração do título começar (~77 s depois da cena).
  • O voo não é idêntico a cada abertura: no mesmo PC, a média variou ±4,5% entre rodadas. Para comparar builds, use a média de três rodadas.
  • Medido em 28/10 num i5-13420H + Intel UHD, 1280x720, sem limite: Direct3D 12 com 55,1 / 57,9 / 53,0 FPS e Vulkan com 41,6 FPS.

Detalhes no design do benchmark.

Trajes

O campo Traje do launcher escolhe a roupa do Superman sem desbloquear nada e sem gravar no save:

OpçãoLinha de comandoO que faz
Padrão do jogo(nada)O traje que o jogo escolher.
Golden Age--sr_costume=2Veste o Golden Age Superman, mesmo bloqueado.
Reino do Amanhã--sr_costume_skin=kingdom_comeRepinta o traje do filme como o Superman do Reino do Amanhã da CW: escudo vermelho com o S recortado em preto, sunga e botas vermelhas, cinto preto com fivela oval dourada.
  • O Reino do Amanhã é uma receita no código que repinta, durante o jogo, as texturas do traje lidas do seu disco. Nenhuma imagem do jogo vem com o projeto.
  • A skin aparece quando o Superman está com o traje do filme. Com outro traje vestido no menu do jogo, o log avisa.
  • --sr_costume também aceita 1 (Pod Suit), que ainda não foi testado. O jogo volta ao traje do filme quando recria o Superman em cinemáticas e cargas de fase, e o traje escolhido é vestido de novo nessas horas.
Texturas (dump e troca)

Funciona nos dois backends nativos (Direct3D 12 e Vulkan):

  • --sr_texture_dump_dir=<pasta> grava cada textura 2D distinta uma vez, como <chave>.png, e uma linha por textura em index.csv (key,width,height,format). A chave é um hash do conteúdo e do formato, a mesma em toda execução e nos dois backends.
  • PNGs com o nome <chave>.png na pasta textures\ ao lado do executável (ou em --sr_texture_replace_dir=<pasta>) substituem a textura original. O PNG precisa ter o mesmo tamanho da original; senão, o log avisa e a original fica. Um PNG vence a skin para a mesma chave.
  • --sr_texture_replace=false desliga as trocas e as skins.
  • O mapa das texturas do Superman está em docs/kingdom-come-texture-map-2026-10-28.md.
  • tools/texture_mods/find_costume_textures.py <dump A> <dump B> lista as texturas que só aparecem no segundo dump.
  • sr_skin_preview <dump> <saída> (em tests/native) aplica a skin aos PNGs de um dump, para ver a arte sem abrir o jogo.
Desempenho

O limite nativo de 30 FPS foi retirado do padrão: o executável e novas preferências do launcher usam sr_native_fps_limit=0. É possível selecionar 30, 60 ou 120 no launcher ou passar --sr_native_fps_limit=60. O modo sem limite agora usa o mecanismo do Xenia Canary: sr_native_fps_limit=0, VSync desligado e vblank seguido de espera de 1 ms. Esse é o padrão nativo para opções não definidas; opções explícitas prevalecem. Com limite zero e VSync ligado, a cadência de vblank fica em 60 Hz. O port também faz o contador de varredura avançar. Um segundo gate, interno ao scheduler de renderização do jogo, também segue o alvo de FPS: limite zero usa um piso de 1 ms; 30 mantém o comportamento original. O peer de simulação permanece com seu tick original. Para comparar com o gate interno de 30 Hz, use --sr_native_guest_render_scheduler=false. O desempenho medido na cidade ainda não comprova 60 FPS. Detalhes e limites em desbloqueio do Xenia Canary.

O build.cmd agora inclui por padrão o runtime verificado com rastreamento de escritas, necessário para evitar hashes de texturas com conteúdo comprovadamente inalterado. O D3D12 já usa staging em CPU, leituras limitadas de constantes e cache de resolves por identidade completa. Sem cobertura segura, a validação por hash continua. set SR_MEMORY_TRACKING_SDK=OFF permite compilar com o runtime original. Detalhes e validação em CPU e desbloqueio de FPS.

Em 29/10, o D3D12 passou a verificar texturas intactas pelas épocas das páginas sem consultar os locks do runtime quando a prova do upload continua válida. Também foram corrigidos o tamanho do pacote em bits e o argumento do segundo kick no flush XMA. Build, testes e limites da comparação de desempenho estão no relatório das otimizações das referências.

O renderer também evita preparar slots de textura não usados pelos shaders, com fallback completo para shaders desconhecidos. A opção --sr_native_used_texture_mask=false restaura o caminho anterior após reiniciar. Testes e medições em máscara de texturas usadas.

Texturas que diferem apenas em filtros, clamp ou LOD bias também compartilham armazenamento no D3D12, preservando seus samplers e versões de conteúdo. No Vulkan, esse compartilhamento é experimental e fica desligado por padrão após regressão nos ensaios desta máquina. SR_NATIVE_TEXTURE_STORAGE_REUSE=0 desliga nas duas APIs; =1 força nas duas. Defina a variável antes de iniciar. Testes e limites em compartilhamento de texturas.

O reaproveitamento de bancos por constantes usadas pelo shader está experimental e desligado por padrão: eliminou escritas, mas piorou os dois pares D3D12 medidos. Pode ser testado com SR_NATIVE_USED_CONSTANT_MASK=1; no Vulkan portável depende também de SR_VULKAN_CONSTANT_BANK_CACHE=1. Validação e medições.

O runtime do build padrão também drena o PCM XMA já decodificado quando a entrada acaba, respeitando espaço/padding e retornando se não houver progresso. Correção e testes de drenagem XMA.

A última etapa, atualizações seletivas de texturas, está implementada nas duas APIs e é experimental (SR_NATIVE_TEXTURE_UPDATES=1, padrão desligado). Ela reaproveita recursos compatíveis após concluir seu uso e preserva versões pendentes; o decode continua completo. Implementação e testes.

No Windows, o monitor de memória agrupa consultas e proteção por regiões, preservando os limites observados e os direitos de cada alias. Esse caminho fica ligado por padrão; SR_TRACKING_BATCH_ARM=0 restaura o legado após reiniciar. Nos ensaios, o ganho mais claro foi remover pausas longas em Compare; o FPS normal variou entre pares. Pesquisa e benchmarks de CPU. Para repetir A/B sequencial sem instrumentação: python tools/bench/cpu_web_sweep.py --suite arm --blocks 3 --cpu-profile 0.

DLSS Quality funciona no renderer nativo D3D12, com SDK oficial instalado e GPU RTX compatível. O build detecta o SDK local; SR_DLSS=OFF permite desabilitar o suporte. Ative NVIDIA DLSS no menu ou use --sr_dlss=quality. Há movimento apenas de câmera, portanto objetos em movimento ainda podem deixar rastros. Correção e validação na RTX 2060.

No renderer nativo, num i5-13420H + Intel UHD, o quadro é limitado pela GPU integrada: a cena principal ocupa ~72% do tempo de GPU. O trabalho de CPU do worker D3D12 fica em ~13 ms por quadro. Números atuais na seção Benchmark; análise em pistas de desempenho de 28/10.

As medições abaixo são históricas e registram explicitamente os limites usados. Medido no fechamento do ciclo 3 em 2026-10-06 no mesmo i5-13420H + Intel UHD, com tools\bench\bench_api.ps1 (New Game, 20 s parado e 20 s andando, janela 1280x720, limite de 30 FPS; o script só mede depois de ver o HUD do jogo na tela):

RendererParadoAndandoObservação
native, Direct3D 1225,5 FPS27,5 FPSexecução final; GPU a 72–77%; resultados históricos ~30 FPS variam com a cena
native, Vulkan (ciclo 3, 2026-10-06)17,4 / 17,6 FPS18,4 / 17,5 FPSduas execuções seguidas; gates de imagem PASS; gravação ~28–32 ms; meta ≥ 29 FPS não atingida

O ciclo 3 reduziu o custo da gravação Vulkan de ~50–56 ms para ~28–32 ms, mantendo texturas exatas por quadro e posse dos recursos até o fence. O FPS ainda depende do worker de replay, da captura na thread do jogo e da GPU. No fechamento, o D3D12 mediu 25,5 FPS parado e 27,5 andando; a câmera variável impede concluir ausência de regressão com uma única execução. Resultados por tarefa e limitações dos testes estão no spec do ciclo 3. Novas otimizações exigem uma decisão de escopo.

Backend Xenos (compatibilidade)

O backend xenos emula a GPU do Xbox 360 e só roda quando você o escolhe. Ele não é o foco do projeto e é bem mais pesado que o nativo: numa GPU integrada fica a ~98% nas cenas 3D. As opções abaixo valem só para ele. Medições num i5-13420H com Intel UHD:

Modo de render (--render_target_path_d3d12)Vídeos de aberturaCena 3D (tela de título)
rov (padrão do runtime)30 FPS~2 FPS
rtv (padrão deste projeto)~16 FPS~10 FPS

Neste hardware o RTV ficou bem à frente, então o jogo aplica por padrão, em port/src/superman_returns_app.h: render_target_path_d3d12=rtv, depth_float24_convert_in_pixel_shader=true (sem ela o céu e o fundo ficam pretos no rtv) e native_stencil_value_output_d3d12_intel=true (dica do Xenia para GPUs Intel, xenia-canary#542: 7,6 → 10,2 FPS na rua). Em outras GPUs o ROV pode se sair melhor: qualquer opção passada na linha de comando prevalece, por exemplo run.cmd --sr_renderer=xenos --render_target_path_d3d12=rov.

Se o D3D12 nativo ficar em 9–11 FPS com a GPU a 100%, o jogo provavelmente está no backend Xenos: confira o log (veja Solução de problemas).

Para medir, F3 abre um painel com o FPS do jogo, e set SR_LOG_FPS=1 antes de rodar grava o FPS em logs/game.log a cada 2 s. F4 abre as configurações do runtime.

Presets (sr_preset)

--sr_preset=quality (padrão) mantém o visual atual; --sr_preset=performance hoje não muda nada (o sr_post_effects=false foi retirado do preset após a validação abaixo); --sr_preset=custom não altera nenhuma opção. O preset só preenche opções que continuam no padrão: uma opção passada na linha de comando, no ambiente ou no .toml prevalece. sr_render_scale ainda é experimental e nenhum preset o altera. Detalhes e limitações em docs/performance-design.md.

Pós-processamento (sr_post_effects, experimental, não validado)

--sr_post_effects=false (padrão true, exige reiniciar) desliga a cadeia de bloom/raios de luz. Exige o backend D3D12 em processo (tools/setup_gpu_source.ps1 antes do build.cmd); sem ele a opção é ignorada com aviso no log. Com a opção desligada, o processador de comandos do projeto pula os quads (primitiva 13 = quad list) das superfícies menores que a cena (640, 320, 160 e 80 pixels de largura) e o resolve que segue cada um. Os passes na superfície de 1280 (entre eles a composição final) e o HUD continuam. A lista fica em port/src/native_renderer/post_effects.h e foi derivada do trace docs/data/gpu_groups_gameplay_intel_uhd.csv. Validado em 2026-09-29 (i5-13420H + Intel UHD, post_effects_check.ps1, 2 pares): nenhum ganho de FPS (−1% parado, −6% andando, dentro do ruído) e imagem corrompida com a opção desligada (ruído na tela: os resolves pulados deixam lixo nas texturas que a composição final lê). Não use false até a opção ser refeita. O teste anterior que pulou todos os draws de primitiva 13 (inclusive os de 1280 e o HUD) deu 8,4 FPS contra 7,1, com imagem não verificada; não é uma estimativa desta opção.

Para validar em casa: powershell -File tools\bench\post_effects_check.ps1 -Pairs 2 -Trace. O script roda o tools\bench\bench.ps1 com a opção ligada e desligada, compara os screenshots (logs\post_effects_<nome>_*_diff.png), confere no log quantos passes foram pulados e, com -Trace, lista a ordem dos passes de um quadro com tools\bench\post_effects_trace.py. Se a imagem quebrar (tela preta, brilho congelado ou lixo), o relatório do trace indica quais passes mantidos leem as texturas que deixaram de ser atualizadas.

Desenvolvimento do renderizador próprio

O modo experimental --sr_renderer=trace já usa um processador de comandos do projeto. Ele registra draws, cópias, swaps, hashes de shaders e estados gráficos, mas ainda delega a renderização ao backend Xenos D3D12. É uma ferramenta de migração, sem ganho de FPS esperado. O modo padrão é native (veja abaixo).

Para compilar o modo de captura, execute powershell -File tools\setup_gpu_source.ps1 antes de build.cmd. O script baixa somente o código gráfico do ReXGlue v0.10.0 para .tools/. Para capturar 120 quadros de gameplay após o início de um jogo novo, execute `powershell -File tools\analysis\