Versão HD de Halo 2: o projeto de remasterização que desafia os limites do Xbox original
(icode4.coffee)- O patch Halo 2 HD para o Xbox original foi um projeto que combinou modificação do executável, alterações no hardware do console e criação de ferramentas de benchmark para tentar renderização além de 480p, em 720p e 1080p
- O Halo 2 existente, apesar da indicação de 480p, internamente desenhava em um back buffer de 640×480 e depois a GPU fazia upscale para 720×480, então o suporte a HD exigia mudanças conjuntas nos buffers D3D e no tratamento dos modos de vídeo
- A execução em 720p não cabia nos 64 MB de RAM padrão, exigindo upgrade para 128 MB de RAM e hot patch no kernel, contornando a limitação para alocar memória física contígua para a GPU também nos 64 MB superiores
- O desempenho foi melhorado com triple buffering, tiling do render target texaccum e overclock da GPU de 233,33 MHz para 300 MHz, elevando a cena de benchmark Zanzibar de cerca de 19 FPS para algo em torno de 27–28 FPS
- A RAM adicional também foi usada para ampliar os caches de textura e geometria e melhorar a taxa de transferência do HDD; o patch final deixou o 720p em um nível utilizável, mas o 1080p ficou mais próximo de um bônus para screenshots
Objetivo do projeto e premissas de hardware
- O objetivo era adicionar suporte a resolução HD à versão original de Halo 2 para Xbox e verificar até onde o hardware modificado do console conseguiria aguentar
- O escopo do trabalho incluía patch no jogo, modificação de hardware do console Xbox e criação de ferramentas customizadas para benchmark de desempenho
- O Xbox modificado que serviu de base para o projeto era chamado de “god box” e incluía as seguintes mudanças
- Substituição da CPU Pentium 3 padrão de 733 MHz por uma variante customizada de Pentium 3 de 1,4 GHz com uma placa interposer personalizada
- Possibilidade de overclock da CPU para cerca de 2 GHz
- Uso de RAM adicional e SSD
- Uso de kernel ou imagem de BIOS customizados para dar suporte às modificações de hardware
- A maior resolução de vídeo suportada por Halo 2 era 480p, e a meta era adicionar 720p e, se possível, suporte a 1080i
- Ao aumentar a resolução, a carga da GPU cresce por causa do maior volume de cálculos de pixel shader, então considerou-se que o trabalho só valeria a pena se fosse possível fazer overclock da GPU
- Depois, tornou-se possível um overclock de cerca de 15% na GPU, e o console “GENESIS-3” foi preparado para desenvolvimento
Os 480p de Halo 2 e a estrutura interna de renderização
- Halo 2 indica suporte a 480p na caixa, mas
D3DPRESENTFLAG_PROGRESSIVEnão estava definido nos parâmetros de present do D3D, e a escala do tamanho de tela era sempre1.0f - O
screen_boundsinterno era configurado para 640×480 independentemente do modo de vídeo- No Xbox original, 480p era tratado como 720×480
- Halo 2 renderizava em um back buffer de 640×480 e depois a GPU fazia upscale para 720×480 antes de enviar ao codificador de vídeo
- No modo widescreen, era usada uma câmera anamórfica de 1,33:1 para comprimir uma imagem mais ampla na mesma superfície de 640×480
- Esse método pode ter sido uma forma de compensar a compressão horizontal do modo stretch da TV
- O patch também adicionou uma opção para desativar o escalonamento anamórfico
Patch de D3D para renderização HD
- Para dar suporte às resoluções, três funções foram os principais alvos de modificação
_rasterizer_detect_video_mode: alterada para ativar progressive scan também em 720p_rasterizer_init_screen_bounds: passou a configurar dimensões de 640×480, 720×480, 1280×720 e 1920×1080 de acordo com o modo de vídeorasterizer_device_initialize: configuração do back buffer do D3D e das flags de present
- No modo 1080i, após verificar se a largura da tela era 1920, o patch remove
D3DPRESENTFLAG_PROGRESSIVEe defineD3DPRESENTFLAG_INTERLACED - Depois das mudanças iniciais, o filtro azul desapareceu no menu principal, e surgiram problemas de listras repetidas e recorte na geometria da água
- Parte dos problemas vinha de views 640×480 hardcoded para os buffers de back/front/depth
- Isso criava views de textura/surface com larguras diferentes apontando para a mesma memória, desalinhando a disposição das scan lines
Memória D3D e reconfiguração dos render targets
- O Xbox original usa uma arquitetura de memória unificada, na qual CPU e GPU compartilham a mesma RAM
- Não é uma estrutura como no PC, em que alocações D3D vão para VRAM e são gerenciadas pela GPU
- A CPU pode criar memória para texturas, render targets, vertex buffers etc. e passar os endereços diretamente para a GPU
- Halo 2 usa cerca de 25 render targets, mas na prática há apenas 4 ou 5 alocações de buffers realmente distintas
- Vários render targets compartilham a mesma memória com views de recursos diferentes para economizar espaço
rasterizer_primary_targets_initializecriava render targets adicionais e views de textura a partir dos buffers back/front/depth criados pelo D3D, e mantinha 640×480 hardcoded- O patch envolveu essa função com um hook para, após a execução da função original, ajustar o tamanho das texturas/surfaces para a resolução atual do back buffer
- O pitch em memória tiled pode ser diferente do habitual
width * bpp, então ele foi calculado comD3D_CalcTilePitch - Um pitch incorreto podia causar o efeito de listras, especialmente em 1080i
- O pitch em memória tiled pode ser diferente do habitual
Ajuste do tamanho do render target texaccum
- O recorte na geometria da água no menu principal acontecia porque o render target texaccum estava fixo em 640×480
- A implementação de DirectX do Xbox permite apenas 4 amostragens de textura por passe de pixel shader
- Objetos que precisam de mais de 4 texturas de entrada exigem renderização em vários passes
- A camada texaccum compõe primeiro as detail textures e depois é usada como entrada no passe de lightmap
rasterizer_targets_initializealocava o render target texaccum em 640×480- O patch aplicou hook em
_rasterizer_alloc_and_create_render_targetpara mudar largura e altura do alvo texaccum comtarget_index == 1para o tamanho atual do back buffer - Após essa mudança, o recorte da geometria da água desapareceu, e também deixaram de aparecer problemas visíveis de renderização ao carregar mapas
- O problema do filtro azul foi resolvido com uma simples atualização na checagem de tamanho, mas os detalhes do processo foram omitidos
Limites de memória que impediam o 720p
- Ao configurar 720p, o jogo travava na inicialização, e a causa era falta de memória devido ao aumento dos buffers front/back/depth e dos rasterizer targets
- O Xbox original teve um modelo de consumo com 64 MB de RAM e um dev kit/debug console com 128 MB
- A placa retail já possuía os locais para os chips extras de RAM
- Soldando os chips de RAM e usando um kernel modificado, era possível acessar os 64 MB adicionais
- Para rodar em 720p ou mais, era necessário o upgrade para 128 MB de RAM
- Para manter até o 480p normal sem upgrade de RAM, seria preciso pegar memória do cache de texturas em memória, o que aumentava o pop-in de texturas
Patch no gerenciador de memória de Halo 2
- Na inicialização, Halo 2 aloca cerca de 48,9 MB dos 64 MB disponíveis em uma grande área única de dados de runtime
- Essa área é dividida entre metadados de fase, texturas, geometria, animação, cache de som, rasterizer target e recursos de rede/simulação
- Para visualizar o uso de memória, foi criado o XboxImageGrabber
- Ele percorre as entradas da page table e visualiza o estado de uso da RAM como bitmap
- A área de dados de runtime era alocada em um endereço hardcoded, 0x80061000
- Os tag data dos arquivos de mapa são serializados com esse endereço-base, então esses dados precisam permanecer sempre no mesmo endereço
- Outros dados de runtime podem ser movidos
- As áreas escolhidas para realocação foram rasterizer target, texture cache e geometry cache
- Chamadas de alocação específicas foram interceptadas para movê-las para a debug memory region
- Nos momentos corretos de liberação, como no carregamento de um novo nível, chamadas de free apropriadas foram adicionadas
- O tamanho da área de dados de runtime também foi reduzido para diminuir desperdício
physical_memory_mallocfoi inlineado pelo compilador, então foi necessário aplicar patches separados em cada call site
Hot patch no kernel do Xbox e memória física nos 64 MB superiores
- Os endereços de memória passados para a GPU precisam ser físicos, e o intervalo correspondente deve ser contíguo
- A GPU não tem conceito de page table nem tradução de endereço virtual
- Mesmo em um kernel com 128 MB de RAM, por padrão só era possível fazer alocações físicas contíguas nos primeiros 64 MB; alocações virtuais podiam usar os 128 MB completos
- Testes usando manualmente entradas da page table dos 64 MB superiores como se fossem memória da GPU deram certo
- A limitação de não usar memória física dos 64 MB superiores para a GPU era uma restrição de software do kernel, não do hardware
- Dentro de
MmAllocateContiguousMemoryExhavia uma checagem deMAX_USABLE_PFN- O valor antigo era 0x83FE0000, equivalente a 64 MB - 128 KB
- Os 128 KB superiores eram reservados para a scratch area da GPU de 64 KB e a page table da CPU de 64 KB
- O patch verifica, na inicialização do jogo, se o console tem 128 MB de RAM e então procura o valor
mov edx, 0x3FDFdentro deMmAllocateContiguousMemoryExpara substituí-lo por um novo valor compatível com a configuração de 128 MB - Depois disso,
MmAllocateContiguousMemoryExeMmFreeContiguousMemorypassaram a ser usados para alocar e liberar memória física contígua em toda a faixa de 128 MB - Também houve efeitos colaterais
- Ao sair do jogo e voltar ao dashboard sem cold reboot, ou ao ejetar a bandeja de DVD e fazer warm reboot, o aplicativo ou jogo seguinte podia apresentar artefatos gráficos severos e travamentos
- Para ocultar isso, foi adicionado um patch extra para forçar cold reboot ao encerrar o jogo
Resultados em 720p/1080p e gargalos de desempenho
- A renderização em 720p trouxe melhoria visual, mas o desempenho era muito baixo em cenas pesadas, com FPS caindo para menos de 10
- Em 1080p, a renderização nativa era possível, mas a saída do console Xbox só aceitava sinal 1080i
- Ao despejar diretamente o back buffer do D3D, era possível obter screenshots em 1080p antes de a GPU convertê-lo para half frame para o codificador de vídeo
- A medição de desempenho comparou três configurações: Xbox padrão, god box com apenas overclock de CPU e god box com overclock de CPU + GPU
- Um trecho pesado de Zanzibar foi usado como “zanzibar benchmark scene”
- Nas medições iniciais, o FPS das três configurações era quase igual, e o gráfico de desempenho mostrou que a causa era swap stall
- Halo 2 usa vsync ligado e double buffering
- Surgia uma situação em que a GPU ficava esperando o vblank e não conseguia girar a swap chain
Triple buffering e confirmação do gargalo na GPU
- Como solução, o número de back buffers foi aumentado para 2, usando 1 front buffer e 2 back buffers, totalizando triple buffering
- Em
D3DPRESENT_PARAMETERS, foram definidosBackBufferCount = 2,D3DSWAPEFFECT_DISCARDeD3DPRESENT_INTERVAL_ONE - O motor de renderização de Halo 2 trocava os ponteiros de back/front buffer a cada frame assumindo double buffering, então o hook de swap e o hook de inicialização dos primary targets também precisaram ser alterados
- As duas primary render surfaces e suas texture views foram modificadas para sempre apontar para o back buffer atual
- Mesmo que o jogo troque internamente os dois ponteiros, ambos passam a apontar para a mesma memória, tornando a troca efetivamente um no-op
- Na cena de benchmark Zanzibar, o FPS com a GPU padrão passou para cerca de 22 FPS
- Aproximadamente 3 FPS acima do valor anterior
- Cerca de 10% de aumento em relação ao limite de 30 FPS
- O swap stall desapareceu e a utilização da GPU foi ao máximo, confirmando que o gargalo era a GPU
Overclock de GPU e RAM
- Ao trocar o render target texaccum para memória tiled, foi possível ganhar mais 1–2 FPS
- A cena de benchmark Zanzibar melhorou de cerca de 19 FPS para 23–24 FPS
- Com a GPU da god box em overclock, a cena de benchmark Zanzibar registrou 27–28 FPS
- Ao circular pelo mapa, em geral o jogo mantinha 30 FPS, caindo apenas em algumas áreas pesadas
- Para evitar a necessidade de regravar a BIOS, o registrador de memory-mapped IO do gerador de clock da GPU foi ajustado diretamente no início do jogo
- O cálculo do clock da GPU é baseado nos valores M, N e P de
NVPLL_COEFFe no clock-base de 16,6667 MHz- O valor N padrão 28 produz clock de GPU de 233,33 MHz
- Ajustando o valor N, tornou-se possível configurar incrementos de cerca de 8 MHz, com opção de configuração por arquivo ini
- O overclock da GPU para 300 MHz acrescentou cerca de 3 FPS no benchmark Zanzibar em relação à GPU padrão
- O limite de overclock variava de GPU para GPU
- GPUs de consoles revisão 1.0 a 1.4 frequentemente mostravam limite na faixa baixa dos 300 MHz
- Houve casos de GPUs de consoles revisão 1.6 operando de forma estável acima de 400 MHz
- O clock da RAM também foi testado
- A largura de banda teórica máxima do barramento de memória do Xbox é de 6,4 GB/s, e a utilizável na prática é tratada como cerca de 70%, ou 4,5 GB/s
- A RAM já opera perto de 200 MHz por padrão, então até um aumento de cerca de 10 MHz pode causar instabilidade
- Em teste com cerca de 208 MHz, observou-se ganho de 0,7 FPS
- Chips de RAM capazes de 250 MHz também foram encomendados, mas ainda não haviam sido instalados nem testados no momento do texto
Redução de pop-in e expansão de cache
- Halo 2 já sofria originalmente com pop-in de texturas e geometria, algo ainda mais visível em consoles com HDD mecânico do começo dos anos 2000
- A RAM extra foi usada para ampliar o texture cache e o geometry cache
- O geometry cache padrão é de 6,5 MB em mapas single-player e 7 MB em mapas multiplayer
- O texture cache varia conforme o tamanho do mapa e usa o espaço restante após os tag data e antes do low detail texture cache
- Os caches funcionam com política LRU
- A cada 30 frames, dados não usados nos 30 frames mais recentes são removidos
- Quando o cache enche, o chamador pode forçar eviction, ou a requisição de carregamento falha e é tentada novamente no frame seguinte
- As texturas podem ter buffers de LOD low/medium/high
- Se o carregamento de high LOD falha, o jogo tenta medium ou low LOD
- Isso pode fazer um LOD mais baixo aparecer primeiro e depois ser trocado por um mais alto, gerando pop-in
- Os mapas também incluem um emergency low detail texture cache com tamanhos de 2×2 até 8×8
- Ele é usado para desenhar temporariamente modelos na tela mesmo quando o carregamento normal de textura falha
- O fenômeno em que o terreno aparecia com texturas de resolução extremamente baixa ao abrir e fechar o menu de amigos do Xbox Live estava ligado ao uso desse cache
- A funcionalidade de visualização gráfica do build de debug da Bungie foi reconstituída para observar diretamente o uso dos caches e ajustar seus tamanhos
- A configuração final aumentou o geometry cache para 20 MB e fixou o texture cache em 30 MB
- Ambos ficaram quase com o dobro do tamanho em relação às configurações padrão
- Na cutscene de abertura de Outskirts, Master Chief já aparece imediatamente com textura em alta resolução e ainda sobra espaço livre no cache
- Para reduzir ainda mais o pop-in, a taxa de transferência do HDD também foi aumentada
- O UDMA 2 padrão oferece cerca de 33,3 MB/s
- O UDMA 3 oferece cerca de 44,4 MB/s
- Com um cabo IDE de 80 vias, é possível configurar até UDMA 5, cerca de 100 MB/s
- Isso oferece cerca de 10% de ganho com o cabo IDE padrão e até 300% teóricos com cabo IDE melhorado
- O perfil final de memória em 720p usa mais de 75% dos 128 MB de RAM
- No modo 1080p, o uso de memória da swap chain e dos rasterizer targets é grande demais, exigindo reduzir o tamanho dos caches e usando, na prática, quase todos os 128 MB
Resultado
- No geral, o patch 720p foi melhorado até alcançar um nível jogável, enquanto o suporte a 1080p ficou mais como um bônus para screenshots
- Ainda há espaço para melhorias de desempenho e mudanças de memória, mas o resultado já leva Halo 2 e o console Xbox bastante perto de seus limites
- O download do patch Halo 2 HD e o código-fonte estão disponíveis no GitHub
1 comentários
Opiniões do Hacker News
Link do vídeo no fim do post: https://www.youtube.com/watch?v=O_nk21389u8
O vídeo traz uma comparação lado a lado entre o original com upscale para 480p e 720p, e, por volta dos 7 minutos, explica o que é necessário para obter 720p mantendo a jogabilidade em cerca de 30 fps
O texto também é excelente, mas o vídeo que resume as mudanças necessárias para uma resolução mais alta também é bom
A discussão de que 720×480 não é uma resolução 16:9, ou não é “480p de verdade”, na verdade deveria ser levada para o lado da padronização da ITU dos anos 1970: https://tech.ebu.ch/docs/techreview/trev_304-rec601_wood.pdf
Em um memorando de fevereiro de 1980, dizia-se que, para acomodar todos os períodos de linha ativa dos padrões europeus, o número de amostras por linha ativa precisava ser maior que 715,5; depois, as 720 amostras usadas na Rec. 601 e na SMPTE 125 se consolidaram como o primeiro valor que “funcionava”
A Rec. 601 fornecia 720 amostras por linha ativa para o canal de luminância e 360 amostras para cada sinal de crominância; ao definir HDTV, dobraram a resolução horizontal desse sistema de TV existente e aplicaram a proporção 16:9, resultando em 1920 amostras/linha e 1080 linhas
O sistema de varredura progressiva 1280×720 também pertence à mesma família de 720 pixels, e a maioria dos sistemas baseados em TV digital, DVD e MPEG deriva desse formato padrão básico 4:2:2
O “espírito hacker” em si é totalmente legítimo, mas fico curioso se há algum motivo específico para jogar Halo 2 assim, passando pelo trabalho de adicionar memória ao console e fazer overclock da GPU, em vez de usar a versão para PC
Há muitos vídeos que cobrem os problemas em vários níveis de detalhe
https://youtu.be/03K2Uz3s1hg?si=zaFO1XdzMcFvI1F6
Dá a sensação de provar que é plenamente possível, ou até melhor
Talvez seja quase uma barreira psicológica, mas, no geral, é algo leve e divertido, como o oposto da obsessão de comprar antes de todo mundo o modelo mais recente de um aparelho popular
Ambos dão uma espécie de sensação de superioridade
Ainda hoje dá para jogar Halo 2 em lobbies online ou na campanha, com a opção de gráficos originais da 343 ou gráficos HD remasterizados
No texto, foi dito que “o sistema de dados de tags foi projetado para ser o mais flexível e rápido possível, e seu funcionamento interno é impressionante do ponto de vista de engenharia. Eu poderia escrever um artigo inteiro só sobre por que acho que ele torna a engine Blam uma das engines mais flexíveis, mas isso não tem relação com este texto”; se esse artigo de fato for escrito, eu certamente gostaria de lê-lo
Eu era iniciante demais para acompanhar como aquilo funcionava, e era dinâmico demais para eu entender fundamentalmente que uma estrutura daquelas era possível
Eu não entendia como a posição do jogador podia estar no mesmo contexto que uma arma com configurações, e como até os efeitos podiam estar na mesma lista
Muitas das coisas que me interessam hoje, no fim, continuam girando em torno desses conceitos
Eu queria que a era do modding de Xbox e Halo 2 voltasse nos tempos modernos
Aquela época teve um grande impacto na minha escolha de carreira, e ainda acredito que Halo 2 é o jogo online mais inovador de todos os tempos
Bastava comprar uma ferramenta simples para carregar saves de jogos e, em poucos minutos, dava para fazer um softmod no Xbox; já os consoles atuais estouram e-fuses, impedem downgrade e têm muito mais reforços de segurança
Junto com o projeto da Insignia para começar a dar suporte a Halo 2, é uma ótima fase para o Halo 2 clássico
Um dos motivos pelos quais virei engenheiro de software hoje foi poder olhar facilmente como uma página web funcionava, mexer na memória de programas e abrir hardware para ver por dentro
Na época de Halo PC, aprendi muito sobre o que entra em um jogo modificando níveis; saber o que é “BSP” talvez seja uma trivia inútil, mas me deu confiança de que eu podia entender mais coisas
Ainda é possível entrar em tecnologia e aprender hoje, mas é difícil ver esse caminho acontecendo por meio de uma experimentação prática de verdade
Software ficou muito mais difícil de crackear ou depurar; não é impossível, mas a barreira de entrada ficou muito mais alta
Páginas web ainda podem ser inspecionadas, mas muitos sites hoje viraram pilhas de divs sustentando monstros de JavaScript minificado e ofuscado, e jogos muitas vezes são simplesmente difíceis por dependerem cada vez mais de streaming de conteúdo a partir de servidores
No hardware também é preciso lidar com procedimentos de segurança que podem transformar o aparelho em tijolo, pistolas de ar quente para abrir bordas coladas e o risco de dano permanente
Cada uma dessas mudanças deve ter tido seus motivos, mas, no processo, boa parte da diversão desapareceu; mesmo que as ferramentas de hoje sejam tecnicamente melhores, o modding de jogos não é mais como antes
Ainda hoje dá para mexer bastante em PCs ou consoles baseados em PC, como o Steam Deck, então não sei por que brigar com um console proprietário projetado para ser fechado
Também não fica claro o que se ganha além de acesso a hardware x86 customizado que pode ser comprado barato no mercado
FPS online competitivos com comunidades fortes de modding já estavam ativos no PC havia mais de 10 anos
Há uma comunidade ativa graças ao Project Cartographer: https://halo2.online/home/
Essa pessoa parece mais dedicada a Halo 2 do que a Bungie hoje dedica à própria IP
A IP pertence à Microsoft e o desenvolvimento fica a cargo da 343 Industries
A Bungie hoje tem Destiny/Destiny 2 e o próximo shooter de extração Marathon
Passei horas demais naquele jogo, e é bom ver que outra pessoa também caiu no mesmo feitiço que eu
Ainda assim, esse nível de dedicação é admirável
Pode soar cínico demais, mas o projeto em si é realmente muito legal
Só fico em dúvida se dá para dizer que trocar a CPU, fazer overclock, aumentar a RAM, adicionar armazenamento de estado sólido e ainda fazer overclock da GPU é levar o Xbox original ao limite
Nesse ponto, ele praticamente já não parece um Xbox
Quando alguém diz que levou um Honda Civic ao limite depois de mexer muito no motor e na suspensão, perguntar “mas ainda é mesmo um Civic?” pode estar tecnicamente correto, mas soa como implicância
O autor tem o direito de dar o título que quiser; basta ler mentalmente como algo do tipo “modificar um OG Xbox até quase matá-lo”
Como Halo 2 pode rodar em resolução maior no 360, é útil deixar claro que é um projeto de modding voltado ao Xbox original
Não quer dizer literalmente um Xbox sem modificações, e sim que o alvo do modding era o Xbox original
Também diz que, em um console com cabo IDE padrão, a taxa de transferência aumenta 10%, e que, usando um cabo IDE atualizado, teoricamente pode aumentar até 300%
Com 128 MB de RAM, dá para aproveitar a RAM adicional para habilitar modos de vídeo 720p e 1080i e aumentar o cache de memória de texturas e geometria, quase eliminando pop-in
Se você só quer 480p, basta fazer overclock da GPU em um console original e usar outro cabo IDE
A formulação sobre SSD parece ter causado confusão sem querer; talvez quisesse dizer uma combinação de cabo de 80 vias e SSD
Uma CPU com overclock não é necessária e a CPU também não é o gargalo; a RAM aumentada só é necessária se você quiser 720p ou mais
Esse feedback foi repassado, então o post do blog talvez seja atualizado para esclarecer melhor essa parte
A cena de computadores retrô é assim, e tuning de carros é parecido
Algumas pessoas querem um Corvette perfeito como saiu de fábrica; outras querem um Model A com um motor 50 anos mais moderno
Há algo muito legal em torcer, do seu jeito, um objeto familiar e conhecido
O volume de trabalho é enorme
Também é interessante que o amigo “doom” não quisesse revelar sua identidade