<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Games | AkitaOnRails.com</title><link>https://akitaonrails.github.io/tags/games/</link><description>Blog do Fabio Akita do Canal do YouTube 'Akitando' falando sobre tecnologia, carreira e coisas geek.</description><generator>Hugo -- gohugo.io</generator><language>pt-BR</language><lastBuildDate>Mon, 19 Oct 2026 23:20:48 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/tags/games/index.xml" rel="self" type="application/rss+xml"/><item><title>Desafio pra IA: converter ROMs de NES pra Master System/SMS</title><link>https://akitaonrails.github.io/2026/09/07/desafio-pra-ia-converter-roms-de-nes-pra-master-system-sms/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/09/07/desafio-pra-ia-converter-roms-de-nes-pra-master-system-sms/</guid><pubDate>Mon, 07 Sep 2026 14:00:00 -0300</pubDate><description>&lt;p&gt;Durante muitos anos eu tive uma ideia fixa na cabeça, e sempre achei que ela não era prática: converter jogos de NES pra rodar no Master System.&lt;/p&gt;
&lt;p&gt;Deixa eu ser preciso. Eu sempre soube que dava pra fazer. Duas máquinas Turing completas conseguem, em tese, rodar o código uma da outra. Você sempre consegue traduzir programa de uma arquitetura pra outra. O problema nunca foi possibilidade, foi custo. O NES roda um 6502, o Master System roda um Z80, e ao longo dos anos eu li em vários cantos que uma tradução direta de 6502 pra Z80 sempre acabava rodando muito mais devagar, por causa das diferenças de arquitetura e de hardware. Devagar o suficiente pra nunca compensar na prática.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Durante muitos anos eu tive uma ideia fixa na cabeça, e sempre achei que ela não era prática: converter jogos de NES pra rodar no Master System.</p>
<p>Deixa eu ser preciso. Eu sempre soube que dava pra fazer. Duas máquinas Turing completas conseguem, em tese, rodar o código uma da outra. Você sempre consegue traduzir programa de uma arquitetura pra outra. O problema nunca foi possibilidade, foi custo. O NES roda um 6502, o Master System roda um Z80, e ao longo dos anos eu li em vários cantos que uma tradução direta de 6502 pra Z80 sempre acabava rodando muito mais devagar, por causa das diferenças de arquitetura e de hardware. Devagar o suficiente pra nunca compensar na prática.</p>
<p>E essa memória tem fundamento. Se você for atrás em fórum de retro-dev, tipo o <a href="https://forums.nesdev.org/viewtopic.php?t=17339"target="_blank" rel="noopener">NESdev</a>, o consenso é que traduzir instrução por instrução é justamente o pior caminho: &ldquo;cada instrução do código-fonte vira várias instruções no código objeto, e o programa resultante roda muito mais devagar e ocupa muito mais memória&rdquo;. Não é só a CPU. O 6502 tem a zero page, um modo de endereçamento baratíssimo que o Z80 não tem equivalente, então você troca um acesso barato por uma sequência cara com <code>IX</code>/<code>IY</code>. E a parte gráfica é pior ainda: o PPU do NES e o VDP do Master System são bichos diferentes, com scroll, sprites e espelhamento de tela que não encaixam um no outro sem gambiarra cara.</p>
<p>Ou seja, todo mundo que já pensou nisso chegou na mesma conclusão: dá pra fazer, mas roda mal demais pra valer a pena.</p>
<p>Só que agora a gente tem LLMs de fronteira. E eu fiquei curioso: será que uma abordagem de força bruta, com uma LLM boa no meio do processo, consegue um resultado melhor do que a tradução ingênua de sempre? Comecei o projeto <a href="https://github.com/akitaonrails/nes-to-sms"target="_blank" rel="noopener">nes-to-sms</a> no fim de maio, uns três meses atrás, pra descobrir.</p>
<p>O primeiro resultado foi exatamente o que a teoria previa: ruim. Uma tradução mais ou menos direta gerou código que roda, mas devagar demais. Eu consegui converter o Super Mario Bros inteiro, com sprites, fases, tudo, mas pra ficar minimamente jogável eu precisava rodar o emulador Mednafen com overclock de 500%. Depois de bater cabeça com Claude, GPT e outros modelos por um tempo, empaquei. Trabalhei firme por junho e julho, e em agosto pausei o projeto pra deixar a poeira baixar.</p>
<h2>Por que Master System, e não NES?<span class="hx:absolute hx:-mt-20" id="por-que-master-system-e-não-nes"></span>
    <a href="#por-que-master-system-e-n%c3%a3o-nes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de explicar a parte técnica, preciso explicar a obsessão, porque ela é o motivo de tudo.</p>
<p>Eu sempre achei o Master System um console superior ao NES. Melhor CPU, melhor chip de vídeo, uma paleta de cores bem mais rica. O NES trabalha com 4 cores por tile de fundo e 3 por sprite. O Master System trabalha com paletas de 16 cores. Isso é uma diferença enorme na prática.</p>
<p>O problema é que a Nintendo tinha um monopólio brutal na época e não deixava as third parties lançarem pra outros consoles. Quem quisesse fazer jogo pro NES assinava um contrato de exclusividade. O resultado é que o Master System, tecnicamente melhor, ficou faminto de jogos. Praticamente só a própria Sega lançava, e a biblioteca da Sega nunca teve o peso de um Castlevania, um Mega Man, um Final Fantasy.</p>
<p>Imagina o que a gente perdeu. Dava pra ter tido aqueles mesmos jogos clássicos do NES, só que com a capacidade superior do Master System por baixo. Um Castlevania com mais cor, sprites melhores, som melhor. A gente nunca teve isso, e é exatamente essa frustração histórica que me fez querer converter NES pra SMS em primeiro lugar.</p>
<h2>O port que provou a tese<span class="hx:absolute hx:-mt-20" id="o-port-que-provou-a-tese"></span>
    <a href="#o-port-que-provou-a-tese" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Enquanto eu estava com o projeto parado, um outro desenvolvedor, o <a href="https://github.com/lackoftrack27/Super-Mario-Bros.-SMS"target="_blank" rel="noopener">lackoftrack27</a>, publicou um port de Super Mario Bros pro Master System que é de outro nível. Roda em velocidade cheia, 60fps, e ainda por cima com uma arte de sprite melhorada que aproveita a paleta superior do console. Ficou mais parecido com o remaster do Super Mario All-Stars do Super Nintendo do que com a versão original meio crua do NES. A comunidade retro ficou de queixo caído.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/igOu1NQL5Ww"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Isso provou, na prática, a minha tese: o Master System é capaz de rodar versões superiores dos jogos de NES. Sempre foi.</p>
<p>Agora, dois pontos honestos sobre esse port, porque eles importam pro resto da história.</p>
<p>Primeiro: o trabalho do lackoftrack27 é uma reimplementação feita à mão, a partir da disassembly do jogo, otimizada especificamente pro Super Mario. Não é uma tradução automática de propósito geral como a que eu tento fazer. Ele resolveu um jogo, lindamente, no braço. Curiosamente, isso reforça o que os fóruns já diziam: o caminho que funciona é reimplementar no braço, não traduzir a máquina.</p>
<p>Segundo: por mais impressionante que seja ver o Super Mario no Master System, é bom lembrar que ele ainda é um jogo de primeira geração, de uns 40kb. Ou seja, é um dos jogos mais simples do NES. Coisas de geração posterior, tipo Super Mario Bros 3 ou Kirby, ninguém tentou converter ainda, e por bons motivos que eu explico mais pra frente.</p>
<p>Mas o mais importante foi o efeito colateral: com o mapa que o port dele me deu, eu finalmente consegui fazer a minha conversão automática rodar direito. Voltei ao projeto no começo de setembro, carreguei o código do lackoftrack27 no Claude Fable e depois no novo GPT Astra, e coloquei os dois pra estudar o que ele fez que eu não estava fazendo.</p>
<h2>A arquitetura da solução<span class="hx:absolute hx:-mt-20" id="a-arquitetura-da-solução"></span>
    <a href="#a-arquitetura-da-solu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Como esse artigo é pra programador, deixa eu abrir a caixa preta.</p>
<p>A primeira decisão importante é que o <code>nes-to-sms</code> não é um emulador, nem um tradutor texto-pra-texto de 6502 pra Z80. Ele é um <strong>recompilador estático</strong>. Ele lê a ROM do NES, levanta o código 6502 pra uma representação intermediária com semântica explícita, e daí gera código Z80 a partir dessa IR. A saída é um projeto em assembly WLA-DX que compila numa ROM <code>.sms</code> de verdade. O núcleo é um workspace Rust com treze crates, mais um runtime Z80 escrito à mão que é compartilhado entre os jogos.</p>
<p>O fluxo, de ponta a ponta, é mais ou menos assim:</p>
<ol>
<li>Parsear o cabeçalho da ROM, separar os bancos de código (PRG) e de tiles (CHR) e ler os vetores de reset e interrupção.</li>
<li>Carregar um perfil por jogo (um TOML com rótulos, regiões de dados, tabelas de salto, tipo de mapper e substituições).</li>
<li>Descobrir as funções, montar o grafo de fluxo e classificar cada byte como código ou dado. Aqui entra um detalhe chave: cada acesso à memória é etiquetado com a região a que pertence (zero page, pilha, RAM, registradores do PPU, DMA de sprite, som, mapper).</li>
<li>Levantar cada rotina pra IR, com as flags do 6502 explícitas. Uma escrita no registrador <code>$2006</code> do PPU não vira um <code>mem[]=</code> qualquer, vira uma primitiva de &ldquo;escrita no PPU&rdquo; de primeira classe.</li>
<li>Baixar a IR pra Z80. As flags do 6502 são mantidas num byte de status sombra na RAM, e todo acesso a hardware vira uma chamada pro runtime.</li>
<li>Emitir os bytes Z80 e também o assembly WLA-DX legível.</li>
<li>Converter os assets: os tiles 2bpp do NES viram tiles 4bpp do modo 4 do Master System, a paleta do NES vira a CRAM do SMS, e por aí vai.</li>
<li>Escrever o projeto SMS inteiro, com Makefile, runtime e dados, pronto pra compilar.</li>
</ol>
<p>O mapeamento da CPU é conservador de propósito. O acumulador <code>A</code> do 6502 vira o <code>A</code> do Z80, os registradores <code>X</code> e <code>Y</code> ficam em RAM ou em registradores, a zero page vira um bloco fixo na RAM do SMS, e cada operação que mexe em flag chama um helper. É seguro e correto, mas é justamente aqui que mora o custo.</p>
<h2>Onde NES e SMS divergem de verdade<span class="hx:absolute hx:-mt-20" id="onde-nes-e-sms-divergem-de-verdade"></span>
    <a href="#onde-nes-e-sms-divergem-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O achado central do projeto é sobre velocidade, e ele é contraintuitivo.</p>
<p>O 6502 do NES roda a 1.79 MHz. O Z80 do Master System roda a 3.58 MHz, o dobro do clock. Você olha isso e pensa &ldquo;então tem folga de sobra&rdquo;. Só que não. O Z80 gasta em média uns 13 ciclos por instrução, enquanto o 6502 gasta uns 4. Na conta real, um Z80 de 3.5 MHz equivale mais ou menos a um 6502 de 1 MHz pra trabalho genérico. Ou seja, o Z80 do SMS é na verdade <strong>mais lento</strong> que o 6502 do NES pra fazer o mesmo trabalho. A folga é negativa.</p>
<p>Pior: o idioma mais barato do 6502, um <code>LDA tabela,X</code>, é um dos mais caros de emular no Z80. Então uma tradução fiel de um jogo que já espremia o NES no talo simplesmente não tem como bater 60fps sem overclock. A culpa é da física do problema, não do meu tradutor.</p>
<p>E o vídeo é outra história. O NES enxerga a memória de vídeo de forma mapeada, com nametables, scroll por hardware e uma tabela de sprites acessada por DMA. O Z80 do SMS não endereça a VRAM como memória: ele seta um latch de endereço e joga bytes por portas do VDP. Então toda escrita de PPU do NES precisa ser capturada, enfileirada num buffer e despejada no VDP durante o vblank. O NES vira sprite de graça, só setando um bit de atributo. O Master System não tem flip de sprite por hardware, então o programa precisa espelhar os dados do tile na VRAM na unha, gastando memória. O split de tela que os jogos de NES fazem no meio do frame, mexendo no scroll a cada scanline, também não tem equivalente direto, porque o VDP trava o scroll vertical no topo do frame.</p>
<p>E ainda tem o teto de VRAM. Os 8 KB de tiles do Super Mario viram 16 KB no formato 4bpp do SMS, que é a VRAM inteira do console. Fundo e sprites não cabem residentes ao mesmo tempo. E o código explode de 3 a 6 vezes de tamanho, por isso a saída SMS já é bancada desde o primeiro jogo, mesmo os mais simples.</p>
<h2>Aproveitando o que o SMS tem de melhor<span class="hx:absolute hx:-mt-20" id="aproveitando-o-que-o-sms-tem-de-melhor"></span>
    <a href="#aproveitando-o-que-o-sms-tem-de-melhor" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A sacada pra recuperar velocidade é parar de emular o comportamento do NES e passar a gastar as forças do Master System. O lema do projeto virou &ldquo;gastar ROM pra comprar CPU&rdquo;.</p>
<p>O SMS aceita cartuchos de vários megabytes. Então em vez de espelhar sprite na unha em tempo de execução, o build já gera variantes pré-espelhadas de cada tile de sprite, e o flip vira uma consulta de tabela. Em vez de emular a tabela de atributos do NES, o assembler já grava a palavra final de nametable do SMS, com os bits de flip, paleta e prioridade embutidos. A tabela de atributos do NES simplesmente deixa de existir no programa. As cópias pro VDP usam blocos de <code>OUTI</code> desenrolados, mais rápidos que o loop genérico. E o split da barra de status, que no NES depende do sprite-zero, vira uma interrupção de linha do SMS, que é o jeito nativo de fazer isso.</p>
<p>Nada disso é mágica. A folga negativa da CPU continua lá, então essas otimizações reduzem o custo mas não fazem milagre sozinhas. Mas é a diferença entre injogável e jogável.</p>
<h2>O pulo do gato: fazer a IA rodar o emulador<span class="hx:absolute hx:-mt-20" id="o-pulo-do-gato-fazer-a-ia-rodar-o-emulador"></span>
    <a href="#o-pulo-do-gato-fazer-a-ia-rodar-o-emulador" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui está a parte que eu considero mais importante do projeto inteiro, e é o que separou a tentativa fracassada de maio da versão que finalmente anda.</p>
<p>Tradução cega não funciona. O modelo precisa de feedback real pra saber o que está quebrado e o que está lento. Então o coração do projeto está no <strong>oráculo diferencial</strong>, a infraestrutura que roda os emuladores e mede a realidade. O tradutor é só a parte fácil.</p>
<p>Funciona em duas camadas. A primeira compara instrução por instrução: pra cada rotina, o sistema gera estados iniciais aleatórios, roda o 6502 original num interpretador de referência e roda o Z80 gerado, e compara o resultado (acumulador, registradores, flags, RAM tocada). Qualquer divergência acende o alerta. A segunda camada compara frame a frame: ela roda a ROM do NES como verdade absoluta e a build do SMS lado a lado, com o mesmo roteiro de botões, e compara a RAM byte a byte em cada frame. Depois isso foi estendido com um oráculo que confere a VRAM e a paleta do SMS, e com um oráculo visual que compara a saída contra o frame real do NES.</p>
<p>Esse loop de medir é o que destravou os consertos recentes. Não foi chute. Dois exemplos concretos:</p>
<p>No Super Mario, cada passo de otimização foi medido em ciclos por frame, com o emulador rodando de verdade. O orçamento de um frame é 59.736 ciclos. A base parou em uns 370 mil ciclos por frame, algo como 6 vezes acima do orçamento, o que dava uns 10fps e explicava a necessidade daquele overclock brutal de 500%. Medindo passo a passo, cada mudança validada pelo oráculo, a coisa desceu até 118.296 ciclos por frame, ou 1.98 vezes o orçamento. Ou seja, saiu de 6 vezes pra menos de 2 vezes. Agora ele roda em velocidade cheia já no overclock padrão do emulador, e fica confortável ali na casa dos 200 a 300%, contra os 500 a 700% do começo.</p>
<p>No Castlevania, o maior ganho de velocidade veio de um perfil que só o emulador conseguiu revelar: um loop de espera de sprite-zero, no endereço <code>$F8C7</code>, estava fazendo 255 leituras de status e saindo por timeout toda vez, consumindo quase 23% de toda a CPU. Sem rodar o emulador e medir, ninguém acharia isso no olho. Com a medição, o conserto foi cirúrgico.</p>
<p>É esse o argumento maior que eu venho batendo faz tempo sobre agentes: um LLM que só gera código no escuro erra feio. Um LLM que consegue rodar o alvo de verdade, coletar dado real e reagir ao que mediu joga em outro nível.</p>
<h2>O que aprendi estudando o port do lackoftrack27<span class="hx:absolute hx:-mt-20" id="o-que-aprendi-estudando-o-port-do-lackoftrack27"></span>
    <a href="#o-que-aprendi-estudando-o-port-do-lackoftrack27" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Com esse oráculo no lugar, coloquei o Claude Fable e o GPT Astra pra dissecar o port do lackoftrack27, que é uma reimplementação do mesmo jogo a partir da mesma disassembly que eu traduzo. Isso respondeu de vez uma dúvida que estava me travando: o Super Mario cabe no Master System. O meu estouro de 6 vezes no orçamento era 100% overhead de tradução, não limitação do jogo nem do hardware.</p>
<p>Os ganhos dele, em ordem de impacto, foram mais ou menos esses:</p>
<ul>
<li><strong>A maior de todas: a representação dos dados.</strong> Ele reorganizou os arrays de objetos do jogo em páginas de RAM, uma por slot, com os mesmos offsets de campo. Aí o <code>X</code> do 6502 vira o registrador <code>H</code> e o nome do campo vira o <code>L</code>, e um acesso que no meu tradutor custava umas 70 unidades de tempo passa a custar 14. O detalhe cruel é que isso só funciona porque o programador sabe, de cabeça, que aquele <code>X</code> ali é sempre um índice de objeto entre 0 e 6. Um tradutor estático não tem como descobrir esse invariante com segurança. Essa é a otimização mais poderosa, e é justamente a que a tradução automática não consegue provar sozinha. É o resíduo que segura as últimas 2 vezes de velocidade.</li>
<li><strong>Flags auditadas, não emuladas.</strong> Ele checou o código e achou só uns 10 lugares que dependem de verdade de alguma peculiaridade do carry do 6502. O resto usa flag nativa do Z80. Isso confirmou uma medição minha: gastar energia emulando flag rende quase nada.</li>
<li><strong>Chamadas nativas.</strong> <code>JSR</code> virando <code>CALL</code> de verdade, sem a contabilidade cara de pilha emulada. Esse foi o maior ganho genérico que eu portei pro meu pipeline.</li>
<li><strong>PPU deletado em tempo de build</strong>, não emulado em runtime, exatamente como descrevi na seção de aproveitar o SMS.</li>
<li><strong>Frame arquitetado pra estourar com elegância</strong>, transformando um estouro em um frame de lag limpo em vez de corromper a tela.</li>
</ul>
<p>Adotei o que dava pra generalizar, e o Super Mario despencou de 6 vezes pra menos de 2 vezes o orçamento. Esse é o resultado rodando hoje:</p>
<div class="embed-container">
  <video controls preload="metadata" playsinline style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000;">
    <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260907152243_smb-sms-conversion.mp4" type="video/mp4">
  </video>
</div>
<p>A lição mais honesta desse estudo é dupla. Os ganhos de verdade estão na representação de dados e na convenção de chamada, não no que eu tinha atacado primeiro. E o ganho mais fundo de todos é exatamente o que o tradutor automático não consegue inferir. Isso desenha bem o teto do que dá pra automatizar.</p>
<h2>Castlevania e o problema dos mappers<span class="hx:absolute hx:-mt-20" id="castlevania-e-o-problema-dos-mappers"></span>
    <a href="#castlevania-e-o-problema-dos-mappers" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Com o Super Mario andando, voltei pro meu velho alvo: o primeiro Castlevania. E aqui a gente esbarra na limitação mais séria do NES.</p>
<p>O NES é um console simples, com um monte de limitação. Uma das principais é que ele não suporta jogo maior do que uns 40kb de ROM, porque o 6502 só enxerga uma janela de 32 KB de programa no espaço de endereço dele. A &ldquo;solução&rdquo; da época foi genial e meio maluca: partes do console foram sendo turbinadas pelo próprio cartucho.</p>
<p>Muita gente pensa que cartucho é só um chip de ROM com o código do jogo. No caso do NES, não. Os cartuchos vinham com uma variedade de chips extras que aumentavam a capacidade do console, seja um chip de som melhor ou, muito mais comum, os <strong>mappers</strong>. Existem vários mappers diferentes, da própria Nintendo e de third parties como Capcom e Konami. Eles usam uma técnica chamada <strong>bank switching</strong>: como o 6502 não enxerga endereço suficiente, o mapper vai trocando quais pedaços de ROM ficam visíveis naquela janela de 32 KB, conforme o jogo pede. É assim que jogos grandes cabem num console que, no papel, não aguentaria.</p>
<p>Eu já expliquei isso em detalhe num vídeo antigo do canal, o <a href="/2020/06/18/akitando-81-aprendendo-sobre-computadores-com-super-mario-do-jeito-hardcore/">Akitando #81, sobre aprender computação com o Super Mario do jeito hardcore</a>:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/hYJ3dvHjeOE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>O Castlevania usa um dos mappers mais antigos, o UxROM. E aqui está o problema de escala do meu projeto: se eu quiser conseguir traduzir a maioria dos jogos de NES, eu tenho que mapear todos os mappers, um por um. Hoje o projeto implementa só dois: o NROM, que é o cartucho pelado do Super Mario, e o UxROM do Castlevania. Todos os outros, os MMC1, MMC3 e companhia, estão só planejados. Cada mapper é um trabalho e tanto de implementar, porque não basta entender o bank switching do NES, é preciso traduzir esse comportamento pro mapper próprio do Master System.</p>
<p>A boa notícia é que o Master System também é um sistema bancado, então o mapeamento é &ldquo;a mesma forma um nível acima&rdquo;. Um banco de PRG do NES vira um conjunto de bancos do SMS, uma escrita de troca de banco do NES vira uma escrita no mapper do SMS através de um shim, e uma chamada que cruza bancos usa a maquinaria de &ldquo;portão&rdquo; que já existe. A identidade de uma rotina passa a ser o par (banco, endereço), e uma tabela de despacho resolve isso em tempo de execução. Quando não acha, ele falha fechado, com um trap, em vez de rodar lixo.</p>
<p>É aqui que os jogos maiores vão bater na parede. O bank switching de tiles dos mappers mais avançados, o timing de interrupção por scanline do MMC3 e do MMC5, e o próprio teto de bancos do SMS pra um jogo de NES bem grande, tudo isso ainda está por resolver. Por isso eu ainda não sei dizer se um Super Mario Bros 3 é viável ou não. É bem possível que os jogos maiores morram exatamente nessa etapa.</p>
<p>De qualquer forma, mexi mais um bocado no Castlevania nessa retomada. Consertei uma pilha de coisas usando o oráculo: o loop de sprite-zero que comia CPU, a lógica de armas e projéteis que perdia retornos de chamada, um glitch de scroll na barra de status, a colisão de VRAM entre sprites 8x16 e 8x8, e a coerência entre fundo, paleta, HUD e sprites. Hoje o Castlevania sobe, aceita o start, desenha o primeiro estágio de forma reconhecível, responde ao controle e roda por um bom tempo sem travar. Mas é honesto dizer que ele ainda roda devagar, e o caminho que eu uso pra jogar é o Mednafen com overclock de 500%, e mesmo assim ainda está de 2 a 3 vezes abaixo da própria meta de velocidade. Está longe de ser pixel perfeito e em tempo real.</p>
<div class="embed-container">
  <video controls preload="metadata" playsinline style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000;">
    <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260907152243_castlevania-sms-conversion.mp4" type="video/mp4">
  </video>
</div>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois de tantas semanas e tantas tentativas, eu ainda não sei quanto mais dá pra espremer de uma tradução automática. O teto pode estar perto, porque as otimizações mais fundas são justamente as que uma máquina não consegue inferir sozinha.</p>
<p>Mas tem um caminho que me anima. A tradução automática pode virar uma linha de base. Uma conversão SMS que já roda, correta, ainda que lenta, e que depois pode ser otimizada no braço, jogo a jogo, exatamente como o lackoftrack27 fez com o Super Mario e como tanta gente vem fazendo com decompilações e ports por aí. O oráculo garante que a base está correta, e a mão humana entra pra fazer o que a máquina não consegue.</p>
<p>Portar jogo pra um hardware muito superior, tipo um port pra PC, é relativamente fácil, porque sobra capacidade. O difícil de verdade é encaixar o jogo num console da mesma geração, onde não sobra nada. E é justamente essa dificuldade que torna a ideia de fazer versões melhores de jogos de NES pro Master System tão atraente. É o console que merecia ter tido esses jogos, e nunca teve.</p>
<p>Eu espero que mais gente se anime com essa possibilidade e contribua com o projeto. Está tudo aberto no <a href="https://github.com/akitaonrails/nes-to-sms"target="_blank" rel="noopener">nes-to-sms</a>. Se você curte 6502, Z80, VDP e o desafio de espremer ciclo de um hardware de 40 anos atrás, apareça. Tem lugar de sobra.</p>
]]></content:encoded><category>retrocomputacao</category><category>agentes-de-codigo</category><category>games</category><category>emulacao</category></item><item><title>Frank GO: brincando de GO com IA</title><link>https://akitaonrails.github.io/2026/07/06/frank-go-brincando-de-go-com-ia/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/07/06/frank-go-brincando-de-go-com-ia/</guid><pubDate>Mon, 06 Jul 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/06/frank-go/key-art-hikaru-no-go.webp" alt="Arte oficial do anime Hikaru no Go: o Hikaru no centro estendendo uma pedra de Go pra câmera, com o fantasma Sai de trajes Heian e leque atrás dele, cercados pelo elenco (Akira, Waya, Isumi, Akari e companhia) e pelo logo da Shonen Jump." loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Eu comecei a gostar do milenar jogo de Go por causa do mangá &lt;strong&gt;Hikaru no Go&lt;/strong&gt;. Cheguei a escrever sobre isso &lt;a href="https://akitaonrails.github.io/2008/07/15/off-topic-por-que-programadores-devem-jogar-go/"&gt;em 2008, num post que ainda está no ar&lt;/a&gt;, defendendo por que programadores deveriam jogar Go. De lá pra cá pouca coisa mudou no meu caso de uso: eu tenho um goban físico em casa, mas nunca tive a menor intenção de entrar em grupo de estudo, federação ou competição. Eu só gosto de jogar sozinho, resolver uns tsumego (os quebra-cabeças de vida e morte do Go), e carregar partidas famosas pra estudar, como os lendários jogos do Lee Sedol contra o AlphaGo em 2016.&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/06/frank-go/key-art-hikaru-no-go.webp" alt="Arte oficial do anime Hikaru no Go: o Hikaru no centro estendendo uma pedra de Go pra câmera, com o fantasma Sai de trajes Heian e leque atrás dele, cercados pelo elenco (Akira, Waya, Isumi, Akari e companhia) e pelo logo da Shonen Jump."  loading="lazy" /></p>
<p>Eu comecei a gostar do milenar jogo de Go por causa do mangá <strong>Hikaru no Go</strong>. Cheguei a escrever sobre isso <a href="/2008/07/15/off-topic-por-que-programadores-devem-jogar-go/">em 2008, num post que ainda está no ar</a>, defendendo por que programadores deveriam jogar Go. De lá pra cá pouca coisa mudou no meu caso de uso: eu tenho um goban físico em casa, mas nunca tive a menor intenção de entrar em grupo de estudo, federação ou competição. Eu só gosto de jogar sozinho, resolver uns tsumego (os quebra-cabeças de vida e morte do Go), e carregar partidas famosas pra estudar, como os lendários jogos do Lee Sedol contra o AlphaGo em 2016.</p>
<p>Pra quem não conhece o mangá: Hikaru no Go (roteiro de Yumi Hotta, arte de Takeshi Obata, o mesmo de Death Note) rodou na Shonen Jump entre 1998 e 2003 e causou um boom de interesse por Go no Japão inteiro. E tem um detalhe que pouca gente sabe: praticamente todas as partidas que aparecem no mangá são baseadas em jogos históricos reais, recriados quadro a quadro. Guarda essa informação, porque ela volta daqui a pouco.</p>
<h2>SGF e o problema do material espalhado<span class="hx:absolute hx:-mt-20" id="sgf-e-o-problema-do-material-espalhado"></span>
    <a href="#sgf-e-o-problema-do-material-espalhado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Existem vários programas open source muito bons pra carregar partidas de Go ou até jogar online. Partidas de Go são gravadas num formato chamado <strong>SGF</strong> (Smart Game Format), um formato de texto puro que existe desde o fim dos anos 80: cada jogada vira uma coordenada (<code>;B[pd]</code> é uma pedra preta no ponto 4-4), e o formato suporta árvores de variação, comentários e metadados da partida. É o padrão de facto do mundo do Go: todo cliente lê SGF, todo servidor exporta SGF, e existe um acervo gigantesco de partidas históricas e problemas nesse formato acumulado ao longo de décadas.</p>
<p>E aí mora o problema: esse acervo está <strong>espalhado pela internet inteira</strong>. Um site tem as coleções clássicas de tsumego, outro tem as partidas históricas, um repositório do GitHub tem os problemas comentados, outro tem os kifu (registros de partida) profissionais. Eu não estava com o menor humor de baixar tudo manualmente, organizar pasta por pasta e configurar cliente por cliente. Eu queria um app bom o suficiente, bonito o suficiente, com tudo embutido.</p>
<h2>2008: a era GNU Go<span class="hx:absolute hx:-mt-20" id="2008-a-era-gnu-go"></span>
    <a href="#2008-a-era-gnu-go" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui vale o contexto histórico, porque ele é a parte divertida. Em 2008, quando escrevi aquele post, a única &ldquo;IA&rdquo; de Go acessível era o <a href="https://www.gnu.org/software/gnugo/"target="_blank" rel="noopener">GNU Go</a>. E olha, a gente nem pode chamar aquilo de IA: era um monte de heurísticas empilhadas. E era terrível. Até um amador como eu conseguia ver que ele fazia jogadas sem fluxo nenhum, sem sentido de direção, pedras soltas que não conversavam entre si. Ganhava de iniciante por pura tática local e só.</p>
<p>O que aconteceu nos 18 anos seguintes é uma das histórias mais bonitas da computação. Primeiro vieram os métodos de Monte Carlo Tree Search, que já melhoraram bastante o nível.</p>
<p>Aí em março de 2016 o <strong>AlphaGo</strong> do DeepMind venceu Lee Sedol, um dos maiores jogadores da história, por 4 a 1. Foi a série da famosa jogada 37 da partida 2 (o &ldquo;ombro&rdquo; que nenhum humano jogaria) e da resposta à altura do Lee Sedol: a jogada 78 da partida 4, a &ldquo;mão de Deus&rdquo; que lhe deu sua única vitória. Se você nunca viu, existe um <a href="https://www.netflix.com/title/80190844"target="_blank" rel="noopener">documentário excelente sobre essa série na Netflix</a>, que vale a pena até pra quem não sabe nada de Go.</p>
<p>E depois que o DeepMind publicou os papers, a comunidade open source correu atrás: primeiro o Leela Zero reimplementando o AlphaZero, e depois o KataGo indo além. Hoje qualquer um tem um jogador sobre-humano de Go rodando de graça no próprio computador. Eu queria ver de perto o quanto essas IAs amadureceram em 20 anos.</p>
<p>Foi dessa vontade que nasceu meu novo projeto de brinquedo: o <strong><a href="https://github.com/akitaonrails/frank_go"target="_blank" rel="noopener">Frank GO</a></strong>.</p>
<h2>Sabaki + KataGo<span class="hx:absolute hx:-mt-20" id="sabaki--katago"></span>
    <a href="#sabaki--katago" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pedi pro Claude Code pesquisar os apps e engines open source de Go mais populares (a pesquisa inteira está documentada <a href="https://github.com/akitaonrails/frank_go/tree/main/docs/research"target="_blank" rel="noopener">no próprio repositório</a>, como manda o figurino). No fim escolhi dois projetos como base:</p>
<p>O <strong><a href="https://sabaki.yichuanshen.de/"target="_blank" rel="noopener">Sabaki</a></strong>, do Yichuan Shen, é o front-end. É provavelmente o editor de SGF e tabuleiro de Go open source mais bonito e bem cuidado que existe, feito em Electron, com suporte a árvores de variação, análise e engines via protocolo GTP. Elegante e minimalista.</p>
<p>O <strong><a href="https://github.com/lightvector/KataGo"target="_blank" rel="noopener">KataGo</a></strong>, do David Wu, é a IA. É o motor open source mais forte do mundo, sobre-humano, herdeiro da linhagem do AlphaZero mas com uma diferença que importa demais pro meu caso: além da taxa de vitória, o KataGo estima <strong>pontuação e domínio de território ponto a ponto</strong>. Ele responde &ldquo;quem está ganhando, por quantos pontos, e quais áreas do tabuleiro pertencem a quem&rdquo;. É exatamente o tipo de informação que um iniciante precisa e que os engines antigos escondiam.</p>
<p>O Frank GO é um fork do Sabaki que amarra o KataGo pra sessões de jogo solo, e embute tudo aquilo que eu queria ter num lugar só:</p>
<ul>
<li><strong>Mais de 4.700 tsumego</strong> das coleções clássicas (a Enciclopédia do Cho Chikun, o Gokyo Shumyo, o Xuanxuan Qijing), transcritas pelo Vít Brunner no <a href="https://tsumego.tasuki.org/"target="_blank" rel="noopener">tsumego.tasuki.org</a> e convertidas pra SGF pelo projeto <a href="https://github.com/Seon82/tasuki2sgf"target="_blank" rel="noopener">tasuki2sgf</a>, mais os 420 problemas comentados do <a href="https://github.com/gogameguru/go-problems"target="_blank" rel="noopener">go-problems do Go Game Guru</a> (do An Younggil, profissional 8-dan), organizados em 10 níveis de dificuldade. Resolve 5 seguidos e sobe de nível. Um seletor de foco filtra por vida e morte, tesuji, ko ou semeai (corrida de capturas).</li>
<li><strong>Os puzzles revidam</strong>: com o KataGo instalado, ele responde suas jogadas dentro do problema, e quando ele desiste da área o app julga o resultado e marca o problema como resolvido automaticamente.</li>
<li><strong>Partidas históricas famosas pra estudar</strong>, do Jogo da Orelha Vermelha (1846, do lendário Honinbo Shusaku) até AlphaGo vs Lee Sedol, curadas do <a href="https://homepages.cwi.nl/~aeb/go/games/"target="_blank" rel="noopener">banco de partidas do Andries Brouwer no CWI</a>, cada uma com a história por trás, e as do AlphaGo com comentário jogada a jogada. Dá pra assistir em auto-play ou ligar o modo &ldquo;adivinhe a jogada&rdquo; e tentar achar o lance do profissional.</li>
<li><strong>As partidas do Hikaru no Go</strong>: lembra que os jogos do mangá são reais? Pois é, 15 deles estão embutidos com referência de capítulo e curiosidades, usando o <a href="https://senseis.xmp.net/?HikaruNoGoGames"target="_blank" rel="noopener">mapeamento capítulo-a-partida que a comunidade compilou na Sensei&rsquo;s Library</a>. A partida de internet do Sai contra o Toya Meijin, por exemplo, é um jogo real decidido por meio ponto.</li>
<li><strong>Dicionário de joseki</strong> (o <a href="https://waterfire.us/joseki.htm"target="_blank" rel="noopener">Kogo&rsquo;s Joseki Dictionary</a>, referência clássica de aberturas de canto), drills de escada, drill de &ldquo;quem está ganhando?&rdquo;, e um teste de rank de dez problemas que estima seu nível e te larga direto na prática certa.</li>
</ul>
<p>Lembra do problema do material espalhado? Essas coleções aí de cima são exatamente ele: cada uma vivia num canto da internet. A procedência e o licenciamento de cada conjunto estão documentados no <a href="https://github.com/akitaonrails/frank_go/blob/main/data/SOURCES.md"target="_blank" rel="noopener">data/SOURCES.md</a> do repositório, porque acervo dos outros se usa dando o devido crédito.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/06/frank-go/tsumego-practice.jpg" alt="Prática de tsumego no Frank GO: um problema de canto no tabuleiro com o overlay de pintura de área ligado, e o painel lateral mostrando nível 1, foco, e o aviso de que o KataGo responde as jogadas."  loading="lazy" /></p>
<h2>Overlays pra quem está começando<span class="hx:absolute hx:-mt-20" id="overlays-pra-quem-está-começando"></span>
    <a href="#overlays-pra-quem-est%c3%a1-come%c3%a7ando" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A parte em que eu mais mexi no Sabaki foi criar sobreposições visuais amigáveis pra iniciante. A principal é a <strong>pintura de área</strong>: um overlay que pinta a influência de cada jogador como um gradiente suave e o território consolidado em cor sólida, então você literalmente <strong>vê</strong> o que as pedras estão fazendo, quais áreas estão mortas e quais estão em disputa.</p>
<p>Junto vem o <strong>placar em tempo real</strong> considerando o komi (a compensação de pontos do branco por jogar em segundo), que avisa quando você está irremediavelmente atrás ou quando o jogo já está decidido. E passando o mouse no tabuleiro aparecem os nomes das jogadas (&ldquo;Hane&rdquo;, &ldquo;One-Point Jump&rdquo;), o vocabulário que os livros usam e que iniciante demora a absorver.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/06/frank-go/study-mode.jpg" alt="Modo de estudo do Frank GO: a partida de aposentadoria do Honinbo Shusai (1938) carregada no tabuleiro, com a pintura de área escurecendo as pedras mortas e o painel lateral contando a história do jogo imortalizado no romance “O Mestre de Go” do Kawabata."  loading="lazy" /></p>
<p>Esse era o meu problema com todo software de Go que já testei: são ferramentas feitas por jogadores fortes pra jogadores fortes. Winrate em porcentagem não diz nada pra quem está aprendendo. &ldquo;Você está 12 pontos atrás e o canto inferior esquerdo morreu&rdquo; diz tudo. O KataGo sempre soube calcular isso; faltava alguém colocar na tela de um jeito que iniciante entende.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/06/frank-go/practice-panel.jpg" alt="Painel de prática do Frank GO dando boas-vindas e sugerindo o teste de rank de dez problemas pra encontrar seu nível."  loading="lazy" /></p>
<p>A ideia é ser um balcão único, sem configuração nenhuma, pra iniciante e estudante aprender Go no próprio ritmo. E tem build pra todo lugar. No Arch Linux é <code>yay -S frank-go</code> via AUR. No <strong>Windows</strong> tem instalador e versão portátil nos <a href="https://github.com/akitaonrails/frank_go/releases"target="_blank" rel="noopener">Releases</a>; o instalador não tem assinatura digital, então o SmartScreen reclama na primeira execução, é só clicar em &ldquo;Mais informações → Executar assim mesmo&rdquo; (<a href="/2026/05/30/boas-praticas-projetos-codigo-aberto-llm-o-minimo/">eu explico por que não assino build de Windows no post de boas práticas</a>). No <strong>macOS</strong> é <code>brew install --cask akitaonrails/tap/frank-go</code>, ou o <code>.dmg</code> pra Apple Silicon e Intel; esse build é assinado com Developer ID e notarizado pela Apple, abre sem drama nenhum. E em qualquer plataforma dá pra rodar do fonte com <code>npm install</code>.</p>
<p>Em todos os casos o app baixa um engine de CPU pequeno com um clique, sem GPU, sem conta, sem servidor, totalmente offline. A exceção é o macOS, onde o KataGo não tem binário oficial: um <code>brew install katago</code> destrava o jogo contra a IA, e todo o resto (tsumego, estudo, drills, pintura de área) funciona sem ele. O progresso fica na sua máquina.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/06/frank-go/study-and-drills.jpg" alt="Menu de estudo e drills do Frank GO: estudar partida famosa, partidas do Hikaru no Go, dicionário de joseki, drill de quem está ganhando, drill de escada e teste de rank."  loading="lazy" /></p>
<h2>E quando você quiser jogar contra gente<span class="hx:absolute hx:-mt-20" id="e-quando-você-quiser-jogar-contra-gente"></span>
    <a href="#e-quando-voc%c3%aa-quiser-jogar-contra-gente" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O Frank GO é deliberadamente um app de estudo solo. Quando você aprender e quiser jogar contra humanos, o caminho natural são os servidores online, e aí os apps mais avançados servem melhor. O <a href="https://online-go.com/"target="_blank" rel="noopener">OGS (Online Go Server)</a> é o mais amigável hoje, roda direto no navegador. O <a href="https://www.gokgs.com/"target="_blank" rel="noopener">KGS</a> e o <a href="https://www.pandanet-igs.com/"target="_blank" rel="noopener">Pandanet IGS</a> (o Internet Go Server original, no ar desde o começo dos anos 90) são os veteranos, e os servidores asiáticos como Fox e Tygem concentram os jogadores mais fortes. O mundo do Go organizado gira em torno da <a href="https://www.intergofed.org/"target="_blank" rel="noopener">IGF (International Go Federation)</a> e das associações nacionais, com rankings e torneios pra quem quiser levar a sério.</p>
<p>Eu não quero. E esse é o ponto do projeto inteiro: como eu disse lá em cima, não tenho nenhuma vontade de competir. Eu queria, há literalmente anos, um jeito de jogar e me divertir com Go no meu ritmo, com material de estudo decente num lugar só, contra uma IA que joga bonito em vez de cuspir pedras sem sentido como o GNU Go de 2008. Acho que finalmente consegui.</p>
<p>O código é MIT, o repositório é <a href="https://github.com/akitaonrails/frank_go"target="_blank" rel="noopener">github.com/akitaonrails/frank_go</a>, e contribuições são bem-vindas. Tem inclusive uma <a href="https://github.com/akitaonrails/frank_go/issues/6"target="_blank" rel="noopener">issue aberta pedindo retratos dos personagens</a> pro modo Hikaru no Go, se alguém quiser desenhar. O Sai agradece.</p>
]]></content:encoded><category>frank</category><category>llms</category><category>inteligencia-artificial</category><category>games</category></item><item><title>Como Driveclub e shadPS4 Quase Derrotaram a IA e a Mim: Como Aprender</title><link>https://akitaonrails.github.io/2026/04/23/driveclub-shadps4-e-ia-como-aprender/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/04/23/driveclub-shadps4-e-ia-como-aprender/</guid><pubDate>Thu, 23 Apr 2026 12:00:00 -0300</pubDate><description>&lt;h2&gt;Onde a gente tava&lt;span class="hx:absolute hx:-mt-20" id="onde-a-gente-tava"&gt;&lt;/span&gt;
&lt;a href="#onde-a-gente-tava" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Na semana passada &lt;a href="https://akitaonrails.github.io/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/"&gt;publiquei sobre o meu setup distrobox-gaming&lt;/a&gt;, com mais de dez jogos de corrida retro rodando em Linux, do Gran Turismo 1 no DuckStation ao Forza Motorsport 4 no Xenia. No fim daquele artigo, falei do Driveclub no shadPS4 como o &amp;ldquo;final boss&amp;rdquo;: o jogo boota, o menu carrega, a corrida começa, o controle responde.&lt;/p&gt;
&lt;p&gt;Só que tinha dois problemas que eu mencionei de passagem e tratei como &amp;ldquo;limitações aceitas&amp;rdquo;:&lt;/p&gt;</description><content:encoded><![CDATA[<h2>Onde a gente tava<span class="hx:absolute hx:-mt-20" id="onde-a-gente-tava"></span>
    <a href="#onde-a-gente-tava" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Na semana passada <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/">publiquei sobre o meu setup distrobox-gaming</a>, com mais de dez jogos de corrida retro rodando em Linux, do Gran Turismo 1 no DuckStation ao Forza Motorsport 4 no Xenia. No fim daquele artigo, falei do Driveclub no shadPS4 como o &ldquo;final boss&rdquo;: o jogo boota, o menu carrega, a corrida começa, o controle responde.</p>
<p>Só que tinha dois problemas que eu mencionei de passagem e tratei como &ldquo;limitações aceitas&rdquo;:</p>
<ol>
<li><strong>De dia, a imagem fica um pouco mais escura do que no PS4 de referência.</strong> Nada alarmante, mas perceptível.</li>
<li><strong>De noite, race start no Canadá ou em Munnar ficava pitch black por 10 a 30 segundos</strong> antes de o jogo &ldquo;se recuperar sozinho&rdquo; perto de 1:30. Durante esses segundos, só o HUD aparecia. Pista, carro, faróis, tudo preto absoluto.</li>
</ol>
<p>No artigo anterior eu empurrei a explicação pra &ldquo;ainda não foi consertado no emulador, vou conviver com isso&rdquo;. Mas por dentro eu não conseguia me aceitar jogando num estado visualmente injogável. Eu queria jogar o Driveclub no melhor que ele podia entregar, e não queria ficar esperando o projeto consertar por mim. Decidi pegar a coisa nas minhas próprias mãos. Um preto absoluto de 30 segundos não é &ldquo;um pouco mais escuro&rdquo;. É um bug grave, dos que tornam o jogo injogável na prática.</p>
<p>Esse artigo é o que aconteceu entre domingo de noite e quinta-feira de manhã.</p>
<h2>O blackout, ao vivo<span class="hx:absolute hx:-mt-20" id="o-blackout-ao-vivo"></span>
    <a href="#o-blackout-ao-vivo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/original-blackout.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Esse vídeo é o comportamento que eu queria consertar. Race start na Índia (Munnar), corrida noturna. Você vê a pista, os faróis aparecem, os primeiros segundos rodam. Depois, escurece progressivamente. Em uns 15 segundos já tá tudo preto. Fica assim por mais uns 60-90 segundos. Aí o jogo &ldquo;recalibra&rdquo; sozinho, e a pista reaparece.</p>
<p>Se você for um jogador, você não quer saber do porquê. Você quer dirigir.</p>
<h2>Por que shadPS4 é difícil de depurar<span class="hx:absolute hx:-mt-20" id="por-que-shadps4-é-difícil-de-depurar"></span>
    <a href="#por-que-shadps4-%c3%a9-dif%c3%adcil-de-depurar" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://shadps4.net/"target="_blank" rel="noopener">shadPS4</a> <strong>ainda não tem release estável</strong>. O projeto tá em desenvolvimento ativo. Main branch muda várias vezes por semana, configs migram de TOML pra JSON sem aviso, settings ficam atrás de &ldquo;Advanced&rdquo; pra não gerar issue de usuário com hardware incompatível, PRs em aberto disputam abordagens diferentes pra o mesmo problema.</p>
<p>Quem tenta configurar Driveclub hoje encontra:</p>
<ul>
<li>Guias de Reddit de setembro/2025 que usam <code>readbacks = true</code> (era bool na época) e dizem &ldquo;pra DriveClub sempre ligar readbacks&rdquo;.</li>
<li>Guias de novembro/2025 que dizem &ldquo;desliga readbacks, mata a performance&rdquo; (porque em 2025-07 readbacks virou enum <code>Disabled | Relaxed | Precise</code>, com perfil de performance diferente, e Bloodborne começou a travar com ele ligado).</li>
<li>Vídeos YouTube de janeiro/2026 com fork customizado que ninguém documentou qual é.</li>
<li>Thread no shadps4.net com três explicações diferentes pro blackout, todas mutuamente exclusivas.</li>
<li>Minhas próprias anotações da semana passada no <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>distrobox-gaming/docs/driveclub-shadps4.md</code></a> dizendo <code>readbacks_mode: 0</code>. Que é exatamente o oposto do que eu descobri essa semana.</li>
</ul>
<p>Ou seja, a informação existe, mas tá espalhada, datada, contraditória, e a maior parte depende de detalhes de versão que mudaram entre a postagem original e hoje. Reproduzir setup via vídeo do YouTube é tentar resolver cubo mágico de olhos vendados.</p>
<h2>Spoiler: a solução é um inteiro<span class="hx:absolute hx:-mt-20" id="spoiler-a-solução-é-um-inteiro"></span>
    <a href="#spoiler-a-solu%c3%a7%c3%a3o-%c3%a9-um-inteiro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois de 31 fases de investigação, 44 commits no meu fork do shadPS4, 15.668 linhas de código instrumental adicionadas e 3 dias de debug quase ininterrupto, a resposta é <strong>uma linha no config por jogo</strong>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;GPU&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;readbacks_mode&#34;</span><span class="p">:</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>readbacks_mode: 2</code> é o modo <code>Precise</code>. Explicar o que isso faz exige entender como o Driveclub implementa auto-exposure, e é aqui que a jornada começa. Pra saber POR QUE esse toggle resolve, você precisa entender a cadeia toda.</p>
<p>O resumo do porquê: o <strong>Driveclub faz auto-exposure como um loop de feedback GPU→CPU</strong>.</p>
<ol>
<li>A cena renderiza num HDR target.</li>
<li>Um compute shader calcula um histograma de luminância num SSBO.</li>
<li>A CPU <strong>lê</strong> esse SSBO no frame seguinte e deriva uma exposição alvo.</li>
<li>A CPU escreve essa exposição de volta num UBO de lighting de 1936 bytes (nos slots <code>[38] [48] [50]</code>).</li>
<li>Os fragment shaders leem esse UBO e multiplicam a luminância da cena por ele.</li>
</ol>
<p>Sem <code>readbacks_mode: Precise</code>, o passo 3 lê zeros obsoletos. A página de memória que o GPU escreveu o histograma nunca é sincronizada pro lado da CPU. O integrator de exposição da CPU conclui &ldquo;a cena tá escura, abrir diafragma ao máximo&rdquo; e rampa o valor de saída monotonicamente: <code>2.59 → 7.84 → 24 → 90 → 179 → 255</code>. Em 60-90 segundos, a escala satura tão alto que tudo clipa pra zero. É esse o pitch black.</p>
<p>Com <code>readbacks_mode: Precise</code> ligado, o emulador marca as páginas que o GPU acabou de escrever como protegidas no nível de kernel (via <code>mprotect</code> no Linux). Quando a CPU tenta ler uma dessas páginas pela primeira vez, dispara uma page fault. O emulador intercepta, emite um <code>vkCmdCopyBuffer</code> download do buffer do GPU pro staging de host, espera no scheduler, e a CPU enfim vê o dado fresco. O histograma verdadeiro entra no integrator, a exposição converge normalmente, e o race start abre brilhante como deveria.</p>
<p>Por que não é o default? Três motivos documentados. Primeiro, per-page <code>mprotect</code> + per-fault GPU stall + compute dispatch + scheduler wait tem custo real: em NVIDIA warm path é tolerável, em AMD derruba pra menos de 12 FPS, <a href="https://github.com/shadps4-emu/shadPS4/issues/3322"target="_blank" rel="noopener">issue aberta</a> a respeito. Segundo, <a href="https://github.com/shadps4-emu/shadPS4/issues/3826"target="_blank" rel="noopener">Bloodborne trava</a> em loading screens com Precise ligado. Terceiro, o maintainer escondeu a opção atrás de &ldquo;Advanced&rdquo; no UI justamente pra evitar que usuário de hardware sensível habilite sem saber. O modo existe desde <code>v0.15.0</code> (setembro/2025), mas <strong>ninguém tinha publicamente conectado <code>Precise</code> + DriveClub + feedback loop de auto-exposure</strong>. O <a href="https://github.com/shadps4-emu/shadPS4/issues/3346"target="_blank" rel="noopener">compat tracker já admite</a> que DriveClub &ldquo;requires readbacks enabled to function properly&rdquo;, mas não especifica o modo.</p>
<p>No meu setup o custo de performance é irrelevante. Tenho uma RTX 5090 no desktop, hardware de sobra pra bancar o mprotect, o page fault, o copy e o stall por frame. A decisão é trivial: ligo Precise, pago o preço, o jogo roda. Num hardware mais modesto ou numa AMD a conversa é outra, e é exatamente por isso que o setting não é default e fica atrás do &ldquo;Advanced&rdquo;.</p>
<p>Importante deixar claro uma coisa: essa explicação toda acima, sobre <code>Precise</code> vs <code>Relaxed</code> vs <code>Disabled</code>, feedback loop GPU→CPU, mprotect syscall por página, não é conhecimento que eu tinha domingo à noite. Eu não sabia o que era um buffer readback, não sabia que Driveclub implementava auto-exposure como feedback loop GPU→CPU, não sabia que <code>readbacks_mode</code> virou um enum em 2025 com três valores. Pra chegar na resposta certa, precisei aprender cada peça do zero. Não dava pra chutar. Se eu tivesse tentado &ldquo;ligar readbacks&rdquo; semana passada sem entender a cadeia, teria pegado o valor errado (Relaxed não basta pra esse feedback loop, explico isso mais pra frente) e desistido achando que &ldquo;não funciona&rdquo;.</p>
<p>E mais duas coisas precisam estar no lugar pra isso funcionar, que já cobri no <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/#driveclub-o-imposs%c3%advel-finalmente-poss%c3%advel">artigo anterior</a>:</p>
<ul>
<li><strong>v1.28 patch aplicado</strong> em cima da install base de v1.00 (sem isso, o conteúdo fica locked com &ldquo;não lançado ainda&rdquo;).</li>
<li><strong>Patch XML de 60fps desabilitado</strong> (render rate subiu mas logic tickrate é fixo; com ele ligado, o jogo roda em câmera lenta).</li>
</ul>
<h2>O resultado<span class="hx:absolute hx:-mt-20" id="o-resultado"></span>
    <a href="#o-resultado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/canada-fixed.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Mesma corrida no Canadá, noturna, com <code>readbacks_mode: 2</code> ligado. Race start abre brilhante, auto-exposure converge imediatamente, a transição pra noite acontece de forma natural conforme o TOD (time of day) do jogo avança. Sem blackout, sem &ldquo;recalibração&rdquo; aos 1:30, sem janela de 30 segundos de preto absoluto. Isso é Driveclub rodando como no PS4.</p>
<p>Agora a pergunta interessante não é &ldquo;qual o setting&rdquo;. É: <strong>como a gente chegou aqui?</strong></p>
<h2>Como um junior aprende hoje?<span class="hx:absolute hx:-mt-20" id="como-um-junior-aprende-hoje"></span>
    <a href="#como-um-junior-aprende-hoje" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem uma pergunta que eu ouço com frequência: &ldquo;com a IA fazendo tudo, como um junior aprende?&rdquo;</p>
<p>A premissa dessa pergunta tá errada. <strong>A IA não faz tudo.</strong> A IA faz o que você pede. Ela não descobre por conta própria. Ela não tem iniciativa de domínio. Ela não é capaz de dizer &ldquo;olha, isso aqui parece um feedback loop quebrado em GPU→CPU readback&rdquo; se você não souber pelo menos que existe uma coisa chamada readback, e que feedback loops quebrados são uma classe de bug.</p>
<p>Pior ainda: se você for num agente de IA hoje e pedir &ldquo;conserta essa tela preta no Driveclub no shadPS4&rdquo;, ele vai te entregar uma lista de respostas possíveis baseada em fóruns antigos, com probabilidade alta de te mandar no caminho errado. Ele vai sugerir patch XML de 60fps (errado, causa slow-motion). Vai sugerir tonemap override (errado, o jogo já escreve SDR correto). Vai sugerir vblank_frequency tweak (inútil pro problema real). Vai sugerir gamma manual (trata o sintoma, não a causa).</p>
<p>O caminho pra descobrir é <strong>mergulhar na cadeia</strong>, fase por fase, descartando hipóteses erradas até o terreno ficar suficientemente conhecido pra você reconhecer a resposta certa quando ela aparece.</p>
<p>E é aí que muita gente se confunde comigo. &ldquo;O Akita já é senior, ele tem 25+ anos de experiência, claro que ele sabe.&rdquo; <strong>Falso.</strong> Profissional senior é alguém que já foi junior em cada tópico que domina. E continua virando junior toda vez que pega um domínio novo. Eu tenho 25 anos de programação web, sistemas distribuídos, Ruby, Erlang, Go. Mas <strong>eu nunca programei pra PS4</strong>. Nunca tinha olhado o codebase do shadPS4. Não conhecia a arquitetura gráfica do PS4. Domingo eu era um absoluto junior nesse domínio.</p>
<p>Junior não é o mesmo que totalmente cru. Em anos anteriores eu já tinha explorado no meu canal a arquitetura low-level de consoles antigos (do 6502 do NES pra cima) e como emuladores funcionam internamente em geral. Os dois vídeos abaixo ajudaram a construir o vocabulário básico de como videogame funciona por dentro, e garantiram que eu não ia tropeçar em conceitos tipo fetch-decode-execute, opcode, interrupt, ou HLE vs LLE.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/hYJ3dvHjeOE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>



<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/vUqLLpUJ47s"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Eu também já tinha feito outro vídeo, mais antigo, sobre a evolução de CPUs, GPUs, DirectX e Vulkan, então pelo menos o vocabulário de &ldquo;pipeline gráfico moderno&rdquo; e &ldquo;shading language&rdquo; não era estranho pra mim.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/JEp7ozWqIps"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Saber que existe <code>VkCommandBuffer</code> é bem diferente de saber onde no shadPS4 um <code>vkCmdCopyBuffer</code> de readback dispara. Mas dá uma base. Esse tipo de curiosidade antiga rendeu juros agora.</p>
<h2>O rodízio: Claude Code e Codex<span class="hx:absolute hx:-mt-20" id="o-rodízio-claude-code-e-codex"></span>
    <a href="#o-rod%c3%adzio-claude-code-e-codex" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A IA (no meu caso o <a href="https://claude.com/claude-code"target="_blank" rel="noopener">Claude Code</a>) não &ldquo;sabia&rdquo; mais que eu. Ela tem o mesmo texto de fórum datado que você achou no Reddit. O que ela fazia bem era <strong>agregar</strong>: ler o código do shadPS4 em paralelo comigo, indexar os comentários, cruzar referências entre phase docs, compilar, rodar probes, parsear logs de 61 MB, comparar binário decompilado com o diff de UBO, jogar luz em cantos do sistema mais rápido do que eu sozinho conseguiria.</p>
<p>Mas a decisão de &ldquo;continuar investigando&rdquo; era minha. A perseverança de &ldquo;não aceita uma mitigação, quer a causa-raiz&rdquo; era minha. E quando a IA sugeria &ldquo;honestly, we should just accept the current result and document it&rdquo; (e ela sugeriu <strong>várias vezes</strong> ao longo dos quatro dias), eu era o que tinha que dizer &ldquo;não, continuamos&rdquo;.</p>
<p>O ponto central do rodízio: <strong>nenhum LLM sozinho conseguiu fechar esse problema.</strong></p>
<p>Ao longo dos quatro dias, várias vezes o Claude Code entrou em loop, repetindo as mesmas hipóteses sem rumo novo. Quando isso acontecia, eu trocava pro Codex por algumas horas pra trazer ideias de fora, probes diferentes, releitura do codebase por ângulo novo. Depois voltava pro Claude Code pra integrar o que o Codex tinha levantado. E assim por diante, alternando.</p>
<p>A resolução final aconteceu no Claude Code, mas a jornada trocou de modelo várias vezes. Cada LLM tinha seus viéses e seus pontos cegos. Deixado sozinho, cada um teria desistido antes.</p>
<p>O que rompeu o impasse foi eu continuar trazendo novas ideias pra tentar, forçando o modelo a reavaliar, trocando quando um deles começava a repetir.</p>
<p>Em dois momentos a coisa foi além de &ldquo;só repetir hipóteses&rdquo;. O Codex literalmente teve um glitch em loop agêntico: começou a repetir a mesma &ldquo;solução&rdquo; que tinha acabado de tentar, de novo e de novo, em sequência, sem perceber o que estava fazendo. Foi a primeira vez que eu vi isso acontecer em qualquer agente de IA. Tive que matar a sessão e começar uma nova do zero pra quebrar o ciclo.</p>
<p>Isso diz muito sobre o tamanho de contexto e a duração da sessão. A complexidade e o ritmo dessa investigação foi suficiente pra derrubar os dois LLMs, cada um do seu jeito.</p>
<p>Toda a jornada abaixo está documentada em 33 phase docs no branch <a href="https://github.com/akitaonrails/shadPS4/tree/gamma-debug/docs/driveclub-investigation"target="_blank" rel="noopener"><code>gamma-debug</code> do meu fork do shadPS4</a>. Cada seção aqui linka pro doc original pra quem quiser o detalhe completo. Aqui eu resumo o essencial: a hipótese que tínhamos, o que tentamos, o que aprendemos de novo, e por que essa fase não fechou o caso.</p>
<h2>Sessão zero: baseline e reprodutibilidade<span class="hx:absolute hx:-mt-20" id="sessão-zero-baseline-e-reprodutibilidade"></span>
    <a href="#sess%c3%a3o-zero-baseline-e-reprodutibilidade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Toda investigação séria começa antes da Fase 1. A primeira coisa, pra qualquer projeto, é garantir que o <strong>baseline funciona como esperado</strong> e que a situação que você quer pesquisar é <strong>reproduzível toda vez</strong>. Se você não consegue reproduzir o bug por comando, tá caçando fantasma. Cada probe depois vai ser inconclusivo porque o bug &ldquo;apareceu e sumiu&rdquo; sem controle. E se o baseline tá quebrado de algum jeito que você nem percebeu, cada experimento mede o problema errado. Sem essas duas garantias, não tem como progredir.</p>
<p>No meu caso, domingo à noite confirmei:</p>
<ul>
<li>O jogo boota até a tela de corrida sem crash, usando a config da <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>distrobox-gaming</code></a>.</li>
<li><a href="https://github.com/Nenkai/DriveClubFS"target="_blank" rel="noopener">DriveClubFS</a> extrai v1.28 limpo, 8018 arquivos, ~47 GB.</li>
<li>MSAA depth resolve aplicado no fork, pistas noturnas renderizam forma em vez de uniforme preto absoluto (isso está coberto no <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/">artigo anterior</a>).</li>
<li>Controle 8BitDo detectado.</li>
<li>Corrida noturna na Índia 19:30 <strong>reproduz o blackout em 100% das tentativas</strong>, no mesmo padrão temporal: fade progressivo nos primeiros ~15s, pitch black entre ~20s e ~90s, &ldquo;recalibração&rdquo; aos 1:30.</li>
</ul>
<p>Esse baseline é a única base sólida que me permite comparar cada experimento de forma confiável. Sem ele, um probe que &ldquo;funcionou&rdquo; pode ser só um cache diferente, não o fix real. Com ele, cada mudança tem um antes e um depois que são mensuráveis.</p>
<p>Fora isso, zero conhecimento específico de:</p>
<ul>
<li>Formato de PKG do PS4 (PFS, param.sfo, disc_info, keystone).</li>
<li>Codebase do shadPS4 (src/core, src/video_core, shader_recompiler, buffer_cache).</li>
<li>Pipeline gráfico do PS4 (GCN ISA, forward+ lighting, MSAA depth resolve).</li>
<li>Vulkan além do superficial (descriptor sets, UBO binding, push constants, pipeline cache).</li>
<li>SPIR-V disassembly e patching.</li>
<li>PS4 OELF loader, Itanium RTTI, SCE dynamic relocations.</li>
<li>mprotect-based page-fault tracking pra CPU-GPU synchronization.</li>
</ul>
<h2>A jornada em fases<span class="hx:absolute hx:-mt-20" id="a-jornada-em-fases"></span>
    <a href="#a-jornada-em-fases" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Vou organizar as 30+ fases em grupos que fazem sentido como narrativa. Cada fase linka pro doc completo pra quem quiser o detalhe técnico.</p>
<blockquote>
  <p><strong>Nota pra quem não quiser ler todas as 30+ fases:</strong> depois da sequência de fases tem seções de reflexão e metodologia que dá pra ler direto. <a href="#a-t%c3%a9cnica-do-shotgun">A técnica do shotgun</a> explica a metodologia de depuração que usei ao longo da investigação. <a href="#o-que-eu-sabia-domingo-vs-quinta">O que eu sabia domingo vs quinta</a> resume o que aprendi de fato. <a href="#a-ia-sugeria-aceitar-a-perseveran%c3%a7a-humana-foi-minha">A IA sugeria aceitar. A perseverança humana foi minha</a> discute o papel real da IA nesse processo. <a href="#custo-real-dessa-jornada">Custo real dessa jornada</a> cataloga o que foi gerado. Se quiser pular direto pro argumento, esses são os atalhos.</p>

</blockquote>
<h3>Fase 01: pipeline cache, o warm-up<span class="hx:absolute hx:-mt-20" id="fase-01-pipeline-cache-o-warm-up"></span>
    <a href="#fase-01-pipeline-cache-o-warm-up" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-01-shader-compile-stalls.md"target="_blank" rel="noopener"><code>phase-01-shader-compile-stalls.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> menus rodam a 2-3 fps no primeiro launch, deve ser compilação de pipelines Vulkan acontecendo em tempo real.</li>
<li><strong>Ação:</strong> ligar <code>pipeline_cache_enabled: true</code> no config global.</li>
<li><strong>Conceito novo:</strong> cache de pipelines Vulkan. Quando o emulador traduz um shader GCN do PS4 pra SPIR-V e depois em binário Vulkan específico do driver, ele pode cachear esse binário. Sem cache, recompila cada cold launch (~864 shaders + ~590 pipelines).</li>
<li><strong>Resultado:</strong> resolvido. Primeira sessão paga o custo; sessões seguintes leem do disk e sobem imediatas. Fácil. Também foi minha primeira lição sobre o codebase do shadPS4.</li>
</ul>
<h3>Fase 02: gamma dim, começando pela direção errada<span class="hx:absolute hx:-mt-20" id="fase-02-gamma-dim-começando-pela-direção-errada"></span>
    <a href="#fase-02-gamma-dim-come%c3%a7ando-pela-dire%c3%a7%c3%a3o-errada" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-02-gamma-dim-image.md"target="_blank" rel="noopener"><code>phase-02-gamma-dim-image.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> imagem do Driveclub tá dim comparada com referência. Deve ser sRGB encode errado, ou HDR tonemap mal aplicado pelo emulador.</li>
<li><strong>Ação:</strong> instrumentei a swapchain pra logar formato; adicionei env var <code>SHADPS4_PP_*</code> pra experimentar; montei pipeline de pós-processamento com três knobs (exposure, ACES tonemap, gamma curve).</li>
<li><strong>Conceito novo:</strong> sRGB OETF, HDR tonemap (ACES vs Reinhard), Bayer dither como anti-banding.</li>
<li><strong>Resultado:</strong> descobri via bypass path (<code>SHADPS4_PP_BYPASS=1</code>, escreve raw game output sem nenhum pós-processamento) que o <strong>jogo escreve SDR já correto</strong> no framebuffer. O pipeline de pós-processamento do emulador é que estava estragando o sinal. Shader final virou simplesmente sRGB encode + Bayer dither. Dim persiste, mas não é culpa de gamma.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/wrong-gamma.png" alt="Ajustes de gamma errando pra todo lado"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/wrong-gamma-blown.png" alt="Blown out: gamma em cima"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/wrong-gamma-sky-dark.png" alt="Céu escuro: gamma pra baixo"  loading="lazy" /></p>
<p>Três horas nessa fase. A lição mais importante é: <strong>quando &ldquo;a imagem tá estranha&rdquo;, o primeiro diagnóstico deveria ser um bypass path que mostra o raw game output</strong>. Se bypass tá certo, o emulador tá estragando o sinal. Pare de mexer no tonemap.</p>
<h3>Fase 03: v1.28 content access<span class="hx:absolute hx:-mt-20" id="fase-03-v128-content-access"></span>
    <a href="#fase-03-v128-content-access" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-03-v128-content-access.md"target="_blank" rel="noopener"><code>phase-03-v128-content-access.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> v1.28 extrai, mas o jogo diz &ldquo;content not released yet, download required&rdquo;.</li>
<li><strong>Ação:</strong> merge v1.28 em cima de v1.00, restaurar <code>param.sfo</code>, <code>disc_info.dat</code>, <code>keystone</code>.</li>
<li><strong>Conceito novo:</strong> PS4 cumulative patches, metadata do package.</li>
<li><strong>Resultado:</strong> resolvido. Detalhado no <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/">artigo anterior</a>.</li>
</ul>
<h3>Fase 04: MSAA depth + slow-motion<span class="hx:absolute hx:-mt-20" id="fase-04-msaa-depth--slow-motion"></span>
    <a href="#fase-04-msaa-depth--slow-motion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-04-slowness.md"target="_blank" rel="noopener"><code>phase-04-slowness.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> pistas à noite pitch black e o jogo &ldquo;parece lento&rdquo;.</li>
<li><strong>Ação:</strong> duas coisas separadas. Desabilitar patch XML de 60fps (que tava descolando render rate do logic tickrate). Implementar <code>ReinterpretMsDepthAsColor</code> no meu fork (pra permitir que o emulador resolva depth MSAA 4x pra color 1-sample, que o Driveclub precisa pro forward+ lighting nas pistas noturnas).</li>
<li><strong>Conceito novo:</strong> forward+ lighting (renderer que escreve cena em MSAA depth target e depois lê como color pra SSAO e volumetrics), MSAA depth resolve.</li>
<li><strong>Resultado:</strong> dois problemas resolvidos. Detalhado no <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/">artigo anterior</a>.</li>
</ul>
<h3>Fase 05: second pass no brilho<span class="hx:absolute hx:-mt-20" id="fase-05-second-pass-no-brilho"></span>
    <a href="#fase-05-second-pass-no-brilho" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-05-brightness-followup.md"target="_blank" rel="noopener"><code>phase-05-brightness-followup.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> já que o game escreve SDR correto, talvez um boost estático no pós-processamento ajude sem mexer em UBO feedback.</li>
<li><strong>Ação:</strong> testei linear boost (1.5x, 2.0x), gamma pre-encode (pow curve), auto-exposure cena-aware com peak+mean sampling.</li>
<li><strong>Resultado:</strong> tudo rollback. Linear boost clipa luz. Gamma introduz banding. Auto-exposure da minha camada cancela o slider manual do usuário. Não tem almoço grátis no pós-processamento. Imagem dim fica dim sem HDR real ou patch de shader.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/wrong-gamma-sky-dark.png" alt="Céu escuro demais"  loading="lazy" /></p>
<h3>Narrowing the blackout: o gate compartilhado<span class="hx:absolute hx:-mt-20" id="narrowing-the-blackout-o-gate-compartilhado"></span>
    <a href="#narrowing-the-blackout-o-gate-compartilhado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/race-start-blackout-040420.md"target="_blank" rel="noopener"><code>race-start-blackout-040420.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> o blackout tem uma assinatura curiosa: main view vai pra dim/preto, retrovisor vai pra preto absoluto, HUD permanece brilhante. Três camadas com comportamentos diferentes sugerem um &ldquo;gate&rdquo; compartilhado, não um fade comum.</li>
<li><strong>Ação:</strong> instrumentei texture-cache aliasing, probes com live fragment shader substitution nos inputs suspeitos.</li>
<li><strong>Conceito novo:</strong> texture-cache aliasing (várias imagens com mesmo endereço de memória, cache do emulador reusa), render-target lifetime.</li>
<li><strong>Resultado:</strong> aponta pra &ldquo;permissão de apresentação&rdquo; compartilhada entre main scene e retrovisor, não um fade narrativo.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/screenshot-2026-04-20_21-22-45.png" alt="Baseline do blackout"  loading="lazy" /></p>
<h3>Fases 07-09: tortura de texturas, cirurgia de UI, plano de binary patch<span class="hx:absolute hx:-mt-20" id="fases-07-09-tortura-de-texturas-cirurgia-de-ui-plano-de-binary-patch"></span>
    <a href="#fases-07-09-tortura-de-texturas-cirurgia-de-ui-plano-de-binary-patch" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-07-aggressive-torture-probe.md"target="_blank" rel="noopener"><code>phase-07-aggressive-torture-probe.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-08-ui-asset-surgery.md"target="_blank" rel="noopener"><code>phase-08-ui-asset-surgery.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-09-eboot-binary-patch-plan.md"target="_blank" rel="noopener"><code>phase-09-eboot-binary-patch-plan.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> o overlay dim do race start é um asset. Textura pequena, panel da UI, ou método do controller <code>FreeplayGetInCar</code> no eboot.</li>
<li><strong>Ação:</strong> null-substituir materiais BC comprimidos, textures pequenas candidatas, four-vector weight masks durante draws críticos. Desabilitar painéis da UI (<code>loading_freeplay.txt</code>, <code>get_in_car_animation.txt</code>, <code>vehicle_select_background</code>). Extrair o OELF, localizar strings ASCII <code>FreeplayGetInCar</code>, identificar construtor em VA 0xf89b00 e vtable em 0x15dc3e0.</li>
<li><strong>Conceito novo:</strong> PS4 OELF loader (variant do ELF da Sony), Itanium C++ RTTI (como C++ encoda type info em vtables), SCE dynamic relocations (placeholders que só o loader dinâmico resolve em runtime).</li>
<li><strong>Resultado:</strong> nulls funcionam mas o fade persiste. O overlay renderiza direto nos HDR scene targets, não via panel system. Binary patch tem placeholder de relocation que não é resolvível estaticamente sem um Ghidra com PS4 plugin. <strong>Asset-side surface exhausted.</strong> Seis horas depurando, final conclusion: o bug vive em state, não em asset.</li>
</ul>
<h3>Fase 10: rethink + animlib<span class="hx:absolute hx:-mt-20" id="fase-10-rethink--animlib"></span>
    <a href="#fase-10-rethink--animlib" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-10a-rethink-040422.md"target="_blank" rel="noopener"><code>phase-10a-rethink-040422.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-10b-video-diagnostic-animlib.md"target="_blank" rel="noopener"><code>phase-10b-video-diagnostic-animlib.md</code></a></p>

</blockquote>
<p>Terça-feira de manhã. Sentei, reiniciei mentalmente. Modelo novo: o blackout é um <strong>state-machine gate</strong>. Não é &ldquo;cena não pronta&rdquo;, é &ldquo;permission transition&rdquo;. O gate fecha depois da grid de largada aparecer. Próximo probe: runtime dispatch trace, chega de blind asset surgery.</p>
<p>Em paralelo: extração de frame da gravação de vídeo a 10 Hz, cruzamento com keyframes de animation library (<code>animlib</code>) em <code>india_posteffects.lvl</code>. Encontramos smoking gun. Track <code>MasterBrightness</code> com keyframe 0.003 e 0.0007 (0.63% brightness), quando o default seria 1.0. Animlib vence inline defaults todo frame.</p>
<ul>
<li><strong>Conceito novo:</strong> animation library, keyframe encoding, float-scanning de binário.</li>
</ul>
<video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/debugging-blackout-fade.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Vídeo acima: o processo de probar pelo fade em real time.</p>
<h3>Fase 11: multi-scalar patch<span class="hx:absolute hx:-mt-20" id="fase-11-multi-scalar-patch"></span>
    <a href="#fase-11-multi-scalar-patch" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-11-multi-scalar-patch.md"target="_blank" rel="noopener"><code>phase-11-multi-scalar-patch.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> patchar <code>MasterBrightness</code> + <code>AutoTargetLuminance</code> + <code>ManualAutoMix</code> simultaneamente vai lift o blackout.</li>
<li><strong>Ação:</strong> estendi <code>PatchAnimlibFloatValues</code> pra reescrever três scalars. Instrumentei com <code>SHADPS4_DC_DRAWLOG</code> + <code>SHADPS4_DC_UBOLOG</code>.</li>
<li><strong>Resultado:</strong> patch produz um lift <strong>numérico</strong> real (1.2 → 6.5 em 255, um 5×), mas ainda é sub-perceptual black. E descobri o achado crucial: o mirror funciona normalmente após o patch. Não está gated, apenas refletindo uma cena escura. <strong>Pelo menos 285× de atenuação adicional vive downstream dos scalars que a gente pode patchar.</strong></li>
</ul>
<h3>Fase 12: bisect fechando o asset-side<span class="hx:absolute hx:-mt-20" id="fase-12-bisect-fechando-o-asset-side"></span>
    <a href="#fase-12-bisect-fechando-o-asset-side" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-12-bisect-closes-asset-side.md"target="_blank" rel="noopener"><code>phase-12-bisect-closes-asset-side.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> um dos 60 patches acumulados quebrou o mirror independente do blackout. Bisect.</li>
<li><strong>Ação:</strong> binary bisect em 60 overlay files ao longo de 5 rounds.</li>
<li><strong>Resultado:</strong> <code>x_live_lobby_pre_race.txt</code> (reroute de loading-spinner transition de <code>ZoomInAndFade</code> pra <code>NoFade</code>) era o mirror killer. Rollback. <strong>Asset-side completamente fechado.</strong> O driver vive em código compilado ou em post-process state, não em asset de jogo.</li>
</ul>
<h3>Asset sweeps 01-09 (consolidado)<span class="hx:absolute hx:-mt-20" id="asset-sweeps-01-09-consolidado"></span>
    <a href="#asset-sweeps-01-09-consolidado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/asset-sweep-09-conclusions.md"target="_blank" rel="noopener"><code>asset-sweep-09-conclusions.md</code></a></p>

</blockquote>
<p>Em paralelo com as fases acima, varri 12 RPK substitutions: page swaps de <code>FreeplayGetInCar</code>, mexidas no postfx de <code>india_landscape_gui.rpk</code>, edits em <code>globaldata</code> RTT-only, rewrites de prerace state strings. <strong>Todos clean misses.</strong> Nenhuma família de asset toca o blackout. Lição: <strong>pare de chasing by names; chase por state transitions.</strong></p>
<h3>Fase 13: UBO dump breakthrough<span class="hx:absolute hx:-mt-20" id="fase-13-ubo-dump-breakthrough"></span>
    <a href="#fase-13-ubo-dump-breakthrough" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-13-ubo-dump-breakthrough.md"target="_blank" rel="noopener"><code>phase-13-ubo-dump-breakthrough.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> loop de feedback de eye-adaptation com input stale é o culpado. Um scalar de luminância crescendo sem convergir.</li>
<li><strong>Ação:</strong> dump de 128 bytes de UBO em hex durante a race window, em seis pipelines hand-picked. Procurar valores monotonicamente em mudança.</li>
<li><strong>Conceito novo:</strong> <strong>UBO (Uniform Buffer Object)</strong>, região de memória compartilhada que o CPU escreve e shaders leem. <strong>Auto-exposure integrator</strong>, componente clássico de eye adaptation que tira tempo pra convergir em direção a um target.</li>
<li><strong>Resultado:</strong> encontrei. <strong>Offset 3 do UBO sobe monotonicamente de 2.59 → 7.84 → 24 → 90 → 179 → 255</strong> em 2 segundos. Textbook feedback loop com input quebrado. Primeiro hit real em 12 fases.</li>
</ul>
<h3>Fase 14: scene-pipeline UBOs são o read-side<span class="hx:absolute hx:-mt-20" id="fase-14-scene-pipeline-ubos-são-o-read-side"></span>
    <a href="#fase-14-scene-pipeline-ubos-s%c3%a3o-o-read-side" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-14-scene-pipeline-ubos-wrong.md"target="_blank" rel="noopener"><code>phase-14-scene-pipeline-ubos-wrong.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> clampar o scalar que tá subindo vai parar o blackout.</li>
<li><strong>Ação:</strong> <code>SHADPS4_DC_LUM_CLAMP=2.0</code> força offset 3 a um valor fixo durante race window.</li>
<li><strong>Resultado:</strong> clamp dispara 1093 vezes, blackout inalterado. Scene-pipeline UBOs <strong>consomem</strong> o dim, não produzem. Dim tá upstream, em um tonemap ou post-fx compute fullscreen.</li>
</ul>
<h3>Fases 15-16: runtime texture dump + mutation<span class="hx:absolute hx:-mt-20" id="fases-15-16-runtime-texture-dump--mutation"></span>
    <a href="#fases-15-16-runtime-texture-dump--mutation" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-15-runtime-texture-dump.md"target="_blank" rel="noopener"><code>phase-15-runtime-texture-dump.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-16-runtime-texture-mutation.md"target="_blank" rel="noopener"><code>phase-16-runtime-texture-mutation.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> o blackout é uma textura fullscreen composta sobre a cena.</li>
<li><strong>Ação:</strong> <code>SHADPS4_DC_TEX_DUMP=1</code> dumpa todas as texturas bound durante race window (1079 texturas capturadas). Converter tiled-format pra PNG pra triagem visual. Depois, mutar deterministicamente cada textura via hash-based tint + <code>InvalidateMemory</code> pra forçar re-upload.</li>
<li><strong>Conceito novo:</strong> <strong>GCN tile format</strong> (Sony interleava bytes de forma específica pra cache locality), texture de-swizzle, buffer cache invalidation.</li>
<li><strong>Resultado:</strong> 14 rounds de mutação (BC textures, float data, render targets, UI atlases, post-fx buffers, LUTs). Blackout <strong>inalterado em todos</strong>. Texture content 100% descartado como source.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/blue-ish-overlay.png" alt="Overlay azul durante mutação"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/green-ish-overlay.png" alt="Overlay verde durante mutação"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/reflections-glitching-blown.png" alt="Reflections glitched"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/reflections-glitched-blown-white.png" alt="Reflections blown white"  loading="lazy" /></p>
<h3>Fases 17-19: UBO smashing, push-constant smashing, compute dispatch probe<span class="hx:absolute hx:-mt-20" id="fases-17-19-ubo-smashing-push-constant-smashing-compute-dispatch-probe"></span>
    <a href="#fases-17-19-ubo-smashing-push-constant-smashing-compute-dispatch-probe" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-17-ubo-batch-smashing.md"target="_blank" rel="noopener"><code>phase-17-ubo-batch-smashing.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-18-push-constant-smashing.md"target="_blank" rel="noopener"><code>phase-18-push-constant-smashing.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-19-compute-dispatch-probe.md"target="_blank" rel="noopener"><code>phase-19-compute-dispatch-probe.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> random-fill em UBOs, push constants e compute input buffers pode bracket and isolate o field do dim sem crashar.</li>
<li><strong>Ação:</strong> <code>SHADPS4_DC_UBO_SMASH=1</code>, <code>SHADPS4_DC_PC_SMASH=1</code>, <code>SHADPS4_DC_DISPATCH_SMASH=1</code> com filtros de cb-index e size.</li>
<li><strong>Conceito novo:</strong> <strong>push constants</strong> (128 bytes de param rápido que o driver empurra direto pro pipeline, sem descriptor), <strong>compute dispatches</strong> (dispara compute shaders com uma grid de threads), <strong>ud_regs</strong> (user data registers do GCN, como shadPS4 mapeia user-data pra push-constants).</li>
<li><strong>Resultado:</strong> brackets seguros geram overlay bokeh + blinks, mas dim inalterado. Brackets wide o suficiente pra pegar o dim também pegam matrices/transforms e crasham. <strong>Random-fill é instrumento errado.</strong> Precisa de diff methodology.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/all-bege.png" alt="Tudo bege depois de smash"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/all-green.png" alt="Tudo verde"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/all-cyan.png" alt="Tudo ciano"  loading="lazy" /></p>
<h3>Fase 19b-c: dim-vs-lift dispatch diff<span class="hx:absolute hx:-mt-20" id="fase-19b-c-dim-vs-lift-dispatch-diff"></span>
    <a href="#fase-19b-c-dim-vs-lift-dispatch-diff" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-19b-dim-vs-lift-diff.md"target="_blank" rel="noopener"><code>phase-19b-dim-vs-lift-diff.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-19c-dispatch-draw-skip-null.md"target="_blank" rel="noopener"><code>phase-19c-dispatch-draw-skip-null.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> compute dispatches que firam só durante dim (e param depois do lift) fazem parte do chain.</li>
<li><strong>Ação:</strong> dividir log limpo em pre / dim / bright windows (via user wall-clock), contar dispatch frequency por pipeline.</li>
<li><strong>Resultado:</strong> identificamos <strong>8 compute pipelines</strong> (histogram 256→downsamples, tile-grid reductions, auto-exposure 1x1 scalars) que param exatamente quando dim lifts. Shapes fortemente sugerem eye-adaptation chain. <strong>First genuine diagnostic hit.</strong> Skip test dessas 8 + 101 draws correlacionados: blackout <strong>inalterado</strong>. Elas são <strong>downstream effects</strong>, não drivers.</li>
</ul>
<h3>Fase 20-21: tonemap inline, fragment → flip buffer<span class="hx:absolute hx:-mt-20" id="fase-20-21-tonemap-inline-fragment--flip-buffer"></span>
    <a href="#fase-20-21-tonemap-inline-fragment--flip-buffer" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-20-shader-dump-tonemap-inline.md"target="_blank" rel="noopener"><code>phase-20-shader-dump-tonemap-inline.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-21-fragment-to-flip-buffer.md"target="_blank" rel="noopener"><code>phase-21-fragment-to-flip-buffer.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> o auto-exposure compute shader tá quebrado, ou o tonemap compute tá com a matemática errada.</li>
<li><strong>Ação:</strong> recompilar todos os shaders, dumpar SPIR-V, desmontar o histogram auto-exposure. Patchar a saída dele pra constante 1.0 e testar.</li>
<li><strong>Conceito novo:</strong> <strong>SPIR-V disassembly</strong> (formato intermediário do Khronos, tem assembly legível). <strong>Verificação de shader compute</strong>. Depois, <strong>pipeline-to-shader mapping</strong>.</li>
<li><strong>Resultado:</strong> patch <strong>sem efeito</strong>. Descoberta: <strong>Driveclub não tem tonemap pass separada</strong>. Scene geometry escreve direto no flip buffer, com exposure inline nos material shaders. Cada material shader bake o scalar de dim de um UBO compartilhado. Pipeline cache wipe + <code>SHADPS4_DC_PIPEMAP=1</code> dumpa todos os pipeline→shader mappings. Filtrar drawlog por pipelines que escrevem em <code>0x5000900000</code> / <code>0x5000108000</code> (os swapchain buffers de verdade) resulta em <strong>14 pipelines únicos</strong>. Zero com Exp2/Log2 tonemap ops. Exposure é aplicada upstream.</li>
</ul>
<h3>Fase 22: tonemap compute identified<span class="hx:absolute hx:-mt-20" id="fase-22-tonemap-compute-identified"></span>
    <a href="#fase-22-tonemap-compute-identified" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-22-tonemap-compute-identified.md"target="_blank" rel="noopener"><code>phase-22-tonemap-compute-identified.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> entre os 510 compute shaders do jogo, um deles tem assinatura de tonemap (muitos Exp2/Log2).</li>
<li><strong>Ação:</strong> scan automatizado, cross-reference com dispatchlog.</li>
<li><strong>Resultado:</strong> <strong><code>cs_0x2c918c06</code></strong> é o candidato forte, com 8 Exp2 + 8 Log2, 5 SSBOs (scene params, TAA, bloom, camera, exposure), 11 images. Skip test pra esse pipeline específico: <strong>para o blackout cycle</strong>, remove color grading, introduz temporal ghosting. <strong>Esse é o caminho final scene→swapchain pra tonemap.</strong></li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/temporal-glitching.png" alt="Temporal ghosting depois do skip"  loading="lazy" /></p>
<h3>Fase 22+: tonemap patches → playable<span class="hx:absolute hx:-mt-20" id="fase-22-tonemap-patches--playable"></span>
    <a href="#fase-22-tonemap-patches--playable" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-22plus-tonemap-compute-patches.md"target="_blank" rel="noopener"><code>phase-22plus-tonemap-compute-patches.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> dois SPIR-V surgical edits (histogram no-op + tonemap exposure clamp/boost) deixam o jogo jogável.</li>
<li><strong>Ação:</strong> patch de histogram pra nunca atualizar; patch de tonemap pra clampar exposure floor em 0.5 e boost blend por ×10. Ambos via SPIR-V patching + shader/patch/ drop-in.</li>
<li><strong>Resultado:</strong> <strong>playable!</strong> Dim reduz de pitch black pra mild. É uma <strong>mitigação real, não fix de causa-raiz.</strong> A fade curve ainda arrasta a exposição, e cada pista precisa de tuning per-threshold.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/blown-just-track-lights.png" alt="Luzes da pista explodindo após ×10 boost"  loading="lazy" /></p>
<video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/india-gamma-correction-attempt.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Aqui a IA sugeriu parar pela primeira vez. <strong>&ldquo;O jogo tá playable, isso é uma mitigação decente, deveríamos documentar e aceitar.&rdquo;</strong> Eu pressionei: &ldquo;tá playable mas tá errado. Não aceita. Continuamos.&rdquo;</p>
<h3>Fase 23: CPU-side exposure intercept<span class="hx:absolute hx:-mt-20" id="fase-23-cpu-side-exposure-intercept"></span>
    <a href="#fase-23-cpu-side-exposure-intercept" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-23-cpu-exposure-intercept.md"target="_blank" rel="noopener"><code>phase-23-cpu-exposure-intercept.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> clampar o exposure scalar no momento do <code>BindBuffers</code> da tonemap compute previne o over-dimming.</li>
<li><strong>Ação:</strong> <code>SHADPS4_DC_EXPOSURE_PIN=1</code> intercepta <code>BindBuffers</code>, sobrescreve exposure offsets com clamp-min threshold, invalidate buffer_cache.</li>
<li><strong>Conceito novo:</strong> <strong>CPU-GPU buffer binding</strong> (momento em que o CPU entrega descriptor pro GPU). <strong>Buffer cache invalidation</strong> (como o emulator mantém consistency entre o estado CPU-side e GPU-side de um buffer).</li>
<li><strong>Resultado:</strong> scalar oscila no race start, depois sobe monotonicamente. Per-track tuning necessário. A Índia quer 3.0, o Canadá blows out no mesmo threshold. <strong>Solução de scalar único não converge cross-track.</strong></li>
</ul>
<video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/debugging-cli-gamma-correction.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<h3>Fase 24: dim upstream of tonemap<span class="hx:absolute hx:-mt-20" id="fase-24-dim-upstream-of-tonemap"></span>
    <a href="#fase-24-dim-upstream-of-tonemap" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-24-dim-upstream-of-tonemap.md"target="_blank" rel="noopener"><code>phase-24-dim-upstream-of-tonemap.md</code></a></p>

</blockquote>
<ul>
<li><strong>Conclusão:</strong> depois de toda a cadeia de probes (identity tonemap, exposure pin, compute skip), o dim <strong>está no HDR target antes</strong> do tonemap ler. Três upstream suspects: (1) atmospheric scattering / volumetric fog, (2) reflection-probe / envmap update, (3) pre-tonemap exposure apply.</li>
<li><strong>Conceito novo:</strong> <strong>atmospheric scattering</strong> (simulação de como luz viaja pela atmosfera, tipo Rayleigh/Mie), <strong>volumetric fog</strong> (neblina renderizada como froxel volume).</li>
<li><strong>Resultado:</strong> plano definido. Frame-order dump, andar pra trás da tonemap pela cadeia toda.</li>
</ul>
<h3>Fase 25: frame-order trace<span class="hx:absolute hx:-mt-20" id="fase-25-frame-order-trace"></span>
    <a href="#fase-25-frame-order-trace" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-25-frameorder-trace.md"target="_blank" rel="noopener"><code>phase-25-frameorder-trace.md</code></a></p>

</blockquote>
<ul>
<li><strong>Ação:</strong> <code>SHADPS4_DC_FRAMEORDER=&lt;N&gt;</code> loga strict per-submit pipeline/shader chain sobre N submits durante race window.</li>
<li><strong>Conceito novo:</strong> <strong>frame-order reconstruction</strong> (listar toda submission ao GPU em ordem exata), <strong>froxel volumetrics</strong> (volume frustum voxels, malha 3D alinhada ao frustum da câmera pra armazenar info de luz).</li>
<li><strong>Resultado:</strong> três suspeitos: (A) half-res compute <code>(60,34,1)</code>, provavelmente SSAO; (B) dispatches progressive <code>(256,1,1)→(2560,1,1)→(10240,1,1)</code>, froxel volumetric; (C) draw fullscreen apply-fog-to-HDR. <strong>Suspeito B</strong> é o mais forte (sunset best-fit, per-pixel non-uniform dim).</li>
</ul>
<h3>Fase 26: O UBO fade pin, o &ldquo;aha moment&rdquo;<span class="hx:absolute hx:-mt-20" id="fase-26-o-ubo-fade-pin-o-aha-moment"></span>
    <a href="#fase-26-o-ubo-fade-pin-o-aha-moment" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-26-ubo-fade-pin.md"target="_blank" rel="noopener"><code>phase-26-ubo-fade-pin.md</code></a></p>

</blockquote>
<p>Aqui mudou tudo.</p>
<ul>
<li><strong>Hipótese:</strong> memory diff direto (bright vs dim vs recovered) identifica os bytes exatos que o jogo escreve pra controlar o blackout.</li>
<li><strong>Ação:</strong> capturar snapshots periódicos de UBO através das transições visuais. Diffar três snapshots byte por byte. Procurar fade signatures.</li>
<li><strong>Conceito novo:</strong> <strong>state diff methodology</strong>. Ao invés de &ldquo;qual passagem parece suspeita?&rdquo;, perguntar &ldquo;quais bytes realmente mudam com o estado visual?&rdquo;</li>
<li><strong>Resultado:</strong> <strong>breakthrough.</strong> Dois UBOs controlam o fade: um de 1936 bytes com slots <code>[38/48/50]</code> (light intensity) sendo multiplicados por 0.094 (fade factor), e um sun UBO de 224 bytes com slot <code>[50]</code> caindo 97%. Pinar os dois: race start abre brilhante. TOD animation intacta. Content-aware three-state lifecycle (idle → engaged → expired).</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/touching-sun-light.png" alt="Primeiro toque no UBO de sun light"  loading="lazy" /></p>
<p>Quarta-feira à noite. Claude sugere parar de novo. <strong>&ldquo;Temos pin funcionando, three-state lifecycle robusto, Canadá + Munnar rodando. Isso é upstream-quality, deveríamos PR-ar e fechar.&rdquo;</strong> Eu insisto: &ldquo;ainda tem dim residual em outras pistas, não tá fechado. Continuamos.&rdquo;</p>
<h3>Fase 28: pivot pra emulator code<span class="hx:absolute hx:-mt-20" id="fase-28-pivot-pra-emulator-code"></span>
    <a href="#fase-28-pivot-pra-emulator-code" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-28-pivot-to-emulator-code.md"target="_blank" rel="noopener"><code>phase-28-pivot-to-emulator-code.md</code></a></p>

</blockquote>
<ul>
<li><strong>Realização:</strong> o dim residual no Canadá ao anoitecer não é um valor errado de UBO. É uma <strong>translation gap do emulador</strong>. O jogo roda correto no PS4 real, então shadPS4 tem algum caminho que traduz ou sincroniza errado.</li>
<li><strong>Ação:</strong> 5 candidatos de bug emulator ranqueados — HLE shader misidentification, image storage classification, layout transitions, IMAGE_STORE_MIP fallback, OpImageFetch LOD restriction.</li>
<li><strong>Conceito novo:</strong> <strong>HLE (High-Level Emulation)</strong>. Substituir funções complexas do sistema operacional do PS4 por implementações host-side. Diferente de LLE (low-level) que emula bit a bit. HLE é mais rápido mas pode divergir do comportamento real quando a implementação host não cobre todos os casos.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/canada-dim.png" alt="Canadá ao anoitecer ainda dim"  loading="lazy" /></p>
<h3>Fase 29: calibrated state + recording harness<span class="hx:absolute hx:-mt-20" id="fase-29-calibrated-state--recording-harness"></span>
    <a href="#fase-29-calibrated-state--recording-harness" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-29-calibrated-state.md"target="_blank" rel="noopener"><code>phase-29-calibrated-state.md</code></a></p>

</blockquote>
<ul>
<li><strong>Ação:</strong> <code>SHADPS4_DC_RECORD=1</code>. Recording harness que dumpa lighting UBOs periodicamente + cross-correlation com screenshots wall-clock.</li>
<li><strong>Resultado:</strong> descoberta importante. <strong>Slots <code>[144..295]</code> do UBO de 1936 bytes</strong> (30+ fields) ficam <strong>denormal/uninitialized</strong> pelos primeiros ~90 segundos de corrida. Na &ldquo;auto-recalibração&rdquo; dos 1:30, o jogo escreve os valores reais. <strong>Não é recovery mágico, é a CPU finalmente escrevendo os valores que já deveriam estar lá desde o frame 1.</strong> No PS4 estão prontos antes do primeiro frame; no shadPS4 atrasam 90s. <strong>Root cause vive num init gap do emulador.</strong></li>
</ul>
<h3>Fase 30: UBO writer audit<span class="hx:absolute hx:-mt-20" id="fase-30-ubo-writer-audit"></span>
    <a href="#fase-30-ubo-writer-audit" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-30-ubo-writer-audit.md"target="_blank" rel="noopener"><code>phase-30-ubo-writer-audit.md</code></a></p>

</blockquote>
<ul>
<li><strong>Ação:</strong> auditoria exaustiva de todos os caminhos que escrevem no slot <code>[38]</code> do UBO de 1936 bytes. 7 suspeitos ranqueados: (1) ObtainBuffer stream-copy race, (2) lazy RegionManager em memory_tracker, (3) histogram compute skip, (4) page-fault delayed invalidation, (5) readback gating, (6) buffer-coherency race, (7) push-constant.</li>
<li><strong>Status:</strong> auditoria incompleta. Antes de conseguir verificar cada suspeito, a Fase 31 curto-circuitou tudo.</li>
</ul>
<h3>Fase 31: readbacks_mode = Precise, a virada<span class="hx:absolute hx:-mt-20" id="fase-31-readbacks_mode--precise-a-virada"></span>
    <a href="#fase-31-readbacks_mode--precise-a-virada" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-31-readbacks-mode-fix.md"target="_blank" rel="noopener"><code>phase-31-readbacks-mode-fix.md</code></a></p>

</blockquote>
<p>Quinta-feira de manhã. Cansado, pensando na suspeita <strong>#5, readback gating</strong>. Essa me coçava porque era a única dos 7 writers que tocava <em>timing</em> do read e não <em>correctness</em> do write.</p>
<ul>
<li><strong>Hipótese:</strong> ligar <code>readbacks_mode: 2 (Precise)</code> no config per-game faz o feedback loop funcionar sincronizando read do CPU a fresh GPU output.</li>
<li><strong>Ação:</strong> uma edit no <code>custom_configs/CUSA00003.json</code>. Boot. Corrida no Canadá à noite.</li>
<li><strong>Resultado:</strong> <strong>race start abre brilhante. Auto-exposure converge normalmente. Zero blackout. Zero recalibração aos 1:30. Night TOD natural.</strong></li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/almost-fixed.png" alt="Quase lá, o teste antes do final"  loading="lazy" /></p>
<p>Testes em Munnar. Mesmo resultado. Um inteiro. <strong>31 fases. 44 commits. 15.668 linhas. Resposta: um inteiro no config.</strong></p>
<p>Por que isso passou batido por 30 fases? O doc da Fase 31 tem a análise honesta:</p>
<ol>
<li><strong>Disfarce de sintoma.</strong> Progressive darkening parece exatamente com tonemap quebrado, shader ruim, ou scalar de exposure compilado errado. Toda probe dump-driven achou <strong>valores errados no UBO</strong>, que é verdade, mas descreve o downstream read, não o upstream gap.</li>
<li><strong>Red herring do <code>readback_linear_images</code>.</strong> Testei essa flag na Fase 29 e deu zero efeito, então concluí que &ldquo;a superfície de readback tá auditada&rdquo;. Esqueci que essa flag é pra <em>image</em> readbacks (linear images via <code>TextureCache::DownloadImageMemory</code>). O histogram SSBO é um <strong>buffer</strong>, caminho separado.</li>
<li><strong>Pinning piorando em vez de melhorar.</strong> Sobrescrever os slots [38/48/50] parecia prometer, mas nunca convergia. O jogo reescrevia em cima do pin a cada frame. Interpretei como &ldquo;o mecanismo de pin chega tarde demais no pipeline&rdquo;. Gastei as fases 27-29 movendo o pin pra mais cedo. O fix real era <strong>parar de clobber o GPU-side input que o integrator lê</strong>.</li>
<li><strong>Nunca auditei o caminho do readback de buffer.</strong> A auditoria da Fase 30 listou 7 candidatos de writer, mas todos eram sobre a correctness do <em>write</em>. Nenhum perguntou &ldquo;o que a CPU está lendo, esperando que o GPU tenha preenchido?&rdquo;</li>
</ol>
<h2>A técnica do shotgun<span class="hx:absolute hx:-mt-20" id="a-técnica-do-shotgun"></span>
    <a href="#a-t%c3%a9cnica-do-shotgun" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem uma coisa que eu quero registrar: <strong>os probes de tortura não são desperdício, são infraestrutura de aprendizado.</strong> E a metodologia por trás deles tem nome: shotgun.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/HkxVhFg81fs?start=40"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Se você tem uma suspeita, tipo &ldquo;o dim vem de alguma textura&rdquo;, a pior coisa que você pode fazer é começar investigando uma textura por vez, em profundidade. Driveclub tem 1079 texturas bound durante a race window. Se cada triagem detalhada leva 20 minutos, você gasta três dias num galho só dessa árvore, e ainda não sabe se o dim vem de textura. Pode até ser que a resposta não esteja na árvore inteira.</p>
<p>Shotgun resolve isso. Em vez de investigar uma por vez, você dispara em todas ao mesmo tempo. Muta cada textura bound com um tint hash-based, força re-upload, roda o jogo. Em 30 segundos você sabe se alguma delas afeta o dim. Se afeta, então o dim é texture-side e aí sim vale a pena começar a narrow down. Se não afeta, parabéns: você acabou de descartar a categoria &ldquo;textura&rdquo; inteira em 30 segundos. Muda de categoria, shotgun em UBOs. Nenhum hit? Shotgun em push constants. Nenhum hit? Shotgun em compute dispatches. Continua até algo reagir.</p>
<p><strong>Não comece tentando estreitar uma árvore que pode ser enorme.</strong> Você vai gastar semanas em folhas irrelevantes. Dê um tiro de shotgun no tronco primeiro. Veja qual galho reage. Aí sim, desce em detalhe dentro desse galho.</p>
<p>Foi isso que eu fiz, sem saber que estava fazendo, pelas 30 primeiras fases. 32 variáveis de ambiente de probe (<code>SHADPS4_DC_UBO_SMASH</code>, <code>SHADPS4_DC_PC_SMASH</code>, <code>SHADPS4_DC_DISPATCH_SMASH</code>, <code>SHADPS4_DC_TEX_NUKE_*</code>, <code>SHADPS4_DC_UBO_NUKE</code>, e mais). Batches randômicos, tints hash-based, substituições null. A maioria nunca apontou pro fix real. Mas cada rodada de shotgun descartou uma categoria inteira de modelo mental. &ldquo;Não é textura.&rdquo; &ldquo;Não é push-constant.&rdquo; &ldquo;Não são esses 8 compute pipelines.&rdquo; &ldquo;Não é UBO write-side em qualquer lugar dessa região.&rdquo; Cada descarte estreita o problema.</p>
<p><strong>E enquanto eu fazia isso, eu aprendia o sistema.</strong> Cada smash que crashava me dizia &ldquo;aqui vive um descriptor pointer crítico&rdquo;. Cada color tint que aparecia me dizia &ldquo;esse UBO alimenta essa passagem de composição&rdquo;. Cada dispatch que fira diferente entre dim/bright me mostrava onde está a fronteira interessante.</p>
<p><strong>Quando você não conhece o sistema, shotgun probes são um mapa.</strong> Você não usa eles pra encontrar a resposta. Você usa pra descobrir o terreno.</p>
<h2>O que eu sabia domingo vs quinta<span class="hx:absolute hx:-mt-20" id="o-que-eu-sabia-domingo-vs-quinta"></span>
    <a href="#o-que-eu-sabia-domingo-vs-quinta" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>Domingo:</strong> zero em tudo. Todas as áreas abaixo eram caixas pretas pra mim.</p>
<p><strong>Quinta:</strong></p>
<ul>
<li>PS4 package format end-to-end (PKG → PFS → param.sfo → disc_info → keystone → npbind). Como v1.28 cumulative patches funcionam em cima de v1.00 base install.</li>
<li>Arquitetura do shadPS4 em resumo: <code>src/common</code>, <code>src/core</code> (OS emulation, libraries HLE), <code>src/shader_recompiler</code> (GCN→SPIR-V), <code>src/video_core</code> (Vulkan renderer, buffer cache, texture cache, page manager).</li>
<li>Pipeline gráfico completo: G-buffer → forward+ lighting (escreve MSAA depth) → read depth como color pra SSAO / volumetric froxel → post-fx compute → tonemap → composite → swapchain.</li>
<li>UBO vs push constant vs descriptor set. Quando usar cada um.</li>
<li>SPIR-V disassembly e re-assembly pra patching cirúrgico. Como identificar tonemap compute por assinatura de Exp2/Log2.</li>
<li>Forward+ lighting + MSAA depth resolve + como implementar ReinterpretMsDepthAsColor.</li>
<li>Buffer cache do shadPS4: <code>MemoryTracker</code>, <code>RegionManager</code>, <code>FaultManager</code>. Como page-fault vira GPU→CPU sync.</li>
<li><code>readbacks_mode</code>: Disabled / Relaxed / Precise. Qual tradeoff de cada. Por que Relaxed não basta pra feedback loops (ele só write-protect, não read-protect).</li>
<li>PS4 OELF → Itanium RTTI → SCE relocation → dynamic linker reasoning, mesmo sem ter feito o binary patch (o plano ficou documentado).</li>
</ul>
<p>Não virei expert em nada disso. Mas virei de <strong>total outsider</strong> pra <strong>operador razoavelmente orientado</strong>. E esse salto, como eu comento depois, foi a coisa mais valiosa dos 4 dias.</p>
<h2>A IA sugeria aceitar. A perseverança humana foi minha<span class="hx:absolute hx:-mt-20" id="a-ia-sugeria-aceitar-a-perseverança-humana-foi-minha"></span>
    <a href="#a-ia-sugeria-aceitar-a-perseveran%c3%a7a-humana-foi-minha" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu disse algumas vezes ao longo do artigo que &ldquo;Claude sugeriu parar&rdquo;. Quero ser justo e específico aqui: não foi uma falha da IA. Foi exatamente o comportamento correto de uma ferramenta inteligente: <strong>quando você tem algo que funciona razoavelmente bem, parar e documentar é frequentemente a escolha certa.</strong> O patch de tonemap na Fase 22+ fez o jogo playable. O pin de UBO na Fase 26 fez a imagem ficar bonita. O recording harness da Fase 29 cobriu a janela crítica. Todos eram pontos legítimos de parada.</p>
<p>Se você ler o <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/codex-conclusion.md"target="_blank" rel="noopener"><code>codex-conclusion.md</code></a>, documento que a IA produziu após a Fase 26 (ainda sem saber sobre a Fase 31), ela descreve a solução de então como &ldquo;<strong>a mitigation, not a root-cause fix</strong>&rdquo;. Admite honestamente o que sabíamos: o pin de UBO era um contra-ataque, não explicação. Esse é bom comportamento.</p>
<p>A diferença é que <strong>eu tinha um teimoso palpite de que algo ainda tava errado</strong>. Ela funcionava no sentido playable. Mas o custo (pin Driveclub-specific + patch SPIR-V de tonemap + per-track threshold tuning + não generalizar) era alto demais pra um fix supostamente de engineering-quality. Profissional senior reconhece quando a assimetria entre custo e entendimento aponta pra algo mais fundo. Não sempre acerta. Mas esse palpite merece ser escutado.</p>
<p>Quatro dias sem interrupção, das 8h à meia-noite, domingo, segunda, terça, quarta, e resolvido quinta de manhã. Quantas vezes a IA sugeriu &ldquo;honestly, we should just accept the current result and document&rdquo;? Umas 4 ou 5 vezes. Cada uma tecnicamente defensável. <strong>A perseverança humana é a diferença entre &ldquo;o jogo funciona bem o bastante&rdquo; e &ldquo;o jogo funciona, e eu sei por quê&rdquo;.</strong></p>
<h2>Custo real dessa jornada<span class="hx:absolute hx:-mt-20" id="custo-real-dessa-jornada"></span>
    <a href="#custo-real-dessa-jornada" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/investigation-effort-accounting.md"target="_blank" rel="noopener"><code>investigation-effort-accounting.md</code></a> catalogue tudo antes da limpeza. Uns highlights:</p>
<ul>
<li><strong>3 dias</strong> de trabalho ativo (Apr 21-23, 2026).</li>
<li><strong>33 phases</strong> numeradas + sweeps + side threads = 54 docs, 412 KB, <strong>6.867 linhas de prosa</strong>.</li>
<li><strong>44 commits</strong> no fork gamma-debug. <strong>15.668 linhas adicionadas</strong>, 1.204 removidas.</li>
<li><code>src/video_core/renderer_vulkan/vk_rasterizer.cpp</code> cresceu de 1.364 pra <strong>4.680 linhas</strong> (3.4×) com instrumentação, pin lifecycles, recording harness.</li>
<li><strong>32 env vars</strong> de probe definidas. <strong>1 efetivamente usada pra encontrar o bug</strong> (<code>SHADPS4_DC_LOG_STREAMCOPY</code>, na Fase 30).</li>
<li><strong>61 MB</strong> de log shadPS4 acumulado. <strong>57 MB</strong> de shader dumps (5.803 arquivos). ~<strong>470 MB</strong> totais de artifacts reclaimáveis depois de fechar.</li>
</ul>
<p>Resolution: <strong>1 inteiro no config.</strong></p>
<p>A proporção <strong>6.867 linhas de prosa : 1 inteiro</strong> me diverte. Mas ela não é uma piada de ineficiência. É o custo real de aprender um sistema que você não conhecia. Cada linha de prosa descartou uma hipótese. Cada commit ensinou uma camada do stack. O inteiro foi o fim; o caminho foi o produto.</p>
<p>Uma nota honesta: apesar das 15.668 linhas adicionadas no fork <code>gamma-debug</code>, <strong>quase nada disso presta pra contribuir upstream no shadPS4</strong>. O que está lá é instrumentação — torture probes, recording harness, pin lifecycles, calibrate-at-arm, snapshots de UBO, dezenas de env vars de debug. Código de diagnóstico, não código de produção. Diagnóstico que só faz sentido pro Driveclub naquelas condições específicas.</p>
<p>O fork vai ficar público, mas <strong>não como branch de contribuição pro projeto shadPS4</strong>. Infelizmente. Fica como documento de estudo: 54 arquivos md cobrindo o processo completo, 44 commits mostrando a sequência de hipóteses, descartes e falhas. É material pra quem quiser entender como foi o processo de depuração, ou pra reaproveitar algumas das técnicas em outras investigações similares. PR upstream-ready dali não sai.</p>
<h2>Fechamento<span class="hx:absolute hx:-mt-20" id="fechamento"></span>
    <a href="#fechamento" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sim, a solução final era um toggle de config que já existia. Está no código do shadPS4 há sete meses. Mas domingo à noite, zero conhecimento de PS4, zero conhecimento do emulator, zero noção de que auto-exposure era um GPU→CPU feedback loop, <strong>eu não tinha autoridade técnica pra dizer &ldquo;liga readbacks Precise, resolve&rdquo;</strong>.</p>
<p>Eu tive que ver a cadeia toda pra entender <em>por que</em> funciona. Por que Relaxed não basta (só write-protects, e o DriveClub lê, não escreve no SSBO do histograma). Por que Precise é caro (per-page mprotect + per-fault GPU stall). Por que o maintainer escondeu atrás de &ldquo;Advanced&rdquo; (Bloodborne trava, AMD cai pra 12 FPS). Por que ninguém na comunidade tinha conectado Precise com DriveClub antes: o compat tracker admite &ldquo;readbacks enabled&rdquo;, mas não cita o modo, e ninguém tinha visto a assinatura de drift monotônico pelo ângulo do loop GPU→CPU.</p>
<p>Essa é a diferença entre <strong>conhecer a resposta</strong> e <strong>conhecer o terreno o suficiente pra reconhecer a resposta</strong>. Pra junior que me pergunta &ldquo;como eu aprendo hoje na era da IA&rdquo;: essa é a minha resposta. Não pergunte. Mergulhe. Use a IA pra acelerar a busca, pra ler código em paralelo, pra indexar fóruns antigos, pra compilar, pra parsear logs. Mas <strong>insista em entender o porquê</strong>. Quando a IA sugerir &ldquo;vamos aceitar e documentar&rdquo; (e ela vai sugerir, porque esse comportamento é frequentemente correto), pergunte a si mesmo se você realmente entendeu a cadeia. Se ainda tiver a coceira de &ldquo;isso tá errado mas eu não sei por quê&rdquo;, continue.</p>
<p>Provavelmente você vai gastar 4 dias numa coisa que tem solução de um inteiro. Provavelmente você vai descobrir 5 caminhos errados antes do certo. Provavelmente a metade dos seus probes vão ser torture shotguns que nunca apontaram pro fix.</p>
<p>E provavelmente, quando terminar, você vai saber um domínio que você não conhecia.</p>
<ul>
<li><strong>Fork gamma-debug:</strong> <a href="https://github.com/akitaonrails/shadPS4/tree/gamma-debug"target="_blank" rel="noopener">github.com/akitaonrails/shadPS4/tree/gamma-debug</a></li>
<li><strong>54 docs da investigação:</strong> <a href="https://github.com/akitaonrails/shadPS4/tree/gamma-debug/docs/driveclub-investigation"target="_blank" rel="noopener">docs/driveclub-investigation/</a></li>
<li><strong>Operational runbook (recipe):</strong> <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener">distrobox-gaming/docs/driveclub-shadps4.md</a></li>
<li><strong>Resolução da Fase 31:</strong> <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-31-readbacks-mode-fix.md"target="_blank" rel="noopener"><code>readbacks_mode: 2</code></a></li>
</ul>
<p>Agora eu vou jogar Driveclub. Corrida noturna no Canadá, brilho natural, sem blackout. Boa quinta-feira.</p>
]]></content:encoded><category>emulacao</category><category>games</category><category>aprendizado</category></item><item><title>Meus Retrogames de Corrida Favoritos Rodando no Meu Distrobox</title><link>https://akitaonrails.github.io/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/</guid><pubDate>Sun, 19 Apr 2026 20:00:00 -0300</pubDate><description>&lt;p&gt;Eu passei o domingo inteiro nisso, e foi um dos domingos mais produtivos que eu tive em tempos. A missão foi específica: fechar os jogos de corrida simcade mais difíceis de emular, que eu quero rodar há anos, e só agora consegui chegar num estado confiável.&lt;/p&gt;
&lt;p&gt;No topo dessa lista estão dois monstros. Primeiro, &lt;strong&gt;&lt;a href="#driveclub-o-imposs%c3%advel-finalmente-poss%c3%advel"&gt;Driveclub&lt;/a&gt;&lt;/strong&gt; no shadPS4. É exclusivo de PS4, nunca foi portado, a Evolution Studios foi fechada, não tem remaster. Pra jogar fora do PS4 original, só via emulação, e emulação de PS4 ainda é a parte mais imatura da ecossistema hoje. Esse é &lt;strong&gt;de longe o mais difícil da lista&lt;/strong&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu passei o domingo inteiro nisso, e foi um dos domingos mais produtivos que eu tive em tempos. A missão foi específica: fechar os jogos de corrida simcade mais difíceis de emular, que eu quero rodar há anos, e só agora consegui chegar num estado confiável.</p>
<p>No topo dessa lista estão dois monstros. Primeiro, <strong><a href="#driveclub-o-imposs%c3%advel-finalmente-poss%c3%advel">Driveclub</a></strong> no shadPS4. É exclusivo de PS4, nunca foi portado, a Evolution Studios foi fechada, não tem remaster. Pra jogar fora do PS4 original, só via emulação, e emulação de PS4 ainda é a parte mais imatura da ecossistema hoje. Esse é <strong>de longe o mais difícil da lista</strong>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/19/distrobox-gaming/shadps4-launcher.png" alt="shadPS4 Qt Launcher mostrando DRIVECLUB CUSA00003 pronto pra rodar"  loading="lazy" /></p>
<p>Segundo, <strong><a href="#forza-motorsport-4-o-goat">Forza Motorsport 4 com Project Forza Plus</a></strong> no Xenia Canary. FM4 é o GOAT da era Xbox 360, Project Forza Plus é a mod comunitária que consolida patches e conteúdo, e fazer os dois rodarem juntos no Xenia com gráfico decente, sem crash de áudio e sem shadow bug, levou horas sérias de trial and error.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/19/distrobox-gaming/xenia-manager.png" alt="Xenia Manager com a coleção Forza do Xbox 360 instalada"  loading="lazy" /></p>
<p>Em torno desses dois eu organizei o resto do que eu já sabia que funcionava em algum nível, só faltava consolidar num setup repetível: <strong><a href="#gran-turismo-4">Gran Turismo 4 com Retexture 3.0 e HD HUD</a></strong>, <strong><a href="#gran-turismo-3-a-spec">Gran Turismo 3 com HD textures e widescreen</a></strong>, <strong><a href="#gran-turismo-2-spec-ii-mod">Gran Turismo 2 na mod Spec II</a></strong>, os Gran Turismos de PS3 (<a href="#gran-turismo-5">GT5</a> e <a href="#gran-turismo-6">GT6</a>), os Forza Horizon <a href="#forza-horizon-1-com-xe-mod">1</a> e <a href="#forza-horizon-2">2</a>, os <a href="#project-gotham-racing-3-e-4">PGRs</a>, <a href="#ridge-racer-v">Ridge Racer</a>, <a href="#enthusia-professional-racing">Enthusia</a>, <a href="#colin-mcrae-rally-1-e-2">Colin McRae</a>. Esses eu tinha ideia de como fazer, só precisava consolidar num setup que não volta a quebrar na próxima vez que eu reinstalar o sistema.</p>
<p>Antes de entrar no detalhe, preciso esclarecer duas coisas.</p>
<p>Primeiro, sobre a infra: não vou repetir aqui o como o setup foi montado. Já escrevi isso em detalhe no artigo <a href="/2026/04/11/distrobox-de-emulacao-com-claude-code/">Distrobox de Emulação com Claude Code</a>. Arch Linux num distrobox com <code>--nvidia</code>, 17 roles Ansible, todos os emuladores no AUR, ES-DE como frontend, configs per-game automatizadas, scripts Python pra PS3 update check e Xbox 360 title updates, Xenia via Wine. Lê lá. O repo tá em <a href="https://github.com/akitaonrails/distrobox-gaming"target="_blank" rel="noopener">akitaonrails/distrobox-gaming</a> pra quem quiser reproduzir. Aqui eu vou falar dos jogos.</p>
<p>Segundo, sobre o gosto: eu gosto de simcade de corrida. Gran Turismo é meu vício declarado desde o PS1, e escrevi sobre o resto no artigo do <a href="/2026/04/01/meu-cockpit-de-sim-racing-formula-fx1/">meu cockpit Formula FX1</a>. Volante direct drive, pedal com load cell, triple monitor quando tô afim de sofrer. Esse é o tipo de corrida que eu gosto.</p>
<h2>O aviso pra quem já tá de dedo no teclado<span class="hx:absolute hx:-mt-20" id="o-aviso-pra-quem-já-tá-de-dedo-no-teclado"></span>
    <a href="#o-aviso-pra-quem-j%c3%a1-t%c3%a1-de-dedo-no-teclado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sim, eu conheço iRacing e os outros sims e simcades atuais. Eu tenho 12 TB de ISO e ROM no NAS, provavelmente tenho algum que você ia lembrar de citar. Não é por falta de opção que eu tô focando em emulação hoje.</p>
<p>Aliás, dos jogos novos que eu realmente tô esperando: <strong><a href="https://forza.net/"target="_blank" rel="noopener">Forza Horizon 6</a> em Tóquio</strong>, <strong><a href="https://www.assettocorsa.it/"target="_blank" rel="noopener">Assetto Corsa EVO</a></strong> e <strong><a href="https://www.assettocorsa.it/"target="_blank" rel="noopener">Assetto Corsa Rally</a></strong>. Tô jogando as demos dos dois Assetto Corsa e gostando muito das campanhas single-player. Quando eles saírem em versão final, vão virar meus jogos principais de sim na rotina. Esse artigo aqui cobre um lado diferente da coleção, que é tirar do esquecimento os clássicos que ainda não têm remaster.</p>
<p>Hoje, aqui, eu estou interessado nesses jogos específicos que listei acima. Ponto. Você faz o que você quer, eu faço o que eu quero. Se você quer iRacing, abra um Steam e vá em paz. Esse artigo é sobre mexer com emulador, preservar jogo velho, e tirar essas pérolas do esquecimento num setup Linux. Quem tá procurando review de sim atual não vai encontrar aqui.</p>
<p>Agora vamos ao que interessa.</p>
<p><strong>Observação sobre os vídeos:</strong> a maioria tá sem áudio porque eu esqueci de ligar a captura de som no OBS antes de gravar e fiquei com preguiça de re-gravar. O áudio funciona perfeito em todos os emuladores aqui, é falha minha no OBS, não do setup.</p>
<h2>Settings globais por emulador<span class="hx:absolute hx:-mt-20" id="settings-globais-por-emulador"></span>
    <a href="#settings-globais-por-emulador" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes dos jogos, vale consolidar as configs globais que valem pra tudo em cada emulador. Isso tá automatizado no repo, mas se você tá configurando na mão, aqui tá o resumo.</p>
<h3>DuckStation (PS1)<span class="hx:absolute hx:-mt-20" id="duckstation-ps1"></span>
    <a href="#duckstation-ps1" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Renderer:</strong> Vulkan</li>
<li><strong>Internal Resolution Scale:</strong> 8x (8K render, downscalado pro monitor)</li>
<li><strong>Texture Filtering:</strong> JINC2 (preserva pixel art mas suaviza)</li>
<li><strong>PGXP:</strong> ligado (corrige wobble de vértice típico do PS1)</li>
<li><strong>Widescreen Hack:</strong> ligado como fallback, mas preferência por cheat widescreen per-game</li>
<li><strong>Aspect Ratio:</strong> 16:9 com widescreen cheat, 4:3 sem</li>
</ul>
<p>PS1 hoje em dia sobe liso no DuckStation. É o emulador mais maduro da lista. A atenção vai pras escolhas per-game (alguns jogos precisam de cheat específico de widescreen).</p>
<h3>PCSX2 (PS2)<span class="hx:absolute hx:-mt-20" id="pcsx2-ps2"></span>
    <a href="#pcsx2-ps2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Renderer:</strong> Vulkan</li>
<li><strong>Upscale:</strong> 4x SSAA (1440p nativo → 4K interno)</li>
<li><strong>Anisotropic Filtering:</strong> 16x</li>
<li><strong>Post Processing:</strong> FXAA ligado, PCRTC antiblur ligado</li>
<li><strong>Deinterlacing:</strong> Automatic (alguns jogos precisam override)</li>
<li><strong>Controller:</strong> bindings Xbox-style (eu uso controle 8BitDo)</li>
</ul>
<p>PCSX2 2.7.x é muito superior ao 2.6.3 que ainda tá no repo oficial do Arch. O AUR <code>pcsx2-latest-bin</code> tracka o 2.7.x e é onde mora o texture replacement, FXAA moderno e PCRTC antiblur. Se você tá em distro diferente e tá no 2.6.3, procure o AppImage oficial.</p>
<h3>RPCS3 (PS3)<span class="hx:absolute hx:-mt-20" id="rpcs3-ps3"></span>
    <a href="#rpcs3-ps3" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Renderer:</strong> Vulkan</li>
<li><strong>Resolution Scale:</strong> 300% (geralmente) ou nativo (jogos com issue de upscale)</li>
<li><strong>Shader Precision:</strong> Ultra</li>
<li><strong>Force High Precision Z:</strong> ligado</li>
<li><strong>SPU XFloat:</strong> Accurate</li>
<li><strong>Multithreaded RSX:</strong> ligado</li>
<li><strong>Write Color Buffers (WCB) / Read Color Buffers (RCB):</strong> desligados por padrão (GT-series safety)</li>
</ul>
<p>RPCS3 é onde mais tem armadilha. Cada jogo tem preset recomendado na <a href="https://rpcs3.net/compatibility"target="_blank" rel="noopener">DB de compatibilidade oficial</a>. E atenção: configs per-game ficam em <code>~/.config/rpcs3/custom_configs/config_&lt;SERIAL&gt;.yml</code>. Prefixo <code>config_</code> obrigatório. Perdi tempo até descobrir isso, o RPCS3 aceita o YAML silenciosamente e depois ignora se o nome tá errado.</p>
<h3>Xenia Canary (Xbox 360)<span class="hx:absolute hx:-mt-20" id="xenia-canary-xbox-360"></span>
    <a href="#xenia-canary-xbox-360" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Build:</strong> Canary (o <code>master</code> tá parado há meses, Canary é o que anda)</li>
<li><strong>Renderer:</strong> Vulkan</li>
<li><strong>Render Target Path:</strong> <code>rtv</code> por default, <code>fsi</code> pra jogos específicos (PGR4)</li>
<li><strong>User Profile:</strong> criado uma vez, persiste</li>
<li><strong>Wine Prefix:</strong> dedicado, gerenciado pelo Xenia Manager</li>
</ul>
<p>Xenia no Linux roda via Wine, gerenciado pelo <a href="https://github.com/xenia-manager/xenia-manager"target="_blank" rel="noopener">Xenia Manager</a>. Não tem build nativo decente. Funciona bem, mas cada jogo pede ajuste específico, e Title Updates tem que ser puxado manualmente do archive.org (escrevi um script pra isso, detalhes no artigo anterior).</p>
<h3>shadPS4 (PS4)<span class="hx:absolute hx:-mt-20" id="shadps4-ps4"></span>
    <a href="#shadps4-ps4" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Esse merece a seção dedicada no final. Resumindo: funciona pra alguns jogos simples, pra Driveclub ainda não é confiável. Continua sendo um tiro no escuro.</p>
<h2>PS1 no DuckStation<span class="hx:absolute hx:-mt-20" id="ps1-no-duckstation"></span>
    <a href="#ps1-no-duckstation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Gran Turismo (o primeiro, de 1997)<span class="hx:absolute hx:-mt-20" id="gran-turismo-o-primeiro-de-1997"></span>
    <a href="#gran-turismo-o-primeiro-de-1997" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%201.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Esse aqui é puro sentimento. GT1 foi um dos primeiros jogos que eu comprei pro PS1, e joguei até rachar o CD. Na época, era outro patamar. Simulação real numa máquina de 128K de RAM de vídeo, física decente, 140 carros quando todo mundo tinha 15, trilha sonora memorável.</p>
<p>Mas sejamos honestos: não dá pra voltar hoje. A física do GT1 tem drift exagerado, o carro desliza mais do que deveria em qualquer curva acima de 80 km/h. É parte do charme de 1997 mas irrita em 2026. O <strong>modelo de controle foi muito refinado a partir do GT2</strong>, e tudo que veio depois só melhorou. Entre GT1 e GT2, GT2 vence em conteúdo (650+ carros vs 140) e principalmente em dirigibilidade.</p>
<p>Eu deixo o GT1 no ES-DE pra abrir em momentos de nostalgia, jogar uns 10 minutos em Trial Mountain e fechar. Pra gameplay sério da era PS1, vai de GT2.</p>
<h3>Gran Turismo 2 (Spec II Mod)<span class="hx:absolute hx:-mt-20" id="gran-turismo-2-spec-ii-mod"></span>
    <a href="#gran-turismo-2-spec-ii-mod" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%202.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>O Gran Turismo original do PS1 é um marco histórico. Eu joguei muito na época. Hoje, pra jogar de novo? Não. GT2 existe, e GT2 é superior em tudo. Mais carros (650+), mais pistas, mais modos, e principalmente, <strong>um modelo de controle muito melhor</strong>. O GT1 tem aquele drift exagerado onde o carro desliza mais do que deveria, o GT2 ajustou isso pra algo mais próximo do que a série seria a partir do PS2. Entre jogar GT1 ou GT2, sempre GT2.</p>
<p>E o GT2 que eu rodo hoje é o <strong>GT2 Spec II Mod</strong> do <a href="https://x.com/projectaspec?lang=en"target="_blank" rel="noopener">Project A-Spec</a>, um projeto comunitário que consolida as duas variantes regionais (Arcade + Simulation) num único jogo, traz de volta eventos que foram cortados no release final, corrige bugs de física, adiciona suporte a widescreen nativo e dá quality-of-life updates em menus. É o jeito definitivo de jogar GT2 em 2026. O projeto não mantém mais site próprio, as atualizações vêm pelo Twitter do autor.</p>
<p>Pra rodar:</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>GT2 Spec II Mod (patch aplicado sobre ISO Simulation USA)</td>
      </tr>
      <tr>
          <td>Serial</td>
          <td>SCUS-94455</td>
      </tr>
      <tr>
          <td>Widescreen cheat</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>8 MB RAM cheat</td>
          <td>Ligado (corrige áudio em pistas cheias)</td>
      </tr>
      <tr>
          <td>Texture Filter</td>
          <td>JINC2</td>
      </tr>
      <tr>
          <td>Resolution Scale</td>
          <td>8x</td>
      </tr>
  </tbody>
</table>
<p>O cheat de 8 MB RAM é importante pra pistas cheias (tipo Seattle em corridas populated) onde o áudio começa a estourar. Ele simula a expansão de memória da versão japonesa que nunca veio pro Ocidente.</p>
<h3>Colin McRae Rally 1 e 2<span class="hx:absolute hx:-mt-20" id="colin-mcrae-rally-1-e-2"></span>
    <a href="#colin-mcrae-rally-1-e-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Jogos icônicos do PS1. CMR1 tem aquela sensação áspera de rally primeiro-gen que tem seu charme. CMR2 é tecnicamente superior, física melhor, mais rallys, melhor grafia. Mas eu vou ser honesto: <strong>pra jogar CMR2 hoje, vale procurar a versão PC original</strong>. Resolução maior, 60fps nativo (a versão PS1 trava em 30), controle direto de teclado/volante. Existem repacks do Codemasters na internet, tem umas 40 segundos num search decente. Não vou linkar, você sabe onde procurar.</p>
<p>No PS1 via DuckStation eles rodam liso, nostalgia garantida, mas não é onde eu passo o tempo.</p>
<h2>PS2 no PCSX2<span class="hx:absolute hx:-mt-20" id="ps2-no-pcsx2"></span>
    <a href="#ps2-no-pcsx2" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Gran Turismo 3 A-Spec<span class="hx:absolute hx:-mt-20" id="gran-turismo-3-a-spec"></span>
    <a href="#gran-turismo-3-a-spec" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%203.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>GT3 foi um salto geracional. Saiu do mundo quadradinho do PS1 pra um mundo de shaders, environment mapping decente, modelos de carro com polígono sério, física que finalmente começou a parecer com física de verdade. A trilha sonora com Feeder de &ldquo;Just a Day&rdquo; abrindo o jogo ainda me dá arrepio.</p>
<p>O problema é que GT3 tem MENOS conteúdo que GT2. Polyphony foi mais cautelosa, cortou modos pra focar em qualidade. Licença A/B/S é menor, carros são menos, pistas são fewer. Mas o que tem é polido.</p>
<p>Em 2026 no PCSX2 2.7.x, GT3 fica muito bom. HD textures de comunidade, widescreen pnach, anti-aliasing via SSAA, 16x AF. Parece jogo relançado.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>GT3 A-spec (SCUS-97102) ou Bundle (PBPX-95503)</td>
      </tr>
      <tr>
          <td>Widescreen pnach</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Pack de retextura</td>
          <td>Opcional (desativado por default, ativar se quiser ver tudo HD)</td>
      </tr>
      <tr>
          <td>Upscale</td>
          <td>4x SSAA</td>
      </tr>
      <tr>
          <td>Deinterlacing</td>
          <td>Automatic</td>
      </tr>
  </tbody>
</table>
<p>Caveat sobre o pack de retextura: quando ligado, tem cenas de mostruário de carro no garage onde o NFS stream causa um flicker momentâneo. Não incomoda em corrida. Se te irrita no menu, desliga.</p>
<p><strong>Lembrete:</strong> pro widescreen pnach fazer efeito você ainda precisa entrar nas opções <strong>dentro do jogo</strong> e mudar o aspect ratio pra 16:9. O pnach libera a opção no menu, não aplica automaticamente.</p>
<h3>Gran Turismo 4 (Spec II Mod)<span class="hx:absolute hx:-mt-20" id="gran-turismo-4-spec-ii-mod"></span>
    <a href="#gran-turismo-4-spec-ii-mod" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%204.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>GT4 é o meu GOAT da série. 700+ carros, 50+ circuitos, física ainda respeitável pra padrão 2026, e aquela trilha sonora que mistura rock alternativo, lounge japonês, e o infame &ldquo;Sail Away&rdquo; do Moby no menu principal. Foi o jogo que mais mexi em 2004, e é o que eu mais mexo hoje.</p>
<p>Igual o GT2, o GT4 que eu rodo hoje <strong>não é o disco original</strong>. É o <a href="https://www.theadmiester.co.uk/specii/"target="_blank" rel="noopener"><strong>Gran Turismo 4: Spec II</strong></a> mantido pelo TheAdmiester — uma mod comunitária massiva que é objetivamente o melhor jeito de jogar GT4 em 2026. Ela combina o disco final USA, a Beta prototype de 2003 e o release japonês original num único jogo, restaurando carros cortados (incluindo vários que nunca saíram fora do Japão), eventos cancelados, dezenas de faixas de trilha sonora faltantes, suporte a widescreen 16:9, mais de 30 cheats integrados como opções de menu (pro tuning, velocidade máxima, economia de combustível), opção de trocar entre idiomas Inglês/Japonês, e correções de bugs originais. O projeto é ativo, ainda recebe patches e tem instalador próprio que aplica sobre uma ISO USA limpa.</p>
<p>Na prática, Spec II é o que o GT4 deveria ter sido se a Polyphony tivesse tido mais seis meses pra polir. Quando você joga hoje, é GT4 com todo o conteúdo que ficou de fora + quality-of-life moderno. Pra qualquer um que gostou do original, é obrigatório.</p>
<p>Por cima disso vai o <strong>Retexture 3.0</strong> da comunidade (pack de textura HD) e o <strong>HD HUD</strong> do <a href="https://github.com/Silentwarior112/GT4-HD-HUD-Pack"target="_blank" rel="noopener">Silentwarior112</a>. Com essas três peças juntas (Spec II Mod + Retexture + HD HUD), GT4 roda a 1440p SSAA no PCSX2 2.7.x com 16x AF, FXAA, e uma cara que honestamente é indistinguível de um jogo novo em low-poly style. É o meu atual favorito pra sentar e jogar longo.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>GT4 USA (SCUS-97328) ou Spec II (SCUS-97436, CRC <code>4CE521F2</code>)</td>
      </tr>
      <tr>
          <td>HD HUD pack</td>
          <td>Instalado via symlink (Silentwarior112)</td>
      </tr>
      <tr>
          <td>Retexture 3.0</td>
          <td>Instalado</td>
      </tr>
      <tr>
          <td>Widescreen pnach</td>
          <td>Ligado (renomeado pro CRC do Spec II se for Spec II)</td>
      </tr>
      <tr>
          <td>Silent&rsquo;s trigger/camera patches</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Deinterlace (Spec II)</td>
          <td>Mode 8 Adaptive TFF</td>
      </tr>
      <tr>
          <td>ShadeBoost (Spec II)</td>
          <td>Saturation +10, Brightness +3, Contrast +2</td>
      </tr>
      <tr>
          <td>FXAA + PCRTC antiblur</td>
          <td>Ligado global</td>
      </tr>
      <tr>
          <td>Upscale</td>
          <td>4x SSAA</td>
      </tr>
  </tbody>
</table>
<p>Quem tá usando o Spec II Mod precisa atentar pro CRC: os HD packs do GT4 vanilla foram feitos pro <code>77E61C8A</code> (USA), então no Spec II com CRC <code>4CE521F2</code> eu linko os assets via symlink na pasta CRC-suffixed que o PCSX2 procura. O pnach de widescreen também foi renomeado pra bater com o CRC do Spec II. Sem esse cuidado, o jogo roda mas os mods não carregam.</p>
<p><strong>Lembretes in-game:</strong> igual ao GT3, o widescreen pnach só libera a opção, você ainda precisa entrar em Options dentro do jogo e trocar pra 16:9. E importante: <strong>mude o modo de vídeo pra progressive 480p</strong> (também em Options). O default é interlaced 480i, que fica péssimo em tela moderna. O Spec II Mod tem suporte nativo a progressive, é só ligar.</p>
<p>Se eu pudesse recomendar um único GT da série pra alguém começar hoje, seria esse. Se você gosta de corrida e nunca jogou GT4 full, tá perdendo.</p>
<h3>Enthusia Professional Racing<span class="hx:absolute hx:-mt-20" id="enthusia-professional-racing"></span>
    <a href="#enthusia-professional-racing" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/enthusia.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Enthusia é o jogo esquecido da Konami de 2005. Saiu na sombra do GT4 e morreu no balcão. É uma pena, porque a <strong>física do Enthusia era mais realista que a do GT4</strong>. Peso do carro, transferência de massa, comportamento em limite, tudo mais próximo do comportamento real. A comunidade sim-racing dos anos 2000 sabia disso e o jogo tem culto hoje.</p>
<p>O problema do Enthusia era o sistema de Enthusia Points: você ganhava pontos por andar limpo, perdia por bater, e a progressão do jogo dependia desses pontos. Muita gente achou punitivo. Eu achei perfeito. Forçava você a dirigir com cabeça.</p>
<p>Em PCSX2 com retexture e widescreen, o jogo fica muito bom. Recomendação forte pra quem quer algo diferente dos Gran Turismo.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>Enthusia Professional Racing (SLUS-20967)</td>
      </tr>
      <tr>
          <td>Widescreen pnach</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Retexture</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Upscale</td>
          <td>4x SSAA</td>
      </tr>
  </tbody>
</table>
<h3>Ridge Racer V<span class="hx:absolute hx:-mt-20" id="ridge-racer-v"></span>
    <a href="#ridge-racer-v" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/ridge%20racer%20v.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Ridge Racer é sua própria coisa. Não é simcade, é arcade puro. Drift tudo, colinha dinâmica, trilha sonora eletrônica, cores saturadas. Ridge Racer V foi o jogo de lançamento do PS2 no Japão e por isso tem aquele cheiro de &ldquo;mostra o que o console pode fazer&rdquo;, com cenários colossais e sensação de velocidade que GT nunca tentou.</p>
<p>No PCSX2 ele roda bem, com uma caveira: textura de carro às vezes flicka em hardware renderer (issues <a href="https://github.com/PCSX2/pcsx2/issues/3639"target="_blank" rel="noopener">#3639</a> e <a href="https://github.com/PCSX2/pcsx2/issues/13729"target="_blank" rel="noopener">#13729</a> do PCSX2). Software renderer resolve mas mata performance. Eu fico no hardware e aceito o flicker ocasional.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>Ridge Racer V (SLUS-20002)</td>
      </tr>
      <tr>
          <td>Widescreen pnach</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>No-interlace pnach</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Upscale</td>
          <td>4x SSAA</td>
      </tr>
  </tbody>
</table>
<h3>Colin McRae Rally 3, 4, 5 (PS2)<span class="hx:absolute hx:-mt-20" id="colin-mcrae-rally-3-4-5-ps2"></span>
    <a href="#colin-mcrae-rally-3-4-5-ps2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Versões de PS2 dos Colin McRae rodam bem no PCSX2 com configs default. CMR3 e CMR04 são bons. CMR05 (o último antes do rebrand pra Dirt) é o melhor dos três tecnicamente. Mas de novo: <strong>se você tá em PC, procura a versão nativa</strong>. Os ports de PS2 eram relativamente inferiores aos PC da época, rodavam em resolução menor, e o PC moderno com repack vai dar 144Hz fácil.</p>
<p>Fica o registro no PCSX2 pra completude da coleção.</p>
<h2>PS3 no RPCS3<span class="hx:absolute hx:-mt-20" id="ps3-no-rpcs3"></span>
    <a href="#ps3-no-rpcs3" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Gran Turismo 5<span class="hx:absolute hx:-mt-20" id="gran-turismo-5"></span>
    <a href="#gran-turismo-5" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%205.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>GT5 é controverso. Polyphony prometeu mundos e entregou um jogo meio fragmentado: modelos Premium lindos ao lado de Standard que eram basicamente carros do GT4 em HD, sistema de níveis que alguns amaram e outros detestaram, online que foi pra lama quando o serviço PSN desligou, modo Top Gear que era estranho. A crítica na época foi mista, e eu lembro de comunidades inteiras brigando sobre se o jogo era decepção ou genial.</p>
<p>Pra mim, é genial. GT5 tem o Course Maker (edita tua própria pista baseada em seções reais), o Nurburgring 24h real com chuva dinâmica, o Moon Rover (sim, modo de dirigir na Lua), Red Bull X-Challenge com Vettel, e a experiência de endurance single-player é ridiculamente grande. Quem entrou no jogo a fundo sabe que tem conteúdo pra ano inteiro.</p>
<p>No RPCS3 em 2026, GT5 roda <strong>muito bem</strong>. Estável, sem os bugs graves de anos passados. É o GT mais estável que eu tenho emulado hoje.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Serial</td>
          <td>BCUS98114 (US) ou BCES00569 (EU)</td>
      </tr>
      <tr>
          <td>Resolution Scale</td>
          <td>300%</td>
      </tr>
      <tr>
          <td>Shader Precision</td>
          <td>Ultra</td>
      </tr>
      <tr>
          <td>Force High Precision Z</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>SPU XFloat</td>
          <td>Accurate</td>
      </tr>
      <tr>
          <td>Multithreaded RSX</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>WCB / RCB</td>
          <td>Desligados</td>
      </tr>
  </tbody>
</table>
<p>A combinação Shader Precision Ultra + Force High Precision Z mata o dithering típico do RSX que fazia GT5 parecer granulado em RPCS3 antigamente. Sem esses dois, o asfalto parece ter ruído constante. Com eles, o jogo fica limpo.</p>
<h3>Gran Turismo 6<span class="hx:absolute hx:-mt-20" id="gran-turismo-6"></span>
    <a href="#gran-turismo-6" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%206.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>GT6 é um dos meus preferidos da série. Saiu em 2013 pra um PS3 no final de vida, enquanto a concorrência já olhava pra PS4. Vendeu mal. Muita gente não jogou. E é uma pena, porque GT6 pegou a base do GT5, cortou a gordura (Standards foram reduzidos), adicionou mais Premiums, sessões em circuito no Moon melhores, meteorologia dinâmica em mais pistas, refinamento de física. É basicamente o GT5 polido.</p>
<p>Em conteúdo, GT6 é comparável ao GT4. Muitos jogadores da velha guarda botam o GT4 acima por causa do charme da era PS2. Eu fico entre os dois e vou mais pro GT6 em dia normal, GT4 em dia nostálgico.</p>
<p>Em RPCS3, GT6 tem uma pegadinha grave: <strong>patches 1.06 em diante regridem visualmente</strong>. Superfícies pretas em carros no menu garagem, flicker em cockpit view, tela inteira piscando em certas pistas. A versão que funciona bem em 2026 é <strong>travada em v1.05</strong>. O script <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/scripts/extract_ps3_dlc.py"target="_blank" rel="noopener"><code>extract_ps3_dlc.py</code></a> do repo tem um ceiling por título específico pra pinar GT6 em 1.05 mesmo quando o PSN cuspa 1.22 como &ldquo;mais recente&rdquo;.</p>
<p>Além disso, Force CPU Blit é mandatório. Sem ele, tem flicker de tela inteira em menu. O trade-off é que o retrovisor fica permanentemente preto. Eu prefiro perder o retrovisor a ter o flicker. Quem quer retrovisor pode ligar Write Color Buffers, mas aí a resolução cai pra 720p nativo.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Serial</td>
          <td>BCES01893 + variantes regionais</td>
      </tr>
      <tr>
          <td>Versão travada</td>
          <td>v1.05 (patches 1.06+ causam black surfaces)</td>
      </tr>
      <tr>
          <td>Resolution Scale</td>
          <td>300% (menus) ou 200% (gameplay pesada)</td>
      </tr>
      <tr>
          <td>Force CPU Blit</td>
          <td>Ligado (mandatório, mata flicker)</td>
      </tr>
      <tr>
          <td>WCB</td>
          <td>Desligado (trade-off: retrovisor preto)</td>
      </tr>
      <tr>
          <td>Shader Precision</td>
          <td>Ultra</td>
      </tr>
  </tbody>
</table>
<p>Em 2026, com essas configs, GT6 tá no meu rodízio. Não é perfeito, mas é jogável o suficiente pra eu passar uma tarde fazendo endurance.</p>
<h3>Ridge Racer 7<span class="hx:absolute hx:-mt-20" id="ridge-racer-7"></span>
    <a href="#ridge-racer-7" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Ridge Racer 7 foi lançamento do PS3 em 2006 e é o último mainline da franquia. Arcade igual Ridge Racer V, drift-first, trilha sonora eletrônica, câmera cinemática. Pra PS3 da época era uma demo tecnológica bonita.</p>
<p>No RPCS3 ele roda, mas com caveats: requer Write Color Buffers ligado pra não ter problemas de iluminação, e o preset recomendado na compat DB é diferente do meu preset GT. Eu uso config per-game dedicada pra ele. Não é meu favorito, mas tá lá pra completude.</p>
<p>Sem vídeo pra esse, gravo depois.</p>
<h2>Xbox 360 no Xenia Canary<span class="hx:absolute hx:-mt-20" id="xbox-360-no-xenia-canary"></span>
    <a href="#xbox-360-no-xenia-canary" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui tá a parte que mais me deu dor de cabeça nesse domingo. Xbox 360 no Linux é território hostil. Xenia roda via Wine, cada jogo tem tweaks específicos, title updates tem que vir do archive.org, e Forza Motorsport 4 especificamente tinha problemas sérios até pouco tempo atrás.</p>
<h3>Forza Motorsport 4 (o GOAT)<span class="hx:absolute hx:-mt-20" id="forza-motorsport-4-o-goat"></span>
    <a href="#forza-motorsport-4-o-goat" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20motorsport%204.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FM4 é, pra muita gente, o melhor Forza Motorsport já lançado. Polyphony fez Gran Turismo, Turn 10 fez Forza, e FM4 é o pico da era 360. Modelos de carro belíssimos pra época, pistas bem construídas, física sólida sem ser simulador puro, Autovista mode com narração do Jeremy Clarkson, trilha sonora épica, e aquela sensação de Xbox 360 sendo usado no limite.</p>
<p>FM4 no Xenia <strong>era um pesadelo até recentemente</strong>. Shadow com artefato severo, texture pop-in constante no carro, textura de pista chiada e pixelada, céu com brilho completamente errado (ficava branco-estourado em vez do azul profundo original), e o pior: crash de áudio frequente, onde o XMA (codec proprietário do Xbox 360) travava e o som virava ruído agudo até congelar o jogo. Eu passei horas nesse domingo mexendo em config, testando builds, procurando issue no xenia-canary, testando diferentes title updates.</p>
<p>O que destravou:</p>
<ul>
<li><strong>Build Xenia Canary mais recente</strong> (o <code>master</code> tá parado, Canary acompanha desenvolvimento ativo)</li>
<li><strong>Render Target Path:</strong> <code>rtv</code> (o default funciona bem pra FM4)</li>
<li><strong>Title Update 1.0.17.0</strong> instalado via Xenia Manager (versão importa, mais velha dá regressão em sombras)</li>
<li><strong>GPU Vulkan com ICD NVIDIA forçado</strong> (no meu setup híbrido com AMD iGPU, tinha que forçar a 5090)</li>
</ul>
<p>Depois disso, FM4 rodou. Não é perfeito. Ainda tem algum crash esporádico de áudio (<a href="https://github.com/xenia-canary/xenia-canary/issues/161"target="_blank" rel="noopener">xenia-canary issue #161</a> aberta). Mas é jogável, e eu passei umas duas horas do domingo no Top Gear Test Track só apreciando o Koenigsegg CCX. Valeu cada hora de debug.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>Xenia Canary recente</td>
      </tr>
      <tr>
          <td>Render Target Path</td>
          <td><code>rtv</code> (default)</td>
      </tr>
      <tr>
          <td>Title Update</td>
          <td>1.0.17.0</td>
      </tr>
      <tr>
          <td>Wine Prefix</td>
          <td>dedicado via Xenia Manager</td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>NVIDIA via <code>VK_ICD_FILENAMES</code> hardforce</td>
      </tr>
  </tbody>
</table>
<h3>Forza Motorsport 3<span class="hx:absolute hx:-mt-20" id="forza-motorsport-3"></span>
    <a href="#forza-motorsport-3" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20motorsport%203.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FM3 é uma das entradas boas da série, entre o charme áspero do FM2 e o pico técnico do FM4. Tentar emular foi surpreendentemente chato, porque eu tava usando a ISO errada.</p>
<p>Existem dois releases do FM3: o <strong>retail</strong> (disco original vendido em loja) e o <strong>Ultimate Edition</strong> (com todas as DLCs empacotadas num segundo disco). Eu tava tentando rodar o Ultimate, que combina dois discos numa ISO híbrida que o Xenia não parseia direito. Troquei pro retail padrão + DLCs instaladas separadamente via Title Update, e bingo, o jogo rodou na primeira.</p>
<p>Moral: se teu FM3 não tá rodando no Xenia, verifica se é retail. Ultimate dá problema.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Versão</td>
          <td>Retail (NÃO Ultimate Edition)</td>
      </tr>
      <tr>
          <td>Build</td>
          <td>Xenia Canary recente</td>
      </tr>
      <tr>
          <td>Render Target Path</td>
          <td><code>rtv</code></td>
      </tr>
      <tr>
          <td>DLCs</td>
          <td>Instaladas via Xenia Manager separadamente</td>
      </tr>
  </tbody>
</table>
<h3>Forza Motorsport 2<span class="hx:absolute hx:-mt-20" id="forza-motorsport-2"></span>
    <a href="#forza-motorsport-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20motorsport%202.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FM2 é da era 2007, primeira-gen do 360. Sistemas menos refinados, modelagem mais básica, mas aquele charme de Forza original que alguns preferem à sofisticação do FM4. No Xenia rodou praticamente out-of-the-box. Nenhum tweak especial.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>Xenia Canary</td>
      </tr>
      <tr>
          <td>Render Target Path</td>
          <td>default</td>
      </tr>
  </tbody>
</table>
<h3>Forza Horizon 2<span class="hx:absolute hx:-mt-20" id="forza-horizon-2"></span>
    <a href="#forza-horizon-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20horizon%202.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FH2 foi o Forza Horizon mais polido da geração 360 (existe também a versão Xbox One, que é melhor tecnicamente, mas o 360 tem seu charme por causa do mapa menor e da progressão mais focada). Mundo aberto no sul da Europa, trilha sonora icônica, festival Horizon no seu pico.</p>
<p>No Xenia rodou sem pedir nada extra. Como o FM2.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>Xenia Canary</td>
      </tr>
      <tr>
          <td>Render Target Path</td>
          <td>default</td>
      </tr>
  </tbody>
</table>
<h3>Forza Horizon 1 (com XE Mod)<span class="hx:absolute hx:-mt-20" id="forza-horizon-1-com-xe-mod"></span>
    <a href="#forza-horizon-1-com-xe-mod" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20horizon%201%20xe%20mod.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FH1 original roda OK no Xenia, mas tem uma comunidade que mantém o <strong>Forza Horizon 1 XE Mod</strong>, que melhora IA do tráfego, rebalanceia progressão, adiciona carros que ficaram de fora, corrige bugs conhecidos, e traz uns quality-of-life tweaks na UI. Eu testei o XE Mod nesse domingo e vale a pena. O jogo parece mais vivo e progressão mais justa.</p>
<p>Detalhes da instalação do XE Mod estão no site do projeto. Basicamente é patch sobre a ISO original + alguns title updates customizados.</p>
<p>Pra comparação, aqui é o FH1 <strong>sem</strong> o mod, rodando puro:</p>
<video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20horizon%201.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>A diferença mais visível é no tráfego e na variedade de situações que aparecem, mas o XE Mod tem muita coisa que você só percebe depois de algumas horas.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>Xenia Canary</td>
      </tr>
      <tr>
          <td>XE Mod</td>
          <td>Aplicado sobre ISO original</td>
      </tr>
      <tr>
          <td>Title Updates</td>
          <td>Version pinada pelo XE Mod</td>
      </tr>
  </tbody>
</table>
<h3>Project Gotham Racing 3 e 4<span class="hx:absolute hx:-mt-20" id="project-gotham-racing-3-e-4"></span>
    <a href="#project-gotham-racing-3-e-4" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>PGR3 foi lançamento do 360 em 2005 e continua lindo hoje. Pistas urbanas (Nova York, Tokyo, Nurburgring, Las Vegas), kudos system, câmera cinemática. PGR4 adicionou clima dinâmico (chuva e neve) e motos (algumas pessoas adoram, eu prefiro fingir que não existe).</p>
<p>PGR3 no Xenia Canary roda razoavelmente bem com configs default. PGR4 precisa de tweak específico: <strong><code>render_target_path_vulkan = &quot;fsi&quot;</code></strong> no config. Sem isso, algumas pistas quebram com artefato visual severo (barras verdes atravessando a tela em corridas de neve).</p>
<p>E PGR4 no NVIDIA tem um bug conhecido de áudio: decoding XMA gera garbage intermitente (issue aberta no xenia-canary, sem resolução). Não é game-breaking, mas incomoda.</p>
<table>
  <thead>
      <tr>
          <th>Jogo</th>
          <th>Config relevante</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>PGR3</td>
          <td>Default</td>
      </tr>
      <tr>
          <td>PGR4</td>
          <td><code>render_target_path_vulkan = &quot;fsi&quot;</code>, aceitar bug de áudio XMA</td>
      </tr>
  </tbody>
</table>
<h3>Ridge Racer 6<span class="hx:absolute hx:-mt-20" id="ridge-racer-6"></span>
    <a href="#ridge-racer-6" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Ridge Racer 6 foi o Ridge Racer do 360, pula o 7 que ficou em PS3. Arcade puro, igual Ridge Racer V do PS2. No Xenia Canary roda com config default, sem tweak especial. É divertido pra sessão curta. Sem vídeo dele no artigo, mas tá no catálogo rodando.</p>
<h2>PS4 no shadPS4: o estado do emulador<span class="hx:absolute hx:-mt-20" id="ps4-no-shadps4-o-estado-do-emulador"></span>
    <a href="#ps4-no-shadps4-o-estado-do-emulador" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://shadps4.net/"target="_blank" rel="noopener">shadPS4</a> <strong>ainda não tem release estável</strong>. O projeto tá em desenvolvimento ativo, main branch muda várias vezes por semana, e &ldquo;o que funciona hoje&rdquo; pode regredir num rebase amanhã. Dito isso, <strong>muitos jogos já bootam e rodam bem o suficiente</strong>. Lista da comunidade tá no <a href="https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues"target="_blank" rel="noopener">compatibility tracker</a> e cresce toda semana.</p>
<p>A diferença entre shadPS4 e os outros emuladores desse artigo é o tipo de esforço. PCSX2, RPCS3, Xenia são projetos maduros onde cada jogo tem uma página de wiki razoavelmente atualizada. shadPS4 é o oposto: você lê um guia do Reddit, tenta reproduzir, descobre que o guia usa um fork específico (não o main oficial), ou um commit de dois meses atrás, ou um firmware com <code>sys_modules</code> linkados de jeito particular, ou patches XML aplicados numa ordem específica que o autor não documentou. Reproduzir setup de shadPS4 a partir de vídeo YouTube é tentar resolver Rubik&rsquo;s Cube com venda.</p>
<p>Mas isso não significa que você não deve tentar. Significa que você precisa tratar shadPS4 como brincadeira, não como workflow. E se você tiver paciência, dá pra colher resultados impressionantes.</p>
<h2>Driveclub: o impossível, finalmente possível<span class="hx:absolute hx:-mt-20" id="driveclub-o-impossível-finalmente-possível"></span>
    <a href="#driveclub-o-imposs%c3%advel-finalmente-poss%c3%advel" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/driveclub.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Driveclub é meu Moby Dick da emulação. É o único jogo de PS4 que eu quero muito rodar. Saiu em 2014 pela Evolution Studios, teve lançamento catastrófico (servers online colapsaram no dia 1), foi patchado durante dois anos até virar um dos melhores jogos de corrida da geração, e foi descontinuado pela Sony quando a Evolution foi fechada em 2016. Não tem port pra PC. Não tem remaster. Não tem sequel. Só existe no PS4.</p>
<p>E hoje, depois de muitas horas de debug, <strong>está rodando aqui</strong>. Menu principal carrega, intro roda, corridas começam, controle responde, áudio funciona, pistas de dia visíveis, pistas de noite com faróis iluminando pista. O vídeo acima é gameplay real, a 30 FPS estáveis, v1.28 com conteúdo DLC acessível.</p>
<p>Chegar até aqui exigiu desarmar várias armadilhas. Vale documentar, porque a maioria dos guias online não menciona nenhuma.</p>
<h3>Armadilha 1: o FMOD loop error que não era FMOD<span class="hx:absolute hx:-mt-20" id="armadilha-1-o-fmod-loop-error-que-não-era-fmod"></span>
    <a href="#armadilha-1-o-fmod-loop-error-que-n%c3%a3o-era-fmod" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Quando você tenta bootar Driveclub no shadPS4 direto da PKG retail, o log estoura um loop infinito de:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>/app0/audio/fmodstudio/masterbank.bank failed, file does not exist</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A primeira reação é investigar FMOD. Tem gente na internet que passou horas mexendo em sceFont, libtbb, sceNgs2, convencidos que era problema de áudio ou lib HLE. <strong>Nada disso é a causa</strong>. O arquivo <code>masterbank.bank</code> literalmente não existe no disco, porque ele tá empacotado dentro dos arquivos <code>gameNNN.dat</code> num formato de archive customizado da Evolution Studios que o VFS do shadPS4 não sabe ler. A mesma história vale pra fontes, modelos, shaders. O conteúdo todo do jogo mora dentro dos <code>.dat</code>.</p>
<p>A única ferramenta pública que parse esse formato é o <strong><a href="https://github.com/Nenkai/DriveClubFS"target="_blank" rel="noopener">DriveClubFS do Nenkai</a></strong>. É uma app .NET que lê o <code>game.ndx</code> (o índice) e decomprime os <code>.dat</code> em arquivos soltos. Sem esse unpack, o shadPS4 não consegue abrir nada.</p>
<p>Detalhe de build: o projeto DriveClubFS tá em <code>net9.0</code>, e o Arch tem <code>net8</code> e <code>net10</code>. Precisa retargetar o csproj pra <code>net10.0</code> antes de buildar. O comando exato tá documentado no <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>docs/driveclub-shadps4.md</code></a> do repo.</p>
<h3>Armadilha 2: v1.28 é patch, não instalador base<span class="hx:absolute hx:-mt-20" id="armadilha-2-v128-é-patch-não-instalador-base"></span>
    <a href="#armadilha-2-v128-%c3%a9-patch-n%c3%a3o-instalador-base" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Como em qualquer PS4, update é patch que vai em cima de uma install base. A PKG do v1.28 traz o eboot atualizado, <code>.dat</code> com conteúdo novo e patch content (<code>sce_sys/about/right.sprx</code>), mas <strong>não traz <code>param.sfo</code>, <code>disc_info.dat</code> nem <code>keystone</code></strong>. Esses metadata ficam na base de v1.00 — num PS4 real já estariam gravados do install original.</p>
<p>E tem mais: o <code>game.ndx</code> do v1.28 referencia tanto os <code>.dat</code> da base quanto os novos. Rodar o DriveClubFS contra só o v1.28 faz o índice apontar pra arquivos que não tão ali.</p>
<p>O sintoma mais cruel vem depois: o jogo boota, a Qt Launcher mostra o tile, você clica, a tela carrega. Aí o jogo decide que nenhum conteúdo &ldquo;foi lançado ainda&rdquo; e pede pra fazer download. Download obviamente não vai acontecer porque PSN pra PS4 não tá acessível. Você fica travado achando que é bug de rede, quando na verdade é metadata faltando.</p>
<p>O fluxo correto é tratar v1.28 como overlay sobre a base. Primeiro, extrai a PKG de v1.00 pra um dir dedicado (<code>CUSA00003.v100-working-backup/</code> funciona bem, e dobra como snapshot de rollback se algum experimento quebrar a instalação viva). Depois extrai o v1.28 pra staging e linka os <code>.dat</code> de índice baixo da base dentro do staging pra o DriveClubFS enxergar o set completo. Roda o unpack. Sai com 8018 arquivos soltos, ~47 GB.</p>
<p>Move pra <code>CUSA00003/</code> final, copia o eboot e conteúdo novo do v1.28 por cima, e puxa <code>param.sfo</code>, <code>disc_info.dat</code> e <code>keystone</code> da base de v1.00. O <code>param.sfo</code> da base já vem com <code>APP_VER = 01.28</code> gravado (porque ela recebeu o patch original), então não tem conflito de versão. O eboot v1.28 lê esses arquivos e libera o conteúdo.</p>
<h3>Armadilha 3: o patch XML de 60fps gera slow-motion<span class="hx:absolute hx:-mt-20" id="armadilha-3-o-patch-xml-de-60fps-gera-slow-motion"></span>
    <a href="#armadilha-3-o-patch-xml-de-60fps-gera-slow-motion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Tem um <code>Driveclub.xml</code> patch comunitário que faz o jogo renderizar a 60fps. Intuitivamente, parece ganho puro. Na prática, o patch reescreve o render rate mas não mexe no logic tickrate interno do jogo, que é fixo em 30fps. Num PS4 Pro real, o hardware reconcilia a diferença. No shadPS4, não.</p>
<p>Resultado: o jogo renderiza liso a 60fps, mas toda a física, AI, áudio, timing de corrida roda em câmera lenta. Você aperta acelerador e o carro leva dois segundos perceptíveis pra sair. Parece bug aleatório até você entender o mismatch.</p>
<p>Desabilitar o patch XML resolve (basta renomear o arquivo pra algo como <code>.disabled</code>). Sem o patch, o jogo fica a 30 FPS nativos, mesma velocidade do PS4 base stock. Que é o que a gente quer. Se alguém conseguir no futuro fazer um patch que mexa nos dois rates (render + logic), a gente religa.</p>
<h3>Armadilha 4: pipeline cache precisa estar ligado<span class="hx:absolute hx:-mt-20" id="armadilha-4-pipeline-cache-precisa-estar-ligado"></span>
    <a href="#armadilha-4-pipeline-cache-precisa-estar-ligado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Default do shadPS4 vem com <code>pipeline_cache_enabled = false</code>. Num jogo grande como Driveclub, que tem centenas de shaders e pipelines Vulkan, isso significa que cada cold launch recompila tudo. Nos meus testes o primeiro launch contou ~864 shaders e ~590 pipelines sendo compilados em tempo real. O menu animava a 2-3 fps. Um minuto depois, com tudo compilado, saltava pra fluidez normal. Próximo launch, mesmo ciclo de compilação do zero.</p>
<p>Basta ligar <code>&quot;pipeline_cache_enabled&quot;: true</code> no <code>config.json</code> global. Primeira sessão paga o custo único de compilação, sessões seguintes leem do cache e sobem direto.</p>
<h3>Armadilha 5: TOML silenciosamente ignorado<span class="hx:absolute hx:-mt-20" id="armadilha-5-toml-silenciosamente-ignorado"></span>
    <a href="#armadilha-5-toml-silenciosamente-ignorado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O shadPS4 migrou de TOML pra JSON em config per-game em late 2025. Se você tem um <code>CUSA00003.toml</code> antigo na pasta <code>custom_configs/</code>, ele é silenciosamente ignorado, sem warning no log. Você pensa que sua config tá ativa, na prática tá rodando tudo default.</p>
<p>Deleta qualquer TOML e usa <code>CUSA00003.json</code>. As configs per-game que funcionam pra Driveclub são específicas e detalhadas, documentei todas no <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>docs/driveclub-shadps4.md</code></a> do repo.</p>
<h3>Armadilha 6: controle não detectado sem hidapi hints<span class="hx:absolute hx:-mt-20" id="armadilha-6-controle-não-detectado-sem-hidapi-hints"></span>
    <a href="#armadilha-6-controle-n%c3%a3o-detectado-sem-hidapi-hints" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Qt Launcher do shadPS4 chama um <code>Shadps4-sdl.AppImage</code> interno. Sem env vars específicas do SDL hidapi, o controle (no meu caso 8BitDo Ultimate 2) não é detectado, mesmo funcionando em outros emuladores. O fix é wrapar o AppImage num shell que exporta <code>SDL_JOYSTICK_HIDAPI=1</code> e variantes específicas por plataforma (PS4, PS5, Xbox), antes de executar o original.</p>
<p>Plugar o controle <strong>antes</strong> de abrir o Qt Launcher também ajuda. Hot-plug funciona durante o jogo, não antes.</p>
<h3>Armadilha 7: pistas de noite ficam pretas no upstream<span class="hx:absolute hx:-mt-20" id="armadilha-7-pistas-de-noite-ficam-pretas-no-upstream"></span>
    <a href="#armadilha-7-pistas-de-noite-ficam-pretas-no-upstream" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Esse aqui é o único que precisou de patch de código, não só config. No upstream do shadPS4, pistas de Driveclub à noite ficavam pretas. HUD aparecia em cima, mas pista, carro, tudo escondido num preto absoluto. Faróis do próprio carro não iluminavam nada.</p>
<p>Investigação apontou pro log repetindo 1325 vezes a mensagem <code>ResolveDepthOverlap: Unimplemented depth overlap copy</code>. A causa: o Driveclub usa renderer forward+, que escreve a profundidade da cena num buffer MSAA 4x D32Sfloat, depois lê esse mesmo buffer como <code>R32G32B32A32Sfloat</code> 1x pra efeitos tipo SSAO, volumetrics e iluminação dinâmica (faróis). O shadPS4 upstream tem caminho pra MSAA → MSAA e pra cor → cor como MSAA depth, mas <strong>não tinha caminho pra &ldquo;MSAA depth de 4x vira color de 1x&rdquo;</strong> nesse formato específico. Cai no <code>else</code> final, libera o buffer, e o shader lê lixo não inicializado — ou seja, preto.</p>
<p>Implementei no meu fork local do shadPS4 um <code>ReinterpretMsDepthAsColor</code> simétrico aos <code>ReinterpretColorAsMsDepth</code> que já existiam. É um fragment shader minúsculo (<code>ms_depth_to_color.frag</code>) que faz <code>texelFetch</code> da profundidade sample 0 e escreve como <code>vec4(depth, 0, 0, 1)</code> no attachment de cor. Plus um helper no <code>BlitHelper</code> e um novo <code>else if</code> no <code>TextureCache::ResolveDepthOverlap</code>. Com isso, pistas de noite iluminam corretamente, faróis dos oponentes aparecem, AO e volumetrics no dia também ficam mais precisos.</p>
<p>O fix tá num branch <code>gamma-debug</code> do meu fork, pronto pra virar PR upstream. Enquanto não mergeia, quem quer rodar Driveclub à noite no shadPS4 precisa buildar desse branch. Quem fica só em corridas de dia pode usar o upstream nightly direto.</p>
<h3>O que finalmente funcionou<span class="hx:absolute hx:-mt-20" id="o-que-finalmente-funcionou"></span>
    <a href="#o-que-finalmente-funcionou" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><table>
  <thead>
      <tr>
          <th>Componente</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>shadPS4</td>
          <td>Pre-release (nightly) do upstream pra dia; fork <code>gamma-debug</code> pra noite (até MSAA depth fix mergear)</td>
      </tr>
      <tr>
          <td>Driveclub</td>
          <td><strong>v1.28 base</strong> (cumulative-patch, ~47 GB, 8018 arquivos)</td>
      </tr>
      <tr>
          <td>Extração</td>
          <td><a href="https://github.com/shadps4-emu/ShadPKG"target="_blank" rel="noopener">ShadPKG</a> → <a href="https://github.com/Nenkai/DriveClubFS"target="_blank" rel="noopener">DriveClubFS</a> (retargetado pra net10.0)</td>
      </tr>
      <tr>
          <td>Metadata</td>
          <td>Restaurar <code>param.sfo</code>, <code>disc_info.dat</code>, <code>keystone</code> da PKG v1.00</td>
      </tr>
      <tr>
          <td>Config global</td>
          <td><code>pipeline_cache_enabled: true</code>, <code>readbacks_mode: 0</code></td>
      </tr>
      <tr>
          <td>Config per-game</td>
          <td>JSON em <code>custom_configs/CUSA00003.json</code></td>
      </tr>
      <tr>
          <td><code>vblank_frequency</code></td>
          <td>60</td>
      </tr>
      <tr>
          <td><code>gpu_id</code></td>
          <td>0 (NVIDIA dGPU hardforced)</td>
      </tr>
      <tr>
          <td><code>Driveclub.xml</code> patch</td>
          <td><strong>Desabilitado</strong> (60fps gera slow-motion, causa raiz: logic tickrate fixo)</td>
      </tr>
      <tr>
          <td>Controle</td>
          <td>Wrapper AppImage com <code>SDL_JOYSTICK_HIDAPI=1</code> + variantes</td>
      </tr>
      <tr>
          <td>Qt Launcher</td>
          <td><code>checkForUpdates=false</code> pra evitar dialog rate-limit do GitHub</td>
      </tr>
  </tbody>
</table>
<p>Tudo isso tá encapsulado no <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>docs/driveclub-shadps4.md</code></a> do repo, com o passo a passo exato de extração, config e wrapper. A investigação técnica completa (5 fases, engineering log detalhado) tá no <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-v128-investigation.md"target="_blank" rel="noopener"><code>driveclub-v128-investigation.md</code></a> do fork.</p>
<h3>Quão jogável tá hoje<span class="hx:absolute hx:-mt-20" id="quão-jogável-tá-hoje"></span>
    <a href="#qu%c3%a3o-jog%c3%a1vel-t%c3%a1-hoje" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Bom. O vídeo acima é gameplay real, a 30 FPS estáveis, com física respondendo, áudio sincronizado, HUD correto, v1.28 com DLC acessível. Corridas de dia e de noite funcionam (com o fork do MSAA depth pra noite). O que sobra de limitação:</p>
<ul>
<li><strong>Brilho de dia um pouco abaixo do que o PS4 entregava.</strong> Não é bug do emulador. Passei horas testando tonemap, auto-exposure, gamma curves, ACES, vários shaders de post-processing, e no fim descobri que o jogo <strong>escreve SDR já correto</strong> no framebuffer. O que estava faltando era o pipeline de calibração de display que o firmware 4.0+ do PS4 aplicava por fora, e que o Linux não tem. O slider de brilho in-game (que no shadPS4 mapeia pra <code>sceVideoOutAdjustColor</code>) funciona, mas só vai até o ponto que o jogo pensou que seria complementado pelo firmware. A cena de 5 segundos escuros no início da corrida também é fade-in cinematográfico do jogo, não falha de emulador. Aceitei.</li>
<li><strong>30 FPS nativos.</strong> Sem patch de 60fps viável (pelo motivo do logic tickrate fixo). Stock PS4 speed.</li>
<li><strong>MSAA depth fix ainda no fork.</strong> Tem PR candidate pronto, aguardando upstream mergear.</li>
</ul>
<p><strong>&ldquo;Achievement Unlocked&rdquo;.</strong> O jogo roda, com som, controle, jogabilidade, dia e noite, e eu completo corrida inteira sem crash. Isso é um marco pessoal. Eu passei anos tentando fazer esse jogo rodar no Linux e chegava num ponto onde simplesmente desistia. Agora é parte do meu ES-DE, atalho no desktop, tá lá esperando eu sentar pra jogar.</p>
<p>Se você quer replicar, o repo tá público. Boa sorte. Vai precisar de paciência.</p>
<h2>&ldquo;Achievement Unlocked&rdquo;<span class="hx:absolute hx:-mt-20" id="achievement-unlocked"></span>
    <a href="#achievement-unlocked" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu venho tentando fazer esses jogos funcionarem, em algum nível, desde que cada respectivo emulador saiu de alpha. GT2 eu tô rodando desde ePSXe. GT4 eu mexo desde PCSX2 0.9.6. FM4 eu tentei fazer rodar em Xenia duas vezes em anos anteriores e desisti nas duas. E Driveclub eu olhei pra cara do shadPS4 três vezes antes desse domingo e engoli em seco.</p>
<p>Hoje fechou. Os dois monstros que abriram esse artigo (Driveclub no shadPS4 e FM4 com Project Forza Plus no Xenia) estão rodando, junto com todo o resto da coleção de Gran Turismo, Forza, Ridge Racer, Colin McRae e Enthusia. Tudo num setup único, reproduzível, automatizado. Agora eu faço parte do <strong>grupo bem pequeno de pessoas que conseguiu brute force emular Driveclub no Linux</strong>, e isso sozinho já tornou o domingo inesquecível.</p>
<p>A frustração de anos não era falta de informação. Era o OPOSTO. Informação demais, mal indexada, espalhada em fóruns apagados, vídeos YouTube que ficaram datados, threads Reddit com soluções pra versão do emulador de dois anos atrás que não valem hoje, wiki de projeto desatualizada em metade das páginas, e mods com requisitos MUITO específicos de CRC, versão, patch, path, setting. Cada vez que eu sentava pra fazer um desses jogos rodar direito, eu ficava três horas lendo material conflitante antes de escrever a primeira linha de config. Pior ainda quando o material bom estava enterrado entre diagnósticos errados, tipo o FMOD loop do Driveclub que todo mundo investigava como se fosse problema de áudio quando na real era formato de archive proprietário da Evolution Studios.</p>
<p>O que mudou nesse último ano é que Claude Code consegue ser meu agregador. Eu peço pro Claude ir na issue tracker do Xenia, na wiki do PCSX2, no subreddit do RPCS3, nos PRs do shadPS4, comparar todas as informações com a versão atual do emulador instalada, cruzar com os logs que eu tô vendo, e me devolver a combinação que funciona hoje. Ele lê source code quando precisa, entende por que <code>Force CPU Blit</code> muda comportamento no GT6, acha qual title update do FM4 foi o que consertou o shadow bug, descobre que o DriveClubFS precisa de retarget pra .NET 10 antes de compilar. O que antes levava três fins de semana pesquisando agora leva uma tarde de execução assistida.</p>
<p>Esse domingo é o resultado consolidado de todo esse trabalho. <a href="https://github.com/akitaonrails/distrobox-gaming"target="_blank" rel="noopener">distrobox-gaming</a> é a versão desse conhecimento virada código, reprodutível, automatizada. Rodando numa máquina fresca, um <code>ansible-playbook site.yml</code> me põe de volta nesse estado em menos de duas horas. Menos de 10 comandos separam &ldquo;Arch Linux vanilla&rdquo; de &ldquo;Driveclub rodando&rdquo;.</p>
<p>Se alguém quiser contribuir, testar em outro hardware, reportar bug ou mandar config que ficou faltando, o repo tá aberto. Quanto mais gente testar em setups diferentes, mais resiliente o projeto fica. Se você melhorar a situação do Driveclub (mergear o MSAA depth fix upstream, patch de 60fps que também corrija o logic tickrate, dump de fontes que não precise hardware jailbroken), manda PR que eu abraço.</p>
<p>Por enquanto, eu vou fazer uma corrida na Islândia no Driveclub. Boa noite de domingo.</p>
]]></content:encoded><category>games</category><category>emulacao</category><category>linux</category></item><item><title>Meu Cockpit de Sim Racing - Formula FX1</title><link>https://akitaonrails.github.io/2026/04/01/meu-cockpit-de-sim-racing-formula-fx1/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/04/01/meu-cockpit-de-sim-racing-formula-fx1/</guid><pubDate>Wed, 01 Apr 2026 17:00:00 -0300</pubDate><description>&lt;p&gt;Eu gosto de carros desde que me entendo por gente. Meu primeiro contato real com jogos de corrida foi nos fliperamas dos anos 80 e 90. E quando eu digo &amp;ldquo;real&amp;rdquo;, eu digo sentar num cabinet com volante, pedal, banco de plástico duro e a tela curvando na sua frente. &lt;a href="https://en.wikipedia.org/wiki/Out_Run"target="_blank" rel="noopener"&gt;OutRun&lt;/a&gt; (1986), &lt;a href="https://en.wikipedia.org/wiki/Rad_Mobile"target="_blank" rel="noopener"&gt;Rad Mobile&lt;/a&gt; (1991), &lt;a href="https://en.wikipedia.org/wiki/Virtua_Racing"target="_blank" rel="noopener"&gt;Virtua Racing&lt;/a&gt; (1992), &lt;a href="https://en.wikipedia.org/wiki/Ridge_Racer"target="_blank" rel="noopener"&gt;Ridge Racer&lt;/a&gt; (1993), &lt;a href="https://en.wikipedia.org/wiki/Daytona_USA_%28video_game%29"target="_blank" rel="noopener"&gt;Daytona USA&lt;/a&gt; (1994), &lt;a href="https://en.wikipedia.org/wiki/Scud_Race"target="_blank" rel="noopener"&gt;Scud Race&lt;/a&gt; (1996). Cada um desses jogos me marcou. Mas o Daytona USA ficou gravado de outro jeito. Aquele cabinet twin, duas máquinas lado a lado, a música &amp;ldquo;DAYTONAAA, let&amp;rsquo;s go away&amp;rdquo; estourando no fliperama, o volante vibrando na mão. Eu lembro disso até hoje.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu gosto de carros desde que me entendo por gente. Meu primeiro contato real com jogos de corrida foi nos fliperamas dos anos 80 e 90. E quando eu digo &ldquo;real&rdquo;, eu digo sentar num cabinet com volante, pedal, banco de plástico duro e a tela curvando na sua frente. <a href="https://en.wikipedia.org/wiki/Out_Run"target="_blank" rel="noopener">OutRun</a> (1986), <a href="https://en.wikipedia.org/wiki/Rad_Mobile"target="_blank" rel="noopener">Rad Mobile</a> (1991), <a href="https://en.wikipedia.org/wiki/Virtua_Racing"target="_blank" rel="noopener">Virtua Racing</a> (1992), <a href="https://en.wikipedia.org/wiki/Ridge_Racer"target="_blank" rel="noopener">Ridge Racer</a> (1993), <a href="https://en.wikipedia.org/wiki/Daytona_USA_%28video_game%29"target="_blank" rel="noopener">Daytona USA</a> (1994), <a href="https://en.wikipedia.org/wiki/Scud_Race"target="_blank" rel="noopener">Scud Race</a> (1996). Cada um desses jogos me marcou. Mas o Daytona USA ficou gravado de outro jeito. Aquele cabinet twin, duas máquinas lado a lado, a música &ldquo;DAYTONAAA, let&rsquo;s go away&rdquo; estourando no fliperama, o volante vibrando na mão. Eu lembro disso até hoje.</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/2/24/DaytonaUSA_arcade_SaoPaulo.jpg" alt="Máquinas de Daytona USA num shopping de São Paulo — exatamente o tipo de cabinet twin que ficou gravado na minha memória"  loading="lazy" /></p>
<p>Mas o jogo que realmente me viciou no gênero simcade foi o <a href="https://en.wikipedia.org/wiki/Gran_Turismo_%28video_game%29"target="_blank" rel="noopener">Gran Turismo</a> original, em 1997, no PlayStation 1. &ldquo;The Real Driving Simulator&rdquo; na capa. Eu joguei aquele jogo obsessivamente. Na mesma época eu assistia o anime <a href="https://en.wikipedia.org/wiki/Initial_D"target="_blank" rel="noopener">Initial D</a>, que estreou em 1998 no Japão. Comprei todos os mangás e li tudo do começo ao fim. A história do Takumi Fujiwara descendo o Monte Akina de madrugada entregando tofu no AE86 do pai dele é, pra mim, uma das melhores histórias de automobilismo já contadas em qualquer mídia.</p>
<p>Até hoje eu acompanho o trabalho do Shuichi Shigeno. Depois de Initial D veio <a href="https://kodansha.us/series/mf-ghost/"target="_blank" rel="noopener">MF Ghost</a> (2017-2025), que se passa no mesmo universo mas num futuro próximo onde carros a combustão viraram peça de museu. E agora, desde julho de 2025, estou lendo <a href="https://kmanga.kodansha.com/title/10664/episode/360584"target="_blank" rel="noopener">Subaru and Subaru</a>, a continuação direta que une os universos de Initial D e MF Ghost com duas protagonistas chamadas Subaru — uma de Gunma, outra de Kanagawa — competindo numa nova série de corridas. É o Shigeno no melhor dele.</p>
<p><a href="https://kmanga.kodansha.com/title/10664/episode/360584"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/subaru-x-subaru-cover.png" alt="Subaru and Subaru — o novo mangá do Shigeno, continuação direta de Initial D e MF Ghost"  loading="lazy" /></a></p>
<p>Dois anos atrás eu viajei pro Japão com minha namorada e fiz questão de ir na <a href="https://en.wikipedia.org/wiki/Daikoku_Parking_Area"target="_blank" rel="noopener">Daikoku PA</a>, o famoso parking area na Shuto Expressway em Yokohama onde a cultura JDM se concentra. Como fã antigo de <a href="https://store.steampowered.com/app/2634950/Tokyo_Xtreme_Racer/"target="_blank" rel="noopener">Tokyo Xtreme Racer</a>, da Genki, eu precisava ver Daikoku com meus próprios olhos pelo menos uma vez. E não decepcionou. Em vez de alugar carro, a gente fechou um tour com um guia local no Nissan GT-R preparado dele. Melhor assim. No caminho ele foi explicando a história da Wangan, como a cena funciona, o que é exagero de YouTube e o que é real. Quando chegamos numa sexta à noite e eu vi aquilo tudo ao vivo — Skyline R34, RX-7, Supra, GT-R, kei trucks tunados, bosozoku insanos — a sensação foi estranha no melhor sentido. Parecia Tokyo Xtreme Racer, só que com cheiro de combustível no ar e barulho de escapamento de verdade.</p>
<p>E tem outro detalhe: eu estou jogando o reboot novo de <a href="https://store.steampowered.com/app/2634950/Tokyo_Xtreme_Racer/"target="_blank" rel="noopener">Tokyo Xtreme Racer</a> no PC, e é exatamente o tipo de jogo que entende o próprio público. Campanha single-player forte, progressão viciante, clima certo, e sem aquelas palhaçadas de loot box. Recomendo fácil. Pelo mesmo motivo, eu também estou esperando muito o <a href="https://forza.net/forzahorizon6"target="_blank" rel="noopener">Forza Horizon 6</a>, que dessa vez vai se passar no Japão. Eu já fiz a pré-compra e estou louco pra jogar isso no cockpit novo.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/daikoku---nissan.jpg" alt="Na Daikoku PA com um GT-R modificado"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/daikoku---trueno.jpg" alt="Com um AE86 Trueno na Daikoku PA — o carro do Takumi"  loading="lazy" /></p>
<h2>Dirigindo de verdade<span class="hx:absolute hx:-mt-20" id="dirigindo-de-verdade"></span>
    <a href="#dirigindo-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agora que estou semi-aposentado, tive a oportunidade de levar meu Mercedes em track days. Já andei no <a href="https://en.wikipedia.org/wiki/Aut%C3%B3dromo_Jos%C3%A9_Carlos_Pace"target="_blank" rel="noopener">Autódromo de Interlagos</a> (o Autódromo José Carlos Pace), circuito de 4.309 km em São Paulo que sedia o GP de F1 do Brasil desde 1973, famoso pelas curvas do S do Senna e pelo desnível maluco do circuito. Também andei no <a href="https://www.velocittapark.com.br/"target="_blank" rel="noopener">Autódromo Velocitta</a>, um circuito moderno de 3.443 km inaugurado em 2014 em Mogi Guaçu, interior de São Paulo, que recebe a Stock Car Brasil e a Porsche Cup.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/velocitta.jpg" alt="No Velocitta com meu Mercedes num track day da AMG"  loading="lazy" /></p>
<p>Em Las Vegas eu já dirigi super carros naquelas experiências de pista. E quando viajei com minha namorada pra Gramado, no RS, fomos na <a href="https://supercarros.cc/"target="_blank" rel="noopener">Super Carros</a>, que fica na Av. das Hortênsias 4635. Eles têm um galpão de 2.400 m² com mais de 50 carros — Ferraris, Lamborghinis, Porsches, GT-Rs, Corvettes, muscle cars americanos. Você escolhe o carro, sai com um instrutor, e dirige um percurso de uns 17 km entre Gramado e Canela. Eu peguei um Nissan GT-R e uma Ferrari California.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/gramado---gtr.jpg" alt="Com um GT-R em Gramado"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/gramado---ferrari.jpg" alt="Com uma Ferrari California em Gramado"  loading="lazy" /></p>
<p>Três anos atrás eu também fui pra Abu Dhabi com minha namorada e fomos no Ferrari World, que tem alguns dos melhores simuladores de corrida que eu já experimentei. Plataforma hidráulica com 6 graus de liberdade, cockpit de F1, a coisa toda. Eu sempre adorei testar simuladores onde quer que eu vá.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/ferrari-park.jpg" alt="Simulador de F1 com plataforma hidráulica no Ferrari World em Abu Dhabi"  loading="lazy" /></p>
<p>Mas dirigir carros de verdade em pistas de verdade é um hobby muito caro. Pneus, combustível, seguro, manutenção, inscrição. E o mais importante: eu sou introvertido. Prefiro estar sozinho. Meu cockpit de simulador é perfeito pra quando eu quero dirigir sem ter que lidar com ninguém. É por isso que eu gosto tanto de rally — sou eu, o co-driver virtual, e a estrada. Nada mais.</p>
<h2>Os jogos que eu jogo<span class="hx:absolute hx:-mt-20" id="os-jogos-que-eu-jogo"></span>
    <a href="#os-jogos-que-eu-jogo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sei que a maioria das pessoas que montam um cockpit como esse fazem pra jogar simuladores sérios — iRacing, Assetto Corsa Competizione, Automobilista 2. Eu respeito, mas não é minha praia. Não gosto de jogar online com outras pessoas. Não tenho nenhuma intenção de começar uma carreira de live streaming. Isso é puramente pro meu divertimento.</p>
<p>Atualmente eu jogo Gran Turismo 7 no PS5, <a href="https://store.steampowered.com/app/2440510/Forza_Motorsport/"target="_blank" rel="noopener">Forza Motorsport</a> (o 8, de 2023) no PC, mas onde eu me divirto mais é nos jogos de rally: <a href="https://store.steampowered.com/app/1849250/EA_SPORTS_WRC/"target="_blank" rel="noopener">EA SPORTS WRC</a>, <a href="https://store.steampowered.com/app/1462810/WRC_10_FIA_World_Rally_Championship/"target="_blank" rel="noopener">WRC 10</a> e <a href="https://store.steampowered.com/app/690790/DiRT_Rally_20/"target="_blank" rel="noopener">DiRT Rally 2.0</a>. Minha primeira experiência com Forza foi no Xbox One com o Forza Motorsport 5 e depois Forza Horizon 4, que me prendeu por centenas de horas.</p>
<p>E eu tenho um carinho enorme por jogos retro. O Colin McRae Rally original de 1998 no PS1 foi meu primeiro jogo de rally. Mas o meu favorito de todos os tempos é o Colin McRae Rally 2.0 (2000), também no PS1. Recentemente eu completei a campanha inteira de novo na versão de PC — dá pra achar repacks que rodam em alta resolução e widescreen, muito melhor que as versões originais de PlayStation. Recomendo pra qualquer um dos títulos da série.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/colin-mcrae-rally-2-gameplay.jpg" alt="Colin McRae Rally 2.0 rodando em widescreen no PC — neve na Suécia com o Ford Focus"  loading="lazy" /></p>
<p>Depois vieram Colin McRae 3 (2002), Colin McRae Rally 04 (2003) e Colin McRae 2005 (2004). Outros arcades que eu revisito com frequência: OutRun 2 SP (2004) e OutRun 2006: Coast 2 Coast (2006) — o melhor OutRun já feito, na minha opinião.</p>
<p>Mas meu jogo do ano, disparado, é o <a href="https://store.steampowered.com/app/3218630/Super_Woden_Rally_Edge/"target="_blank" rel="noopener">Super Woden: Rally Edge</a>. Um indie feito por um desenvolvedor solo (ViJuDa, da Espanha) que lançou em janeiro de 2026 por menos de R$ 60. Oito países, mais de 80 carros, modo carreira, multiplayer local split-screen pra até 4 jogadores, leaderboards online. A câmera atrás do carro em vez do top-down dos Super Woden GP anteriores fez toda a diferença. 96% de reviews positivos no Steam com mais de 1.300 avaliações. É o tipo de jogo que mostra que você não precisa de orçamento milionário pra fazer algo incrível.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/super-woden-rally-edge.jpg" alt="Super Woden: Rally Edge — indie feito por um dev solo que compete com os grandes"  loading="lazy" /></p>
<h2>A evolução do meu setup de volante<span class="hx:absolute hx:-mt-20" id="a-evolução-do-meu-setup-de-volante"></span>
    <a href="#a-evolu%c3%a7%c3%a3o-do-meu-setup-de-volante" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Era Logitech G29 (~2015-2021)<span class="hx:absolute hx:-mt-20" id="era-logitech-g29-2015-2021"></span>
    <a href="#era-logitech-g29-2015-2021" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Eu sempre quis um volante de corrida. Comecei há mais de 15 anos com algo equivalente ao volante de entrada da Logitech, um G29. O G29 é um bom volante pra começar — force feedback por engrenagens, pedais com embreagem, 900 graus de rotação. Mas o force feedback dele é barulhento e meio grosseiro. Você sente as engrenagens girando.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/logitech-g29-and-myself.jpeg" alt="Eu jogando com o Logitech G29 no sofá — o começo de tudo"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/logitech-g29-with-support.jpg" alt="O G29 com suporte simples na frente do sofá"  loading="lazy" /></p>
<h3>Era Thrustmaster T300RS + Suporte SXT V2 (~2021-2024)<span class="hx:absolute hx:-mt-20" id="era-thrustmaster-t300rs--suporte-sxt-v2-2021-2024"></span>
    <a href="#era-thrustmaster-t300rs--suporte-sxt-v2-2021-2024" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Por volta de 2021 eu fiz o upgrade pro <a href="https://www.thrustmaster.com/products/t300rs-gt-edition/"target="_blank" rel="noopener">Thrustmaster T300RS</a>, um volante por correia que é um salto enorme em relação ao Logitech. O force feedback é muito mais suave e preciso. E comprei o suporte <a href="https://loja.cockpitextremeracing.com.br/products/suporte-para-volantes-sxt-v2?variant=51111119454489"target="_blank" rel="noopener">Extreme Sim Racing SXT V2</a>, que é bem mais robusto que aqueles suportes de mesa genéricos.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/thrustmaster-with-support.jpg" alt="O Thrustmaster T300RS montado no suporte SXT V2"  loading="lazy" /></p>
<p>Primeiro eu montei o setup na frente do meu PC desktop, que na época tinha uma RTX 3090. Funcionava bem, mas era muito trabalhoso ficar montando e desmontando o suporte e os cabos toda vez que eu queria jogar.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/thrustmaster-with-pc.jpg" alt="O Thrustmaster na frente do PC desktop — funcional mas trabalhoso"  loading="lazy" /></p>
<p>Depois eu fiz um setup com cabo HDMI de fibra óptica longo pra conectar minha TV de 60&quot; ao PC nos fundos da sala. Movi o suporte pra frente do sofá. Menos trabalhoso, mas eu ainda tinha que desmontar quando queria assistir filme com minha namorada.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/thrustmaster-with-big-tv.jpg" alt="Setup com a TV grande — melhor, mas ainda trabalhoso"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/thrustmaster-in-the-living-room.jpg" alt="O suporte na sala de estar — sempre no caminho"  loading="lazy" /></p>
<p>Por volta de 2024 ou 2025 eu troquei meu sofá por um daqueles sofás VIP de cinema da <a href="https://www.starseat.com.br/sofa-cinema-sofa-cinema"target="_blank" rel="noopener">Star Seat</a>, que reclina e tudo. Problema: era muito mais alto que o sofá anterior. Tive que fazer todo tipo de gambiarra pra fazer o suporte funcionar naquela altura. Cheguei a imprimir suportes em 3D e mandar pra PCBWay usinar placas de aço pra prender rodas grandes embaixo do suporte e ganhar uns centímetros de altura. Mas isso deixou o setup muito instável pra dirigir confortavelmente.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/fanatec-support-sofa-too-high.jpg" alt="O problema: sofá VIP alto demais pro suporte — gambiarra total"  loading="lazy" /></p>
<h3>Era Fanatec CSL DD + Direct Drive (~2024-2025)<span class="hx:absolute hx:-mt-20" id="era-fanatec-csl-dd--direct-drive-2024-2025"></span>
    <a href="#era-fanatec-csl-dd--direct-drive-2024-2025" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Nesse meio tempo eu dei o T300 pro meu irmão e fiz o upgrade pra um <a href="https://fanatec.com/eu-en/racing-wheels-wheel-bases/racing-wheels/gran-turismo-dd-pro-5-nm-wheel-base"target="_blank" rel="noopener">Fanatec CSL DD Gran Turismo Edition</a>. O motor direct drive do CSL DD entrega 5 Nm de torque na base, mas o kit Gran Turismo DD Pro já vem com o Boost Kit 180 que sobe pra 8 Nm sustentados sem cooling ativo. Direct drive significa que não tem engrenagem nem correia entre o motor e o volante — o eixo do motor É o eixo do volante. A diferença é absurda. O T300 já era ótimo, muito superior ao Logitech. Mas o Fanatec está em outro patamar. Você sente cada textura do asfalto, cada lombada, cada derrapagem incipiente. Não tem como voltar atrás depois que experimenta.</p>
<p>Comprei junto o kit de <a href="https://fanatec.com/eu-en/pedals/csl-pedals"target="_blank" rel="noopener">pedais CSL com Load Cell</a>, que mede pressão no freio em vez de deslocamento. Faz toda a diferença na frenagem — você aprende a dosar pela força do pé, não pela distância que o pedal percorre. Muito mais natural.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/fanatec-direct-drive-close-up.jpg" alt="Close-up do motor Fanatec CSL DD direct drive"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/fanatec-csl-pedals.jpg" alt="Pedais Fanatec CSL com Load Cell Kit"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/fanatec---shifter.jpg" alt="O shifter Fanatec — câmbio manual com knob cromado"  loading="lazy" /></p>
<p>Eu também quis experimentar o câmbio manual H-pattern com o <a href="https://fanatec.com/us/en/p/add-ons/crd-9040002-ww/clubsport-shifter-sq"target="_blank" rel="noopener">ClubSport Shifter SQ V1.5</a> da Fanatec e o freio de mão separado. É legal pra experimentar carros antigos com embreagem e câmbio H, mas na prática eu não me adaptei. O suporte SXT V2 já balançava bastante com o direct drive, e usar o shifter naquele setup instável era frustrante. E eu sei que tem gente que quer fazer &ldquo;ponta e calcanhar&rdquo; (heel-toe), mas no simulador eu prefiro ter o pé esquerdo no freio e o direito no acelerador e dosar os dois ao mesmo tempo. Funciona melhor pra mim. Agora que eu tenho o volante McLaren com os paddles analógicos de freio de mão e embreagem direto no volante, o câmbio H e o handbrake externo ficaram aposentados. Pra rally, o handbrake analógico no volante é muito mais natural.</p>
<p>Também comprei o PS5 com Gran Turismo 7 nessa época. Coloquei as <a href="https://dbrand.com/shop/ps5"target="_blank" rel="noopener">dbrand Darkplates</a> matte black pra trocar as placas brancas originais — fica muito mais bonito e discreto.</p>
<p>Mas o setup ainda era o suporte SXT V2 na frente do sofá VIP. A mesma gambiarra. O mesmo balanço. Eu não ia desistir do sofá de cinema, claro. A situação ficou insustentável.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/fanatec-with-support.jpg" alt="O Fanatec CSL DD no suporte SXT V2 — poderoso demais pro suporte aguentar"  loading="lazy" /></p>
<h2>O computador e o setup de hardware<span class="hx:absolute hx:-mt-20" id="o-computador-e-o-setup-de-hardware"></span>
    <a href="#o-computador-e-o-setup-de-hardware" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Uma nota sobre meu hardware de gaming. Eu comprei um <a href="https://www.minisforum.com/products/UX790-Pro.html"target="_blank" rel="noopener">Minisforum UX790 Pro</a> pra ser minha máquina dedicada de Steam. É um mini-PC com processador Intel Core Ultra 9 285H, que cabe na palma da mão. Junto comprei o <a href="https://www.minisforum.com/products/minisforum-deg1-egpu-dock"target="_blank" rel="noopener">Minisforum DEG1</a>, um dock de GPU externo que conecta via OCuLink (PCIe 4.0 x4, 64 GT/s). É um design aberto — basicamente uma placa com slot PCIe x16 e espaço pra fonte ATX ou SFX. Não tem limitação de tamanho de placa, então cabe uma RTX 4090 tranquilamente. A perda de performance comparado a um slot PCIe nativo é mínima. Coloquei a RTX 4090 nele. A 4090 veio do meu desktop — no começo de 2025 eu viajei pra Miami e aproveitei pra comprar uma RTX 5090 porque estava usando cada vez mais IA e LLMs locais. Dei a 3090 antiga pra minha namorada usar na edição de vídeo. A 4090 foi pro mini-PC.</p>
<p>Então meu setup de gaming hoje é: Minisforum UX790 Pro + eGPU com RTX 4090 pra Steam e jogos de PC, e PlayStation 5 com Darkplates matte black pra Gran Turismo 7 e exclusivos.</p>
<h2>O cockpit: Formula FX1<span class="hx:absolute hx:-mt-20" id="o-cockpit-formula-fx1"></span>
    <a href="#o-cockpit-formula-fx1" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pra completar o setup eu também precisava de um monitor decente. Eu já estava acostumado com minha TV OLED Samsung de 80&quot; na sala e não queria dar um downgrade na qualidade de imagem. Então investi no <a href="https://www.samsung.com/br/monitors/gaming/odyssey-oled-g8-g81sf-32-inch-240hz-oled-uhd-ls32fg810snxzd/"target="_blank" rel="noopener">Samsung Odyssey OLED G8 de 32&quot;</a>. É um monitor 4K (3840x2160) OLED com 240 Hz de refresh rate, 0.03 ms de tempo de resposta (GTG), HDR True Black 400, HDR10+, 99% de cobertura DCI-P3, contraste de 1.000.000:1, e FreeSync Premium Pro. Tem 2 entradas HDMI 2.1 e 1 DisplayPort 1.4.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/closed-delivery-box.jpg" alt="A caixa do Samsung Odyssey OLED G8 de 32&#34; quando chegou"  loading="lazy" /></p>
<p>Na prática: as cores explodem, preto é preto de verdade (é OLED, não tem backlight), e com a RTX 4090 eu rodo a maioria dos jogos em 4K a 120 fps tranquilo. Em títulos mais leves como o Super Woden: Rally Edge, chega fácil nos 240 Hz. A fluidez é absurda. Pra um cockpit onde você está a uns 60-70 cm da tela, 32&quot; OLED em 4K é o sweet spot. Maior que isso e você começaria a enxergar pixels. Menor e perde a imersão.</p>
<p>Em janeiro de 2026, depois de anos de gambiarra, eu finalmente encomendei um cockpit dedicado. Pesquisei bastante. Considerei o <a href="https://loja.cockpitextremeracing.com.br/products/cockpit-ax160-horizontal?variant=52008751431961"target="_blank" rel="noopener">Cockpit AX160</a>, que é de perfil de alumínio e muito modular, e o <a href="https://loja.cockpitextremeracing.com.br/products/cockpit-4-0-horizontal?variant=52004294852889"target="_blank" rel="noopener">Cockpit 4.0</a>, que é de aço tubular mais tradicional. Mas nenhum dos dois estava disponível no momento da compra. E aí eu encontrei o <a href="https://loja.cockpitextremeracing.com.br/products/cockpit-formula-fx1-preto-e-verde?variant=51700876509465"target="_blank" rel="noopener">Formula FX1 preto e verde</a> da Extreme Racing — cores Petronas, estilo F1.</p>
<p>O FX1 é muito diferente dos cockpits tradicionais. A estrutura inteira é de tubos de aço grossos, soldados. Quando eu digo que a coisa não balança, eu quero dizer que não balança nada. Zero wobble. É uma diferença brutal em relação ao suporte na frente do sofá. A posição de pilotagem é reclinada, tipo F1 — seus pés ficam na mesma altura ou mais altos que seu quadril. Parece que vai ser desconfortável, mas não é. Dá pra ficar horas ali sem reclamar. Vem com banco acolchoado e ajustável, suporte pra monitor com articulação, suporte pra pedais com inclinação ajustável, e suporte pra volante com altura regulável.</p>
<p>Tive que esperar cerca de 1 mês pela entrega. No meio tempo, como quem acompanha meu blog sabe, eu mergulhei numa maratona de 16 horas por dia testando os novos agentes de IA da Anthropic e OpenAI — veja as tags <a href="/tags/vibe-coding/">#vibecoding</a> e <a href="/tags/inteligencia-artificial/">#agents</a> pra ver tudo que eu fiz. Depois de uns 30 dias nessa maratona insana, minha lombar cedeu e eu comecei a desenvolver o que parece ser hérnia de disco. Tive que ir ao médico e tomar anti-inflamatórios pesados.</p>
<p>E exatamente nessa semana, o cockpit decidiu chegar.</p>
<h3>A montagem<span class="hx:absolute hx:-mt-20" id="a-montagem"></span>
    <a href="#a-montagem" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Eu estava com dor absurda, mas montei o cockpit assim mesmo. Levou o dia inteiro pra desembalar e montar as peças de aço pesadas com a lombar gritando, mas eu fiz.</p>
<p>O vídeo de montagem oficial que eu segui:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/WnocqqhmZas"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/first-pieces-mounted.jpg" alt="Primeiras peças montadas — a base e a estrutura do banco"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/mostly-mounted.jpg" alt="Estrutura quase completa — banco, suporte do volante, pedais"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/mostly-mounted-from-front.jpg" alt="Vista frontal da estrutura quase pronta"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/almost-mounted,-with-monitor.jpg" alt="Montagem quase completa com o suporte do monitor"  loading="lazy" /></p>
<h3>O volante McLaren GT3 V2<span class="hx:absolute hx:-mt-20" id="o-volante-mclaren-gt3-v2"></span>
    <a href="#o-volante-mclaren-gt3-v2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Depois de montar o cockpit, eu decidi que o volante padrão que vem com o kit CSL GT não era suficiente. Fiz o upgrade pro <a href="https://www.racingwheelbrasil.com.br/produtos/volante-fanatec-csl-elite-mclaren-gt3-v2-pc-xbox-ps4-ps5-ready/"target="_blank" rel="noopener">Fanatec CSL Elite McLaren GT3 V2</a> (~R$ 4.990). É uma réplica em escala real do volante do McLaren GT3, com fibra de carbono, display OLED, e compatível com PC, Xbox, PS4 e PS5.</p>
<p>O que eu mais gosto nele: tem as borboletas de câmbio normais atrás (shift up/down), mas também tem dois paddles analógicos adicionais que podem ser configurados em quatro modos diferentes. No modo B, que é o que eu uso, o paddle esquerdo funciona como handbrake analógico e o direito como embreagem analógica. Isso é perfeito pra rally — eu consigo puxar o freio de mão no meio da curva sem tirar a mão do volante. Tem também dois toggles de 2 posições, dois rotary de 12 posições, 7 botões padrão com caps intercambiáveis, e o FunkySwitch de 7 direções da Fanatec. É um controle completo de corrida.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/mclaren-wheel.jpg" alt="O volante McLaren GT3 V2 montado no cockpit — fibra de carbono e display OLED"  loading="lazy" /></p>
<h2>O setup final<span class="hx:absolute hx:-mt-20" id="o-setup-final"></span>
    <a href="#o-setup-final" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O cockpit ficou num cantinho do meu quarto, entre as estantes de mangá (dá pra ver Akira, Initial D, e uns 500 outros volumes atrás). Montei o mini-PC e o PS5 na estrutura lateral do cockpit, junto com a eGPU e a RTX 4090. Tudo fica permanentemente conectado. É isso que faz a diferença: eu não preciso mais montar nem desmontar nada. Sento, ligo, e estou dirigindo em 30 segundos.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/fully-mounted-from-side.jpg" alt="Vista lateral do cockpit completo — entre as estantes de mangá"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/all-consoles-from-front.jpg" alt="Os consoles montados na estrutura: PS5 com Darkplates, Minisforum UX790 Pro, eGPU com RTX 4090"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/close-up-of-the-consoles-from-front.jpg" alt="Close-up dos consoles e cabeamento"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/sitting-angle.jpg" alt="A perspectiva do piloto — é assim que eu vejo quando estou sentado"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/monitor-on-view-from-front.jpg" alt="PS5 mostrando a lista de jogos — Gran Turismo 7 no topo"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/another-fully-mounted-shot.jpg" alt="O cockpit completo visto de trás"  loading="lazy" /></p>
<div style="max-width: 100%; margin: 1em 0;">
  <video controls playsinline style="width: 100%; border-radius: 8px;">
    <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/from-front-gran-turismo-h264.mp4" type="video/mp4">
  </video>
  <em>Gran Turismo 7 rodando no cockpit final</em>
</div>
<h2>O sistema de áudio<span class="hx:absolute hx:-mt-20" id="o-sistema-de-áudio"></span>
    <a href="#o-sistema-de-%c3%a1udio" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pra completar o setup eu precisava de áudio dedicado. Eu não queria usar o áudio do monitor (péssimo) nem ficar sempre de headset. A solução foi montar um sistema de áudio separado com extração de áudio do HDMI.</p>
<p>A peça central é um <a href="https://www.amazon.com.br/dp/B00MNGIP2Y"target="_blank" rel="noopener">switcher HDMI 2.1 da OREI</a> com extração de áudio. Ele tem 2 entradas e 1 saída HDMI, suporta 4K a 120Hz (48 Gbps de bandwidth), e extrai o áudio via saída óptica TOSLINK e P2 3.5mm. Eu conecto a saída HDMI da RTX 4090 numa entrada e o PS5 na outra. O vídeo vai pro monitor. O áudio sai pela óptica.</p>
<p>O áudio óptico vai pra um <a href="https://www.mercadolivre.com.br/amplificador-de-potncia-aiyima-d03-bluetooth-50-150-watts-cor-preto/p/MLB46172770"target="_blank" rel="noopener">amplificador Aiyima D03</a>, um amp compacto 2.1 canais com 150W por canal, DAC integrado (chip PCM1808), e Bluetooth 5.0 com aptX HD. Ele tem entrada óptica, coaxial, USB, RCA e Bluetooth. Tem até saída dedicada pra subwoofer quando eu resolver adicionar um. Usa chip amplificador TAS5624 da Texas Instruments e tem controle de graves e agudos pelo controle remoto. Pra um setup de cockpit onde você está a 1 metro das caixas, 150W é mais que suficiente.</p>
<p>Na prática, eu deixo o amplificador em 50% e o volume do Windows em 50%, e isso já fica alto pra caramba. Ou seja: não é um sisteminha &ldquo;quebra-galho&rdquo;. Está equipado pra tocar realmente alto se eu quiser.</p>
<p>As caixas são <a href="https://edifier.com.br/caixa-de-som-passiva-p12-madeira-edifier.html"target="_blank" rel="noopener">Edifier P12</a>, passivas, com woofer de 4 polegadas e tweeter de 19mm. Resposta de frequência de 55Hz a 20kHz, impedância de 6 ohms, potência de 20W RMS cada. O gabinete de MDF com acabamento em madeira tem um porte-reflex traseiro que ajuda nos graves. Pra caixas passivas desse tamanho, elas entregam bem. O mid-range sai limpo e os agudos não distorcem mesmo no volume alto.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/audio-equipment.jpg" alt="Os equipamentos de áudio — caixa do Aiyima D03 e do Edifier P12"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/audio-speakers-next-to-other-stuff.jpg" alt="As Edifier P12 posicionadas nas estantes ao lado do cockpit, junto com a coleção de Akira e miniaturas de carros"  loading="lazy" /></p>
<p>A lógica do setup é: HDMI switcher faz o chaveamento entre PS5 e PC, extrai o áudio pra óptica, o amp converte e amplifica, e as caixas passivas entregam o som. Tudo sem precisar tocar no monitor ou trocar cabos. Aperto um botão no switcher e troco de console.</p>
<p>Quando eu quero jogar sem incomodar ninguém, conecto meu <a href="https://www.mercadolivre.com.br/fones-de-ouvido-meze-audio-109-pro-com-fio-de-madeira-com-en/p/MLB42456685"target="_blank" rel="noopener">Meze 109 Pro</a> direto na saída P2 do switcher HDMI. O Meze 109 Pro é um headphone aberto com drivers dinâmicos de 50mm, impedância de 40 ohms, sensibilidade de 112 dB SPL/1mW, e resposta de 5Hz a 30kHz. Os ear cups são de madeira de nogueira com acabamento artesanal. É um headphone audiófilo que funciona perfeitamente sem amplificador dedicado graças à impedância baixa. O som é quente, com graves cheios e mids ricos. Dá pra ouvir cada detalhe do ronco dos motores.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/meze-headset.jpg" alt="Meze 109 Pro — madeira de nogueira, som audiófilo"  loading="lazy" /></p>
<p>Ainda não decidi sobre subwoofer, mas vai ser meu próximo upgrade. Um sub dedicado vai adicionar aquele peso nos graves que faz você sentir o motor no peito.</p>
<h2>O veredito<span class="hx:absolute hx:-mt-20" id="o-veredito"></span>
    <a href="#o-veredito" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O sofa com suporte funciona. A mesa do PC com suporte funciona. Mas nenhum dos dois chega perto de um cockpit dedicado. A estrutura de aço do FX1 não mexe nem um milímetro, mesmo com o direct drive do Fanatec dando torque máximo. A posição F1 reclinada é confortável pra sessões de horas. Os pedais com load cell ficam firmes na base. O monitor fica exatamente na altura e distância certas. E o melhor de tudo: está sempre pronto. Eu não preciso montar, desmontar, passar cabo, nada. Sento e dirijo.</p>
<p>Pra quem está na dúvida se vale a pena investir num cockpit dedicado vs. ficar com suporte na mesa ou no sofá: vale. Se você já tem um volante direct drive, o cockpit é a peça que falta. Eu passei anos achando que &ldquo;tá bom assim&rdquo; com o suporte no sofá. Não tava. A diferença na dirigibilidade é outra coisa. E pro meu caso — introvertido, single-player only, simcade — não podia ter montado antes. Pra falar a verdade, eu acho que finalmente cheguei no meu setup de simulador perfeito pro meu gosto.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/monitor-on-view.jpg" alt="O monitor ligado com a vista do piloto"  loading="lazy" /></p>
<div style="max-width: 100%; margin: 1em 0;">
  <video controls playsinline style="width: 100%; border-radius: 8px;">
    <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/cockpit/video-testing-h264.mp4" type="video/mp4">
  </video>
  <em>Eu dirigindo no cockpit final</em>
</div>
<h2>Lista de compras: quanto custou tudo<span class="hx:absolute hx:-mt-20" id="lista-de-compras-quanto-custou-tudo"></span>
    <a href="#lista-de-compras-quanto-custou-tudo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui está a lista consolidada de tudo que compõe meu setup atual, com preços aproximados (alguns comprei em dólar, converti pra real na cotação da época):</p>
<table>
  <thead>
      <tr>
          <th>Item</th>
          <th style="text-align: right">Preço Estimado (R$)</th>
          <th>Link</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="https://loja.cockpitextremeracing.com.br/products/cockpit-formula-fx1-preto-e-verde?variant=51700876509465"target="_blank" rel="noopener">Cockpit Formula FX1 Preto e Verde</a></td>
          <td style="text-align: right">~6.290</td>
          <td>Extreme Racing</td>
      </tr>
      <tr>
          <td><a href="https://fanatec.com/us/en/p/sim-racing-bundles/crd-9020007-8nm-us/gran-turismo-dd-pro-8nm-qr2l-us"target="_blank" rel="noopener">Fanatec Gran Turismo DD Pro 8Nm (motor + volante + pedais + Boost Kit)</a></td>
          <td style="text-align: right">~9.590</td>
          <td>Fanatec / Racing Wheel Brasil</td>
      </tr>
      <tr>
          <td><a href="https://fanatec.com/us/en/p/pedals/csl_p_lc/csl_pedals_lc"target="_blank" rel="noopener">Fanatec CSL Pedals LC (com Load Cell)</a></td>
          <td style="text-align: right">~1.500</td>
          <td>Fanatec</td>
      </tr>
      <tr>
          <td><a href="https://www.racingwheelbrasil.com.br/produtos/volante-fanatec-csl-elite-mclaren-gt3-v2-pc-xbox-ps4-ps5-ready/"target="_blank" rel="noopener">Fanatec CSL Elite McLaren GT3 V2</a></td>
          <td style="text-align: right">~4.990</td>
          <td>Racing Wheel Brasil</td>
      </tr>
      <tr>
          <td><a href="https://fanatec.com/us/en/p/add-ons/crd-9040002-ww/clubsport-shifter-sq"target="_blank" rel="noopener">Fanatec ClubSport Shifter SQ V1.5</a></td>
          <td style="text-align: right">~2.500</td>
          <td>Fanatec</td>
      </tr>
      <tr>
          <td><a href="https://www.minisforum.com/products/UX790-Pro.html"target="_blank" rel="noopener">Minisforum UX790 Pro</a></td>
          <td style="text-align: right">~5.000</td>
          <td>Minisforum</td>
      </tr>
      <tr>
          <td><a href="https://www.minisforum.com/products/minisforum-deg1-egpu-dock"target="_blank" rel="noopener">Minisforum DEG1 eGPU Dock</a> + RTX 4090</td>
          <td style="text-align: right">~12.000</td>
          <td>Minisforum / comprado separado</td>
      </tr>
      <tr>
          <td>PlayStation 5 + <a href="https://dbrand.com/shop/limited-edition/ps5"target="_blank" rel="noopener">dbrand Darkplates</a></td>
          <td style="text-align: right">~4.500</td>
          <td>Sony / dbrand</td>
      </tr>
      <tr>
          <td><a href="https://www.samsung.com/br/monitors/gaming/odyssey-oled-g8-g81sf-32-inch-240hz-oled-uhd-ls32fg810snxzd/"target="_blank" rel="noopener">Samsung Odyssey OLED G8 32&quot;</a></td>
          <td style="text-align: right">~2.500</td>
          <td>Samsung</td>
      </tr>
      <tr>
          <td><a href="https://www.amazon.com.br/dp/B00MNGIP2Y"target="_blank" rel="noopener">OREI BK-21A HDMI 2.1 Switcher 2x1 com extração de áudio</a></td>
          <td style="text-align: right">~450</td>
          <td>Amazon</td>
      </tr>
      <tr>
          <td><a href="https://www.mercadolivre.com.br/amplificador-de-potncia-aiyima-d03-bluetooth-50-150-watts-cor-preto/p/MLB46172770"target="_blank" rel="noopener">Amplificador Aiyima D03</a></td>
          <td style="text-align: right">~900</td>
          <td>Mercado Livre</td>
      </tr>
      <tr>
          <td><a href="https://edifier.com.br/caixa-de-som-passiva-p12-madeira-edifier.html"target="_blank" rel="noopener">Edifier P12 (par)</a></td>
          <td style="text-align: right">~799</td>
          <td>Edifier</td>
      </tr>
      <tr>
          <td><a href="https://www.mercadolivre.com.br/fones-de-ouvido-meze-audio-109-pro-com-fio-de-madeira-com-en/p/MLB42456685"target="_blank" rel="noopener">Meze 109 Pro</a></td>
          <td style="text-align: right">~5.390</td>
          <td>Mercado Livre / Heinrich Audio</td>
      </tr>
      <tr>
          <td>Cabos (HDMI 2.1, óptico, P2, energia)</td>
          <td style="text-align: right">~300</td>
          <td>Diversos</td>
      </tr>
      <tr>
          <td><strong>TOTAL ESTIMADO</strong></td>
          <td style="text-align: right"><strong>~56.709</strong></td>
          <td></td>
      </tr>
  </tbody>
</table>
<p>Sim, quase R$ 57 mil é bastante dinheiro. Eu trabalhei feito um condenado por décadas. Agora que consegui me aposentar honestamente, minha família está bem amparada, não tenho dívidas, e eu posso finalmente me dar algo que eu sempre quis quando era moleque mas não tinha como bancar. Quando eu sentava naqueles cabinets de OutRun e Daytona USA no fliperama, eu sonhava em ter algo assim em casa. Levou 30 e poucos anos, mas cheguei lá.</p>
<p>E se você somar os anos de gambiarras, suportes que não funcionavam, cabos HDMI de 15 metros, impressões 3D, placas de aço usinadas, e a frustração de montar e desmontar tudo — o cockpit dedicado economiza sanidade. Diferente de um PC que deprecia rápido, um cockpit de aço dura décadas.</p>
]]></content:encoded><category>games</category><category>hardware</category><category>off-topic</category></item><item><title>Tudo que Precisa Saber Sobre Retro-Gaming</title><link>https://akitaonrails.github.io/2025/09/14/tudo-que-precisa-saber-sobre-retro-gaming/</link><guid isPermaLink="true">https://akitaonrails.github.io/2025/09/14/tudo-que-precisa-saber-sobre-retro-gaming/</guid><pubDate>Sun, 14 Sep 2025 16:00:00 -0300</pubDate><description>&lt;p&gt;Tá, já que escrevi quase um e-book sobre &lt;a href="https://akitaonrails.github.io/2025/14/coisas-que-iniciantes-ignoram-sobre-pcs/"&gt;tudo que você precisa saber sobre componentes de PCs&lt;/a&gt; resolvi que chegou a hora de outro artigo que estou faz anos segurando: &lt;strong&gt;tudo que você precisa saber sobre retro-gaming e handhelds&lt;/strong&gt;. É outro artigo que vai envelhecer mal porque saem coisas novas o tempo todo. Tudo que está aqui vale pra 2025. Então vamos lá.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914123715_20250914_122919.jpg" alt="Coleção" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Como podem ver, eu tenho praticamente todos os handhelds possíveis e imagináveis. Então acho que tenho alguma propriedade pra falar sobre as vantagens e desvantagens da maioria dos mais populares. E eu tinha mais, mas fui doando pra amigos com o tempo. Esses são os meus favoritos.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Tá, já que escrevi quase um e-book sobre <a href="/2025/14/coisas-que-iniciantes-ignoram-sobre-pcs/">tudo que você precisa saber sobre componentes de PCs</a> resolvi que chegou a hora de outro artigo que estou faz anos segurando: <strong>tudo que você precisa saber sobre retro-gaming e handhelds</strong>. É outro artigo que vai envelhecer mal porque saem coisas novas o tempo todo. Tudo que está aqui vale pra 2025. Então vamos lá.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914123715_20250914_122919.jpg" alt="Coleção"  loading="lazy" /></p>
<p>Como podem ver, eu tenho praticamente todos os handhelds possíveis e imagináveis. Então acho que tenho alguma propriedade pra falar sobre as vantagens e desvantagens da maioria dos mais populares. E eu tinha mais, mas fui doando pra amigos com o tempo. Esses são os meus favoritos.</p>
<p>Vou falar dos hardwares primeiro e na segunda parte do artigo vou falar um pouco dos softwares também. Use os links de seção na direita (na versão desktop), pra navegar onde quer ler primeiro.</p>
<p>Já aviso que vou ser preguiçoso e nas tabelas de especificações, sim, é ChatGPT pra ajudar. Senão é muito detalhe kkkk 🤣</p>
<h3>Ambernic RG400M<span class="hx:absolute hx:-mt-20" id="ambernic-rg400m"></span>
    <a href="#ambernic-rg400m" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914124055_20250914_123944.jpg" alt="RG400M"  loading="lazy" /></p>
<p><strong>Especificações</strong></p>
<table>
  <thead>
      <tr>
          <th>Component</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Display</td>
          <td>4.7-inch LTPS In-Cell, full lamination, multi-touch</td>
      </tr>
      <tr>
          <td>Resolution</td>
          <td>1280 × 960</td>
      </tr>
      <tr>
          <td>Refresh Rate</td>
          <td>120 Hz <a href="https://retrohandhelds.gg/anbernic-rg477m-launched-everything-you-need-to-know/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>CPU</td>
          <td>MediaTek Dimensity 8300 (4nm process) — 1×A715 @ 3.35GHz + 3×A715 @ 3.20GHz + 4×A510 @ 2.20GHz <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>Mali-G615 MC6 <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>RAM options</td>
          <td>8GB LPDDR5 or 12GB LPDDR5 <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Storage options</td>
          <td>128GB or 256GB UFS internal + micro-SD (TF) expandable to 2TB <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>5,300 mAh, ~7 hours use <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Charging</td>
          <td>5V/9V — 27W <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Connectivity</td>
          <td>Wi-Fi 6E, Bluetooth 5.3 <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Other features</td>
          <td>3.5mm headphone jack; dual speakers; large-angle 3D Hall joystick with RGB lighting; six-axis gyroscope; active cooling (fan + heat pipe); USB-C display out; vibration motor; FOTA, etc. <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Shell / Build</td>
          <td>Aluminum alloy (CNC), metal body; two colours: Silver Blade &amp; Chocolate Bronze <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Dimensions / Weight</td>
          <td>176 × 89.4 × 16 mm, 354 g <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
  </tbody>
</table>
<p>Este é um dos mais antigos que eu ainda tenho. <strong>Ambernic</strong> é a marca que eu mais gosto e um dos mais confiáveis. De vez em quando lançam modelos esquisitos, mas no geral são bem consistentes na qualidade.</p>
<p>Esse modelo 400M acho que não existe mais, mas o sucessor dele é <strong>RG477M</strong> e recomendo assistir o review do canal Retro Game Corps:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/9eQDFtmzuhM"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Durante todo o artigo vou sempre linkar pros reviews desse canal porque considero que o Russ faz os reviews mais completos. Ele realmente vai fundo em cada detalhe, tamanho dos botões, peso, compatibilidade, tudo. É o único canal que você precisa assistir.</p>
<p>Pra 2025 o 400M/477M é antiquado, inclusive é caro, a <a href="https://anbernic.com/products/rg477m"target="_blank" rel="noopener">USD 280</a>, sem considerar frete e taxa bostil (que vai dobrar esse preço). Isso porque ele tem corpo de alumínio, o que dá uma sensação bem mais <strong>premium</strong> do que os baratos de plástico. Porém, eu acho que a maior desvantagem dele é que a resolução da tela é só <strong>1280x960</strong>. Vou falar de resolução em outra seção, mas acho isso <strong>baixa resolução</strong>.</p>
<p>Quer dizer, pra jogar coisas como Gameboy, funciona super bem, mas se for pra Mega Drive, Super Nintendo, já começa a ficar apertado. Acima disso já sinto pixelizado mesmo numa tela pequena de 4.0&quot;.</p>
<p>O 477M tem tela maior, inclusive é isso que os nomes querem dizer: 400M tem tela de 4.0&quot; e 477M tem tela de 4.7&quot;. O 400M tem SoC (System on a Chip) Unisoc T618 2.0Ghz e o 477M tem o MediaTek Dimensity 8300 3.35Ghz. Triplo de RAM (4G LDDDR4X vs 12GB LPDDR5), bateria um pouco maior (4.500 mAh vs 5.300 mAh).</p>
<p>Parece potente mas é porque esse handheld roda Android. Eu particularmente não curto handhelds Android. Depois falo porque.</p>
<p>No geral é um excelente handheld, pequeno, premium, roda bem até PS1 e dá pra arriscar um PSP, mas a tela não foi feita pra isso (PSP é widescreen, este é 4:3). Só que eu <strong>não recomendo</strong> ele é muito caro e a performance não condiz com o preço, só é caro porque é de alumínio. Pelo mesmo preço se compra outros muito melhores, como vou mostrar a seguir.</p>
<h3>TRIUMUI BRICK - MIYOO MINI<span class="hx:absolute hx:-mt-20" id="triumui-brick---miyoo-mini"></span>
    <a href="#triumui-brick---miyoo-mini" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914125818_20250914_125744.jpg" alt="TriumUI - Miyoo"  loading="lazy" /></p>
<p>Os próximos da lista são os verticais &ldquo;miniatura&rdquo;.</p>
<p>O mais clássico de todos é sem dúvida o <a href="https://officialmiyoomini.com/pt_pt/"target="_blank" rel="noopener"><strong>Miyoo Mini Plus</strong></a>:</p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Screen</td>
          <td>2.8-inch IPS</td>
      </tr>
      <tr>
          <td>Resolution</td>
          <td>~ 750 × 560 <a href="https://www.keepretro.com/products/onion-os-miyoo-mini-v4?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>CPU</td>
          <td>ARM Cortex-A7, dual-core, 1.2 GHz <a href="https://www.keepretro.com/products/onion-os-miyoo-mini-v4?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+2Miyoo Mini+2</a></td>
      </tr>
      <tr>
          <td>RAM</td>
          <td>128 MB <a href="https://officialmiyoomini.com/product/miyoo-mini-v4-retro-grey/?utm_source=chatgpt.com"target="_blank" rel="noopener">Miyoo Mini+1</a></td>
      </tr>
      <tr>
          <td>Storage Expansion</td>
          <td>microSD (TF), shipped with 32/64/128 GB cards; supports up to 128 GB <a href="https://www.keepretro.com/products/onion-os-miyoo-mini-v4?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+2Miyoo Mini+2</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>2,000 mAh Li-polymer <a href="https://officialmiyoomini.com/product/miyoo-mini-v4-retro-grey/?utm_source=chatgpt.com"target="_blank" rel="noopener">Miyoo Mini+1</a></td>
      </tr>
      <tr>
          <td>Battery Life</td>
          <td>~ 5-6 hours typical <a href="https://www.litnxt.com/products/miyoo-mini-v4-portable-handheld-game-console?utm_source=chatgpt.com"target="_blank" rel="noopener">litnxt+1</a></td>
      </tr>
      <tr>
          <td>Size</td>
          <td>93.5 × 65 × 18 mm <a href="https://officialmiyoomini.com/product/miyoo-mini-v4-retro-grey/?utm_source=chatgpt.com"target="_blank" rel="noopener">Miyoo Mini+1</a></td>
      </tr>
      <tr>
          <td>Weight</td>
          <td>~ 104-107 g <a href="https://retrohandhelds.gg/rg28xx-miyoo-a30-vs-mini-v4-comparison/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Miyoo Mini+2</a></td>
      </tr>
      <tr>
          <td>OS</td>
          <td>Linux (Stock / OnionOS available) <a href="https://www.keepretro.com/products/onion-os-miyoo-mini-v4?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Sensor / Extras</td>
          <td>Vibration motor; full-lamination screen; flat shoulders; R2/L2 micro buttons; OCA laminated screen in newer batches. <a href="https://www.litnxt.com/products/miyoo-mini-v4-portable-handheld-game-console?utm_source=chatgpt.com"target="_blank" rel="noopener">litnxt+2keepretro+2</a></td>
      </tr>
  </tbody>
</table>
<p>Falei que 4.0&quot; e 1280x960 acho pequeno? O Miyoo Mini Plus tem tela de só 2.8&quot; e resolução de 750x560. O SoC é muito bom com ARM Cortex-A7, 1.2Ghz que consegue rodar bem até PS1. Nessa tela pequena é mais indicado pra coisas como Gameboy, GameGear e outros portáteis antigos. Dá pra jogar NES, MasterSystem, MegaDrive. Mas PS1 já começa a ficar muito pequeno pra conseguir ler.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914130734_20250914_130603.jpg" alt="miyoo screen"  loading="lazy" /></p>
<p>É difícil de descrever quão pequeno é essa tela. Compare acima a tela com meu <strong>dedão</strong> pra ter uma noção. É extremamente pequeno. Não recomendo pra nada muito maior que jogos de Gameboy mesmo. Se você for jovem, com boa vista, vai conseguir jogar melhor. E vai ficar com a vista ruim como a minha mais rápido também kkkk 🤣 fica pelo seu risco.</p>
<p>Eu uso óculos de muito grau, então essa tela é muito pequena pra mim. Mas a construção da Miyoo é muito boa. Ela tem aquela sensação de Gameboy clássico mesmo, só que em miniatura. O fator nostálgico é muito forte.</p>
<p>O melhor OS pra ela é o <a href="https://onionui.github.io/"target="_blank" rel="noopener"><strong>Onion OS</strong></a>, que torna o Miyoo ainda muito melhor. Uma coisa comum é que todo handheld vamos acabar substituindo o OS que vem por um open source melhor. É muito satisfatório a UI pra salvar estado do game, depois recarregar de onde parou.</p>
<p><img src="https://user-images.githubusercontent.com/44569252/189434217-72ef0daf-c630-4ec9-b96a-30fd76cb709f.png" alt="OnionOS"  loading="lazy" /></p>
<p>De longe uma das melhores UIs pra handhelds. Todo OS deveria copiar o OnionOS. De novo, o review do Russ sobre ele é bem detalhado:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/6CkJNKupU9A"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Depois do Miyoo Mini Plus, que considero &ldquo;miniatura com tamanho suficiente&rdquo; é o <a href="https://trimui.net/collections/trimui-brick"target="_blank" rel="noopener"><strong>TrimUI Brick</strong></a>. Ele é parecido em formato e funcionalidades com o <a href="https://anbernic.com/en-br/products/rg35xx-plus"target="_blank" rel="noopener"><strong>Ambernic RG35xx Plus</strong></a> então qualquer um dos dois vai atender quem quer esse tamanho.</p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>Allwinner A133P, 1.8 GHz <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2keepretro+2</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>PowerVR GE8300 @ 660 MHz <a href="https://trimui.net/products/trimui-brick-retro-handheld-game-64g?srsltid=AfmBOorFLIscOPS80tgdzShZ1bVwngtTX1q8VU01fVL5UH12dqlAoUaP&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Trimui Store+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>RAM</td>
          <td>1 GB LPDDR3/LPDDR4x (sources vary) <a href="https://mechdiy.com/products/trimui-brick-retro-handheld-game-console?srsltid=AfmBOooc_fIOP2p5G2jnS2jspN4lbtt6qXdi6PEOijUZu6Kh7gB4Ue-J&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Mechdiy+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Internal Storage</td>
          <td>8 GB eMMC <a href="https://trimui.net/products/trimui-brick-retro-handheld-game-64g?srsltid=AfmBOorFLIscOPS80tgdzShZ1bVwngtTX1q8VU01fVL5UH12dqlAoUaP&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Trimui Store+1</a></td>
      </tr>
      <tr>
          <td>External Storage</td>
          <td>TF card support up to ~1 TB <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+1</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>3.2-inch IPS, fully laminated, 1024×768 (4:3) <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2keepretro+2</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>3,000 mAh Li-polymer; ~5-6 hours typical use <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2keepretro+2</a></td>
      </tr>
      <tr>
          <td>Wireless / BT</td>
          <td>Wi-Fi 802.11 b/g/n; Bluetooth 2.1 + EDR / 4.2 <a href="https://trimui.net/products/trimui-brick-retro-handheld-game-64g?srsltid=AfmBOorFLIscOPS80tgdzShZ1bVwngtTX1q8VU01fVL5UH12dqlAoUaP&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Trimui Store+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Audio</td>
          <td>Stereo speakers, 3.5mm jack, mono mic <a href="https://www.keepretro.com/products/trimui-brick-handheld?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+1</a></td>
      </tr>
      <tr>
          <td>Other Features</td>
          <td>RGB lighting (top bar, shoulder buttons etc.), vibration, FN keys, USB-C ports (charging, host, OTG) <a href="https://trimui.net/products/trimui-brick-retro-handheld-game-64g?srsltid=AfmBOorFLIscOPS80tgdzShZ1bVwngtTX1q8VU01fVL5UH12dqlAoUaP&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Trimui Store+2keepretro+2</a></td>
      </tr>
      <tr>
          <td>Size / Weight</td>
          <td>~73.2 × 109.9 × 19.9 mm; ~159 g <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+1</a></td>
      </tr>
  </tbody>
</table>
<p>A tela do TrimUI é consideravelmente melhor em qualidade, cores saturadas, mais nítido, mais brilhante. É uma das melhores telas nesse formato que existem. Não tem como errar. Comparado com o Miyoo Mini, veja a diferença de qualidade de tela e, principalmente o tamanho!</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914131820_20250914_131501.jpg" alt="TrimUI vs Miyoo"  loading="lazy" /></p>
<p>E veja como a área útil não é muito menor que a tela de um Gameboy Advance SP de verdade, por isso é bem jogável.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914131658_20250914_131609.jpg" alt="TriumUI GB Advance"  loading="lazy" /></p>
<p>Pra melhorar, existem outros OS que dá pra instalar no TrimUI, como o lendário <a href="https://knulli.org/pt-BR/"target="_blank" rel="noopener"><strong>Knulli</strong></a>, mas você pode optar por pedir um microSD card já configurado e com vários jogos bons (não aquela lista genérica gigante de jogos repetidos que vem nos outros). Ele vem com o <a href="https://surwish.com/"target="_blank" rel="noopener"><strong>SurwishOS</strong></a>, que não é um OnionOS mas não está longe.</p>
<p>Ou seja, &ldquo;out-of-the-box&rdquo;, sem precisar configurar nada, o TrimUI Brick é um dos mais simples. Só ligar e já jogar, sem precisar mexer em OS ou fazer qualquer tuning. Plug and play. É fácil, um dos melhores que posso recomendar.</p>
<p>Novamente, roda bem até PS1, arrisca um PSP mas PSP é muito pesado mesmo. Não é o indicado. O ideal é até Gameboy Advance. Assista o review do Russ:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/F1fHemFCi3I"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Numa classe um pouco superior, mais parecida com Ambernic RG35XX vertical, tem os <a href="https://www.goretroid.com/collections/retro-game-system/products/retroid-pocket-classic"target="_blank" rel="noopener"><strong>Retroid Pocket Classic</strong></a>. Eu nunca tive, mas ouço falar muito bem também. Em particular a versão com 6 botões igual controle de luta do Mega Drive/Sega Saturn:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914155554_Retroid-Pocket-Classic-08.webp" alt="Retroid Classic"  loading="lazy" /></p>
<p>Também é uma boa recomendação e tem o r<a href="https://www.youtube.com/watch?v=HQOBdhnnQkM"target="_blank" rel="noopener">eview do Russ</a>.</p>
<h3>Ambernic RG35XX SP<span class="hx:absolute hx:-mt-20" id="ambernic-rg35xx-sp"></span>
    <a href="#ambernic-rg35xx-sp" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Se eu tivesse que escolher só um, ficaria bem dividido com o TrimUI Brick, mas acho que acabaria sempre voltando pra este: <a href="https://br.anbernic.com/products/rg35xxsp?variant=44326801539225"target="_blank" rel="noopener"><strong>Ambernic RG35XX SP</strong></a></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914132910_20250914_132230.jpg" alt="RG35XX SP fechado"  loading="lazy" /></p>
<p>Como expliquei antes, RG400M significa tela de 4&quot;, então RG35XX significa tela de 3.5&quot;. É um pouco maior que os 3.2&quot; do TrimUI Brick, um pouco menor que o RG477M. Na minha opinião acho que este é o &ldquo;sweet-spot&rdquo; entre portabilidade e visibilidade.</p>
<p>O &ldquo;SP&rdquo; significa que ele copiou o formato do lendário <strong>Gameboy Advance SP</strong>&quot;, a segunda revisão da Nintendo que introduziu o formato &ldquo;<strong>clamshell</strong>&rdquo;, que se dobra ao meio. A grande vantagem é que esse formato protege a tela quando fechada e não precisamos de uma bolsa pra quando queremos jogar na mochila, preocupados em riscar a tela.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914133341_20250914_132251.jpg" alt="RG35XX aberto"  loading="lazy" /></p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>Allwinner H700, quad-core ARM Cortex-A53 @ 1.5 GHz <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2GamesRadar++2</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>Dual-core Mali-G31 MP2 <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>RAM</td>
          <td>1 GB LPDDR4 <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>Internal Storage</td>
          <td>64 GB via TF/MicroSD (some variants lower) <a href="https://anbernic.com/products/rg35xxsp?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+2Mechdiy+2</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>3.5-inch IPS, OCA fully bonded, 640×480 (4:3) <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2GamesRadar++2</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>3,300 mAh Li-polymer, ~8 hours use <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>Charging</td>
          <td>5 V / 1.5 A, USB-C, supports USB-C to C charger <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>Connectivity</td>
          <td>WiFi 802.11 a/b/g/n/ac (2.4/5 GHz), Bluetooth 4.2 (controllers only) <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>Outputs &amp; Extras</td>
          <td>Mini-HDMI output; 3.5mm headphone jack; vibration motor; dual TF card slots; magnetic hinge for sleep/wake; multiple buttons including extra shoulder buttons etc. <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>Dimensions / Weight</td>
          <td>89 × 85 × 27 mm; ~192 g <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>OS</td>
          <td>Linux 64-bit <a href="https://anbernic.com/products/rg35xxsp?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
  </tbody>
</table>
<p>Em termos de specs, todos os que falei até agora tem performance parecida. Os RG477M são mais poderosos porque rodam Android (que é bem mais pesado), os demais rodam Linux então é bem mais leve.</p>
<p>Novamente, depende muito de quem é você. Por exemplo, eu tenho mãos pequenas, e mesmo pra mim um Miyoo Mini e até mesmo o TrimUI Brick eu sinto desconfortável pra jogar por muito tempo. Tenho que ficar segurando o console só com os dedos. Já o RG35XX SP se apoia na palma das minhas mãos, então eu sinto muito mais confortável e ergonômico pra jogar.</p>
<p>Por causa disso também eu não recomendo a nova versão RG34XX SP:</p>
<p><img src="https://br.anbernic.com/cdn/shop/files/20250514141311.jpg?v=1747203223&amp;width=1150" alt="RG34XX SP"  loading="lazy" /></p>
<p>Também não recomendo o <strong>Miyoo Flip v2</strong>:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914133648_Miyoo-Flip-Hero-1080x675.webp" alt="Miyoo Flip"  loading="lazy" /></p>
<p>O diferencial deles são os dois controles analógicos no final, que seria bom pra jogar coisas como Nintendo 64, os jogos mais novos de PS1, PSP, Dreamcast. Mas tem um porém: nenhum deles tem potência suficiente pra jogar acima de PS1. Sim, dá pra jogar mais ou menos bem Nintendo 64 e Dreamcast, mas não roda tudo.</p>
<p>Daí o que eu elogiei que dá pra apoiar na palma da mão se perde com os analógicos, porque pra usar os dedões nele, precisa segurar o handheld muito pra cima pra alcançar. Daí tem outro problema: os botões de ombro, que ficam atrás, os L1 e R1, ficam longe de apertar com os indicadores. Pra jogar FPS (jogos de tiro em primeira pessoa), é horrível. Então um Golden Eye 007 do Nintendo 64 fica ruim de jogar, mesmo com os analógicos.</p>
<p>Além disso note o nome: RG34XX, significa que a tela cai de 3.5&quot; pra 3.4&quot;. Falei antes que eu acho 3.5&quot; ideal e nessa nova versão é um downgrade. O erro é tentar achar que dá pra ter um único handheld que vai ser bom pra tudo. Não tem isso.</p>
<p>Outro canal que eu gosto muito é o <strong>Wulff Den</strong> e ele faz essa consideração nesse review:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/mCVOetPvhXQ"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Minha recomendação sempre é o RG35XX SP. Não precisa de botões analógicos e vai rodar tudo até PS1 sem problemas. Mais que isso, você quer um handheld MAIOR e mais potente.</p>
<p>Na categoria &ldquo;clamshells&rdquo; um que vale a pena olhar é o <a href="https://www.goretroid.com/collections/retro-game-system/products/retroid-pocket-flip-2"target="_blank" rel="noopener"><strong>Retroid Pocket Flip 2</strong></a>, que é maior, mais potente e mais caro. Mas ouço falar bem também:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914155800_D_NQ_NP_798192-MLB86423937046_062025-O.webp" alt="Retroid Flip 2"  loading="lazy" /></p>
<p>Novamente, assista o <a href="https://www.youtube.com/watch?v=6LIZWnD-62Q"target="_blank" rel="noopener">review do Russ</a></p>
<h3>Ayn Odin 2<span class="hx:absolute hx:-mt-20" id="ayn-odin-2"></span>
    <a href="#ayn-odin-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Vamos falar dos mais potentes. Pra mim, o melhor de todos, que roda basicamente tudo até Nintendo Switch, é o <a href="https://www.ayntec.com/products/odin-2"target="_blank" rel="noopener"><strong>Odin 2</strong></a> - e está pra sair o <a href="https://www.indiegogo.com/projects/odin-3-the-ultimate-6-120hz-oled-gaming-handheld#/"target="_blank" rel="noopener">Odin 3</a>, que vai ser melhor.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914134536_20250914_134446.jpg" alt="Odyn 2"  loading="lazy" /></p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Details</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>Qualcomm Snapdragon 8 Gen 2 <a href="https://www.ayntec.com/products/odin-2?utm_source=chatgpt.com"target="_blank" rel="noopener">AYN+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>Adreno 740 <a href="https://www.ayntec.com/products/odin-2?utm_source=chatgpt.com"target="_blank" rel="noopener">AYN+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>RAM options</td>
          <td>8 GB / 12 GB / 16 GB LPDDR5X <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>Storage options</td>
          <td>128 GB / 256 GB / 512 GB UFS <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>6-inch IPS LCD, 1920×1080, 60 Hz <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>8,000 mAh Li-polymer <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2AYN+2</a></td>
      </tr>
      <tr>
          <td>Charging / Ports</td>
          <td>USB-C with video output; HDMI + Micro HDMI in some variants <a href="https://www.amazon.com/Android-handheld-performance-Snapdragon-Octa-core-storage/dp/B0CP45TJF2?utm_source=chatgpt.com"target="_blank" rel="noopener">Amazon+1</a></td>
      </tr>
      <tr>
          <td>Wireless / Bluetooth</td>
          <td>Wi-Fi 7; Bluetooth 5.3 <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2AYN+2</a></td>
      </tr>
      <tr>
          <td>Weight</td>
          <td>~ 420 g <a href="https://www.amazon.com/Android-handheld-performance-Snapdragon-Octa-core-storage/dp/B0CP45TJF2?utm_source=chatgpt.com"target="_blank" rel="noopener">Amazon+2AYN+2</a></td>
      </tr>
      <tr>
          <td>Operating System</td>
          <td>Android 13 <a href="https://www.ayntec.com/products/odin-2?utm_source=chatgpt.com"target="_blank" rel="noopener">AYN+1</a></td>
      </tr>
      <tr>
          <td>Variants</td>
          <td>Base / Pro / Max with different RAM/storage combos</td>
      </tr>
  </tbody>
</table>
<p>O preço não é muito maior que o RG477M, mas ele é infinitamente melhor. Na faixa de <strong>USD 300</strong> (sem frete, sem impostos), é o melhor custo-benefício.</p>
<p>Veja as especificações, é um Qualcomm Snapdragon 8 Gen 2. É o mesmo chip que se tem em smartphones Android midrange pra high-end. Com GPU Adreno 740 e de 8GB até 16 GB LPDDR5X. Bateria de 8.000 mAh (maioria dos smartphones nessa categoria tem bateria de 5.000 mAh ou menos).</p>
<p>O principal: é uma tela IPS 6&quot; de 1080p de resolução (Full-HD). Nesse tamanho, até eu que sou cegueta, consigo enxergar qualquer jogo sem problemas. Um Nintendo Switch original tem tela de 6.2&quot;, então é levemente menor. É basicamente a potência de um Switch 2, na realidade.</p>
<p>O review do Wulff Den diz tudo:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/KHwHpiAMog4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Na prática, veja na foto os controles: se quiser ter sticks analógicos, eles precisam estar no formato de Xbox ou Switch, na horizontal, esse é o formato mais ergonômico pra jogar por bastante tempo. Por isso falei que os Miyoo Flip ou RG34XX SP não vale a pena. No Odin 2 sim, dá pra jogar Halo, Golden Eye, Doom, etc sem problemas. E como é um Android também dá pra instalar Call of Duty da Play Store sem problemas.</p>
<p>Agora, minha reclamação pessoal: Android é BEM mais chato pra configurar emuladores do que Linux. De longe mesmo. Precisa de MUITO tempo, MUITA paciência e MUITA tentativa e erro até deixar do jeito perfeito. É tanta coisa que recomendo assistir o guia do Russ sobre isso:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/I4mqgcDYZFo"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Sério, assista o video, leia o <a href="https://retrogamecorps.com/2022/03/13/android-emulation-starter-guide/"target="_blank" rel="noopener">blog post</a> do site dele pra mais detalhes. Você não vai acertar de primeira.</p>
<p>Pelo menos, uma vez configurado, vai rodar tudo liso. PSP com 3x resolução, Dreamcast com 3x resolução, PS2 com 3x resolução, GameCube com 2x resolução, até Switch Full-HD Docker mode. É meu modelo preferido pra jogar PSP mesmo: Ridge Racer 2 fica perfeito.</p>
<p>Nessa categoria de Android horizontal, outra boa recomendação é o <a href="https://www.goretroid.com/collections/retro-game-system/products/retroid-pocket-5-handheld"target="_blank" rel="noopener"><strong>Retroid Pocket 5</strong></a>, na mesma faixa de preço e também ouço falar bem. Em particular todo mundo fala muito bem da qualidade da tela.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914160025_kiboTEK_retroid_pocket_5_005-1024x1024.webp" alt="Retroid Pocket 5"  loading="lazy" /></p>
<p>Novamente, assista o <a href="https://www.youtube.com/watch?v=ZFTrwWQOe5Y"target="_blank" rel="noopener">review do Russ</a>.</p>
<h3>Ayaneo Pocket DMG<span class="hx:absolute hx:-mt-20" id="ayaneo-pocket-dmg"></span>
    <a href="#ayaneo-pocket-dmg" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Se tiver dinheiro pra jogar fora mesmo, também recomendo o <a href="https://ayaneo.com/product/AYANEO-Pocket-DMG"target="_blank" rel="noopener"><strong>Ayaneo Pocket DMG</strong></a>. Esse monstro começa na bagatela de <strong>USD 420</strong> (sem impostos, sem frete, na config básica). Se escolher tudo, sobe até <strong>USD 690</strong>. Mais caro que um Playstation 5!!! Realmente não dá pra recomendar, é o pior custo-benefício de todos.</p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>Snapdragon G3x Gen 2 <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Time Extension+2</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>Adreno A32 <a href="https://www.timeextension.com/reviews/ayaneo-pocket-dmg-this-pricey-emulation-monster-thinks-its-a-game-boy?utm_source=chatgpt.com"target="_blank" rel="noopener">Time Extension+2Retro Dodo+2</a></td>
      </tr>
      <tr>
          <td>RAM (options)</td>
          <td>8 GB / 12 GB / 16 GB LPDDR5X <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2overkill Media+2</a></td>
      </tr>
      <tr>
          <td>Storage (internal)</td>
          <td>128 GB / 256 GB / 512 GB / 1 TB <a href="https://retrododo.com/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Dodo+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>3.92-inch OLED, 1240×1080 (≈31:27 aspect) <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Time Extension+2</a></td>
      </tr>
      <tr>
          <td>OS</td>
          <td>Android 13 <a href="https://www.timeextension.com/reviews/ayaneo-pocket-dmg-this-pricey-emulation-monster-thinks-its-a-game-boy?utm_source=chatgpt.com"target="_blank" rel="noopener">Time Extension+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Connectivity</td>
          <td>Wi-Fi 6; Bluetooth 5.3 <a href="https://www.timeextension.com/reviews/ayaneo-pocket-dmg-this-pricey-emulation-monster-thinks-its-a-game-boy?utm_source=chatgpt.com"target="_blank" rel="noopener">Time Extension+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Expansion Ports</td>
          <td>microSD slot; USB-C (for charging/data) <a href="https://droix.net/blogs/ayaneo-pocket-dmg-review/?srsltid=AfmBOoqrvlyNHVvMF7_f9Jn4pgVKChziQFJitL7RDCD-9tmjywBIJvKc&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">DROIX Global+1</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>6000 mAh <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Retro Dodo+2</a></td>
      </tr>
      <tr>
          <td>Size</td>
          <td>91.5 × 151 × 22.3 mm <a href="https://www.timeextension.com/reviews/ayaneo-pocket-dmg-this-pricey-emulation-monster-thinks-its-a-game-boy?utm_source=chatgpt.com"target="_blank" rel="noopener">Time Extension+2DROIX Global+2</a></td>
      </tr>
      <tr>
          <td>Weight</td>
          <td>~ 278-279 g <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Time Extension+2</a></td>
      </tr>
  </tbody>
</table>
<p>Ele é mais potente que o Odin 2 com um Snapdragon G3x Gen 2 e Adreno A32. É comparável a um bom Samsung Galaxy da vida.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914140234_20250914_140205.jpg" alt="Pocket DMG"  loading="lazy" /></p>
<p>A construção dele é super-premium, case, botões, tudo. A tela é um pouco pequena, de 3.92&quot; (acima do que eu falei que considero ideal no 35XX SP), mas é OLED, super nítido, super brilhante, cores super saturadas, uma das melhores telas em qualquer handheld, comparável mesmo à tela de um Samsung Galaxy. Não tem como errar com essa tela. Todo jogo fica ainda mais bonito nela. Por isso custa <strong>caro</strong>!</p>
<p>Pra não dizer que é perfeito, os botões são um pouco &ldquo;mushy&rdquo; enquanto eu prefiro botões mais &ldquo;clicky&rdquo; com os Ambernic. Mas não significa que são ruins.</p>
<p>Por ser potente, também rodaria até Nintendo Switch sem problemas, mas aí a limitação é o tamanho da tela. Não acho que vale a pena rodar jogos feitos pra TVs grandes numa tela tão pequena assim. Ela é melhor mesmo pra retro-games, mas vai rodar PS2 e Gamecube de boas mesmo, com todos os filtros e upscaling que quiser pra deixar mais bonito que o original.</p>
<p>O review do Wulff Den diz tudo:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/U7G_R7nj7BM"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Sendo Snapdragon, esse handheld também é Android, então também é um saco de configurar. Mas no final roda tudo direitinho mesmo. Só seguir o guia do Russ.</p>
<p>Ele tem esse stick analógico no canto inferior esquerdo e tem um touchpad na direita que simula stick analógico direito. Não é confortável pra FPS, é usável pra algumas coisas como reposicionar câmera em jogos de plataforma 3D. Mas não espere usar o tempo todo. Tem o mesmo problema do Miyoo Flip que falei acima: fica MUITO pra baixo. Não é confortável num handheld vertical.</p>
<p>Se quiser jogos que requerem sticks analógicos, é melhor ficar num handheld horizontal, como o Odin 2, SteamDeck, Rog Ally, etc. O nome DMG é de Dot-Matrix Gameboy, que é o Gameboy Clássico. E o Pocket DMG de fato tem todos os fatores nostálgicos do DMG.</p>
<p>Eu, que tive o clássico, gosto muito desse formato. Mas eu acho que se você não tem nostalgia desse período, não vai fazer muita diferença. Esse formato limita jogos feitos pra telas wide-screen. Nesse caso o formato horizontal similar a Nintendo Switch é mil vezes mais ergonômico.</p>
<p>Como falei antes, é pra quem tem nostalgia e dinheiro pra jogar fora. Nada justifica comprar esse aparelho, por melhor que ele seja. É pra colecionador como eu. Odin 2 ou Retroid Pocket 5 tem custo-benefício melhores pra essa categoria.</p>
<h3>Analog Pocket<span class="hx:absolute hx:-mt-20" id="analog-pocket"></span>
    <a href="#analog-pocket" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Falando em caros, chegamos na categoria <strong>super-premium</strong>. E o mais super-premium de todos com certeza é o <a href="https://store.analogue.co/products/analogue-pocket-black"target="_blank" rel="noopener"><strong>Analog Pocket</strong></a>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914141132_20250914_141049.jpg" alt="Analog Pocket"  loading="lazy" /></p>
<p>Essa desgraça nunca está em estoque. Eu mesmo encomendei na época da campanha de lançamento na Indiegogo e levou acho que <strong>1 ano</strong> pra chegar na minha casa. Custou os olhos da cara e mais alguns rims com os impostos do Brasil.</p>
<p>Ele é caro, mas o Pocket DMG é mais caro. Felizmente o preço hoje - se estiver em estoque - é &ldquo;só&rdquo; <strong>USD 220</strong> (sem frete, sem impostos). É razoavelmente acessível. Mas ele é feito pra um público muito específico: quem gosta de FPGAs.</p>
<p>A Analog é famosa por não usar emuladores via software, como RetroArch. Todos os handhelds que comentei até agora usam emuladores: Citra, RPCS3, PCSX2, DuckStation, Sudachi, Yuzu, etc.</p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Display</td>
          <td>3.5-inch backlit LTPS LCD, Gorilla Glass, 1600 × 1440 resolution (~615 ppi) <a href="https://www.analogue.co/pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">TweakTown+3analogue.co+3Retro Handhelds - Play It Forever+3</a></td>
      </tr>
      <tr>
          <td>Refresh Rate / Display Modes</td>
          <td>Variable refresh (about 30-62 Hz) with modes simulating original hardware quirks; supports display filters / palettes per system <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+2analogue.co+2</a></td>
      </tr>
      <tr>
          <td>CPU / FPGA</td>
          <td>Altera Cyclone V FPGA (≈49,000 logic elements) + Altera Cyclone 10 for system management <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+1</a></td>
      </tr>
      <tr>
          <td>Memory</td>
          <td>~ 3.4 MB Block RAM (in Cyclone V), plus 2 × 16 MB 16-bit cellular RAM, 64 MB 16-bit synchronous DRAM, 256 KB asynchronous SRAM <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>4,300 mAh Li-ion (≈3.7 V) <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+2Reddit+2</a></td>
      </tr>
      <tr>
          <td>Battery Life</td>
          <td>~6-10 hours depending on usage/brightness <a href="https://retrohandhelds.gg/rh-reviews-the-analogue-pocket/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+1</a></td>
      </tr>
      <tr>
          <td>Weight</td>
          <td>~276 g <a href="https://retrohandhelds.gg/rh-reviews-the-analogue-pocket/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+1</a></td>
      </tr>
      <tr>
          <td>Connectivity / I/O</td>
          <td>USB-C (for power, firmware, dock/video); micro-SD slot; 3.5 mm headphone jack; Game Boy link cable port <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+1</a></td>
      </tr>
      <tr>
          <td>Cartridge Support</td>
          <td>Native for Game Boy / Game Boy Color / Game Boy Advance; supports additional systems via adapters (Game Gear, Neo Geo Pocket, TurboGrafx-16, Atari Lynx etc.) <a href="https://retrohandhelds.gg/rh-reviews-the-analogue-pocket/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2analogue.co+2</a></td>
      </tr>
      <tr>
          <td>Extras</td>
          <td>Stereo speakers; Nanoloop sequencer/synth; original style “link” port; sleep mode; various display filters; possibility of dock for HDMI output (via Analogue Dock, sold separately) <a href="https://retrohandhelds.gg/rh-reviews-the-analogue-pocket/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2analogue.co+2</a></td>
      </tr>
      <tr>
          <td>Release Date</td>
          <td>December 13, 2021 <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+2Ars Technica+2</a></td>
      </tr>
  </tbody>
</table>
<p>O Analog Pocket vem com o Altera Cyclone V FPGA. Ele foi feito pra rodar consoles antigos como se fosse o hardware original. Não é 100% perfeito (porque os cores de cada console são codificados via engenharia reversa dos chips, mas não é garantia que foram clonados 100%, depende de quem codificou os cores).</p>
<p>No caso do Pocket, ele tem slot pra encaixar cartuchos de verdade de Gameboy e Gameboy Advance. Dinamicamente ele copia a ROM pra memória RAM, carrega o core do Gameboy, e dali é como se estivesse rodando um Gameboy de verdade, no hardware original. Então coisas como frame lag, input lag, e qualquer tipo de latência são minimizados ou zerados. E se jogar lado a lado com um Gameboy de verdade, ele tende a ser idêntico, frame a frame.</p>
<p>Pra maioria das pessoas, na prática, isso não importa - ninguém vai ficar comparando quadro a quadro e a maioria dos emuladores via software hoje fazem um excelente trabalho de emular os consoles antigos de uma forma que um jogador médio não vai perceber a diferença. É realmente só pra quem entende os detalhes, como speed runners. Eu mesmo não noto a diferença.</p>
<p>Mas a grande vantagem desse console, pra mim, é a tela. O tamanho dela é só 3.5&quot; e é IPS, não OLED. Mas é um dos melhores IPS do mercado. Brilhante, boas cores. Mais importante, é a mais densa do mercado com resolução absurda de 1600x1440 pixels (absurdos 615 ppi).</p>
<p>Isso é exatamente 10x a resolução do Gameboy original. Significa que ele consegue fazer upscaling de 10x pixel-perfect. Cada 1 pixel do Gameboy original vira 10 pixels no Analog Pocket. Com isso é possível também colocar filtros que simulam a tela dot-matrix verde antiga, no nível do sub-pixel, simulando todos os efeitos colaterais daquela tela obsoleta, trazendo uma sensação ainda mais perfeita de estar jogando um Gameboy de verdade.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914142232_20250914_142204.jpg" alt="DMG screen"  loading="lazy" /></p>
<p>Não é exagero. Olhem nessa foto, a simulação dos pixels do LCD antigo. Você enxerga exatamente o mesmo comportamento dos pixels com latência do LCD verde.</p>
<p>Acho que ninguém fez um review mais detalhado do que a <strong>Digital Foundry</strong>:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/O9Qy-H7H6og"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Essa tela, sozinha, é razão suficiente pra ter um Analog Pocket se você for um aficcionado por retro-games como eu. É item de colecionador que aprecia qualidade de verdade.</p>
<p>Além disso, eles abriram suporte a <strong>openFPGA</strong> e isso dá possibilidade de instalar dezenas de outras cores de FPGA feitas pela comunidade open source.</p>
<p>Existem várias ferramentas pra instalar e organizar esses cores, como o <a href="https://github.com/neil-morrison44/pocket-sync"target="_blank" rel="noopener">PocketSync</a></p>
<p><img src="https://github.com/neil-morrison44/pocket-sync/raw/main/readme_images/main_screen.png" alt="PocketSync"  loading="lazy" /></p>
<p>Tem FPGAs de arcades antigos, CPS1, NeoGeo, Lynx, PC Engine e muito mais. É como ter o hardware original desses consoles no seu bolso. Não tem experiência igual.</p>
<p>Sim, dá pra rodar tudo isso num emulador no seu PC. Mas vai por mim, essa tela é impressionante. Igualmente tão impressionante quanto o OLED do Pocket DMG. Eles ficam pau a pau em nível de qualidade, mas o Analog tem mais densidade de resolução ainda.</p>
<h3>Menção Honrosa: Razer Kishi<span class="hx:absolute hx:-mt-20" id="menção-honrosa-razer-kishi"></span>
    <a href="#men%c3%a7%c3%a3o-honrosa-razer-kishi" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Notem como metade dos handhelds que eu falei acima são todos Android. Basicamente chips de smartphone mesmo. Daí você já deve ter pensado, <em>&ldquo;ué, porque não jogar direto no meu smartphone então?&rdquo;</em></p>
<p>E você está correto. Pra isso existem controles especiais pra smartphones, como o meu favorito, o <a href="https://www.razer.com/br-pt/mobile-controllers/razer-kishi-v2"target="_blank" rel="noopener"><strong>Razer Kishi</strong></a></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914143603_20250914_143535.jpg" alt="Razer Kishi"  loading="lazy" /></p>
<p>Pra você que não pode sair de casa sem seu Genshin Impact, essa é a melhor opção mesmo:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914143839_razer-kishi-v2-usbc-hero-desktop-1920x700-update.webp" alt="Kishi"  loading="lazy" /></p>
<p>Eu sei que existem outras alternativas, algumas genéricas do AliExpress, e eu não conheço elas. Procure o review específico no YouTube. Cada uma tem suas características. E por causa de tamanho, posição da porta USB-C e coisas assim, nem todo modelo encaixa, por isso é bom ver o site do fabricante pra ver se seu modelo vai encaixar nele. Não é garantido.</p>
<p>Mas ele basicamente funciona como um controle de Xbox conectado via Bluetooth ou USB-C no seu smartphone. Só isso.</p>
<p>O <a href="https://retrogamecorps.com/2022/03/13/android-emulation-starter-guide/"target="_blank" rel="noopener">guia de Android do Russ</a> vale pro seu smartphone também então dá pra instalar emuladores e jogar retro-games igual um Odin 2 ou Pocket DMG. A tela de smartphone normalmente é maior e você já carrega ele no seu bolso todos os dias, daí não precisa carregar um segundo dispositivo.</p>
<p>O controle em si não é pequeno, mas é leve. Tem num case que é fácil de jogar na mochila e não ter problema:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914144206_20250914_144142.jpg" alt="case kishi"  loading="lazy" /></p>
<p>Então sim, não precisa gastar a mais com um novo handheld, use seu smartphone ou aquele mais velho que você encostou e não tinha uso pra ele. Pra retro-games vai funcionar muito bem.</p>
<h3>Rog Ally X<span class="hx:absolute hx:-mt-20" id="rog-ally-x"></span>
    <a href="#rog-ally-x" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>No outro lado espectro, se quiser o mais poderoso e o mais versátil de todos, tamanho não for problema, dinheiro não for problema, vá pra um Handheld PC mesmo. Na minha opinião, o melhor ainda é o <a href="https://rog.asus.com/br/gaming-handhelds/rog-ally/rog-ally-x-2024/"target="_blank" rel="noopener"><strong>ASUS Rog Ally X</strong></a></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914144402_20250914_144341.jpg" alt="Rog Ally X"  loading="lazy" /></p>
<p>Esse é caro nível notebook, porque é basicamente isso que ele é: um notebook num formato mais compacto. Tem as mesmas tecnologias de um notebook.</p>
<table>
  <thead>
      <tr>
          <th>Category</th>
          <th>Specification</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>AMD Ryzen Z1 Extreme processor <a href="https://rog.asus.com/gaming-handhelds/rog-ally/rog-ally-x-2024/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+2Tom&rsquo;s Guide+2</a></td>
      </tr>
      <tr>
          <td>RAM</td>
          <td>Up to 24 GB LPDDR5X-7500 <a href="https://rog.asus.com/gaming-handhelds/rog-ally/rog-ally-x-2024/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+2Ars Technica+2</a></td>
      </tr>
      <tr>
          <td>Storage</td>
          <td>Up to 2 TB NVMe M.2-2280 SSD; common version is 1 TB <a href="https://rog.asus.com/us/gaming-handhelds/rog-ally/rog-ally-x-2024/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+2Best Buy+2</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>7-inch IPS LCD, FHD (1920×1080), 120 Hz refresh rate, 500 nits brightness, Gorilla Glass Victus, sRGB 100%, Adobe ~75% <a href="https://rog.asus.com/us/gaming-handhelds/rog-ally/rog-ally-x-2024/spec/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+2Tom&rsquo;s Guide+2</a></td>
      </tr>
      <tr>
          <td>Ports / I/O</td>
          <td>• 1x USB-C (USB4 / DisplayPort 2.1 / Power Delivery)  <br>• 1x USB-C USB 3.2 Gen2  <br>• 3.5 mm audio jack  <br>• microSD card reader (UHS-II) <a href="https://www.xbox.com/en-US/handhelds/rog-xbox-ally?utm_source=chatgpt.com"target="_blank" rel="noopener">Xbox.com+2Tom&rsquo;s Guide+2</a></td>
      </tr>
      <tr>
          <td>Wireless / Connectivity</td>
          <td>Wi-Fi 6E; Bluetooth 5.2 <a href="https://www.tomsguide.com/gaming/handheld-gaming/asus-rog-ally-x-review?utm_source=chatgpt.com"target="_blank" rel="noopener">Tom&rsquo;s Guide+1</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>80 Wh battery cell <a href="https://www.tomsguide.com/gaming/handheld-gaming/asus-rog-ally-x-review?utm_source=chatgpt.com"target="_blank" rel="noopener">Tom&rsquo;s Guide+1</a></td>
      </tr>
      <tr>
          <td>Cooling / Design</td>
          <td>Zero Gravity thermal system with dual fans; upgraded grips and refined control layout vs original Ally <a href="https://los40.com/2024/06/06/asus-lanza-el-rog-ally-x-una-de-las-mejores-consolas-portatiles-del-mercado/?utm_source=chatgpt.com"target="_blank" rel="noopener">LOS40+1</a></td>
      </tr>
      <tr>
          <td>Weight &amp; Size</td>
          <td>~ 678 g; dimensions similar to original Ally but thicker and heavier due to bigger battery and reinforced frame <a href="https://los40.com/2024/06/06/asus-lanza-el-rog-ally-x-una-de-las-mejores-consolas-portatiles-del-mercado/?utm_source=chatgpt.com"target="_blank" rel="noopener">LOS40+1</a></td>
      </tr>
      <tr>
          <td>OS</td>
          <td>Windows 11 Home + Armoury Crate SE <a href="https://rog.asus.com/gaming-handhelds/rog-ally/rog-ally-x-2024/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+1</a></td>
      </tr>
  </tbody>
</table>
<p>A primeira versão (que ainda é boa e superior ao Steam Deck), num Mercado Livre, vai ser faixa de <strong>BRL 5.000</strong>. A segunda geração que é o &ldquo;X&rdquo;, com chip Z1 Extreme vai ser nada menos que uns <strong>BRL 15.000</strong>. Como falei é nível de notebook e iPhones.</p>
<p>Mas também, se conectar em qualquer Dock USB-C, dá pra conectar num monitor externo, teclado, mouse e ele vira um PC mesmo, rodando Windows 11 normalmente. Dá pra usar pra navegar a web, ver seus e-mails, até programar.</p>
<p>São 24GB de LPDDR5X-7500 (compartilhada com a iGPU Radeon) é bem rápida, tem 2TB de NVME 2280 (full-size), tela de 7&quot; IPS (1&quot; maior que o Switch Original, 1&quot; menor que o Switch 2, Full-HD, 1920x1080 pixels, 120hz, 500 nits de brilho).</p>
<p>O SOC Z1 Extreme é Zen 4, com 8 cores, 16 threads, boost até 5.10 Ghz, com Radeon 780M (12 CUs), TDP de 15 a 30W (essa é a parte que ele é mais fraco que um notebook, lógico, não tem espaço pra dissipar mais calor).</p>
<p>Em comparação a outros chips, ele é mais rápido que um antigo Ryzen 9 5980HS, mais rápido que um Ryzen 5 7535HS. Ou seja é classe de um Ryzen 9 HS. Não chega a ser classe desktop como um Ryzen 9 7945HX ou 8945HX, mas pra um handhed, é muita potência.</p>
<p>E sim, tem outros similares no mercado hoje, como o <a href="https://www.lenovo.com/us/en/c/handheld/"target="_blank" rel="noopener">Lenovo Legion Go</a> que tem tela maior ainda de 8&quot; 120hz, mesmo Z1 Extreme. Ou o Legion Go 2 já com Z2 Extreme, que é arquitetura Zen 5.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914145339_nSZZBYmfv2J7nDTkzGbRcN.webp" alt="Lenovo Legion Go 2"  loading="lazy" /></p>
<p>Tem o <a href="https://www.msi.com/Handheld/Claw-A8-BZ2EMX"target="_blank" rel="noopener">MSI Claw A8</a> também com Z2 Extreme, tela de 8&quot; 120hz.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914145452_Spesifikasi-MSI-Claw-A8.webp" alt="MSI Claw A8"  loading="lazy" /></p>
<p>Qual o melhor? Não sei. Eu só experimentei o Rog Ally X. Recomendo assistir os reviews do <strong>ETA PRiME</strong>. Ele faz as melhores comparações de performance e benchmarks desses chips.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/5T6ZvpZNZT4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>A ASUS também firmou parceria com a Microsoft pra lançar o novo <a href="https://www.xbox.com/en-US/handhelds/rog-xbox-ally"target="_blank" rel="noopener"><strong>ROG Xbox Ally</strong></a>, com Z2 Extreme e um OS de Xbox adaptado pra handheld, que tira a principal desvantagem desses handhelds todos: o fato que Windows 11 é um dos piores OS de todos os tempos pra handhelds. Dá pra usar, mas é bem gambiarra. Já com esse OS oficial, é como se tivesse um Xbox Series no bolso de verdade, com capacidade pra rodar jogos de Steam e outra lojas também.</p>
<p>Eu não tenho, mas fiquei com vontade de experimentar.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914145806_new-leak-rog-xbox-ally-and-ally-x-prices-retail-1-860x484.webp" alt="Rog Xbox Ally"  loading="lazy" /></p>
<p>Todos esses são mais potentes que o <strong>SteamDeck</strong>, mas este ainda continua sendo o melhor custo-benefício no segmento e com o melhor ecossistema de mods, acessórios, e tudo mais. E a Valve tem dado bom suporte de atualizações.</p>
<p>Graças a tecnologias como FSR, hoje em dia dá pra fazer upscaling de resolução e frame generation via IA pra ter mais FPS. Então, jogando em medium settings ou low settings, não fica tão ruim. Com chips Z1 Extreme, Z2 Extreme e Ryzen AI Max+, já dá pra subir pra medium ou até high settings e ficar com bom FPS em Full-HD (1080p).</p>
<p>Todos eles tem saída HDMI, então dá pra ligar numa TV ou monitor. Todos eles aceitam controles externos Bluetooth, então dá pra ligar seu controle de Xbox ou 8BitDo da vida. E ele vira tanto um console quanto um handheld.</p>
<p>Mas são caros, faixa que vai de USD 600 a USD 900 dependendo da marca e modelo. São mais caros que um Playstation 5 e quase faixa de um bom notebook mesmo. Dependendo vale mais a pena comprar um notebook com Ryzen AI Max, que vai ter a mesma Radeon integrada e suportar bons jogos.</p>
<h3>Portáteis Originais<span class="hx:absolute hx:-mt-20" id="portáteis-originais"></span>
    <a href="#port%c3%a1teis-originais" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Vamos a outra constatação importante: qual a melhor forma de jogar handhelds antigos com duas telas, como <strong>Nintendo DS</strong> e <strong>Nintendo 3DS</strong>?</p>
<p>Simples: nos handhelds originais.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914152655_20250914_152628.jpg" alt="nintendo"  loading="lazy" /></p>
<p>A forma mais fácil de jogar jogos piratas neles é com os <a href="https://www.r4ds.com/"target="_blank" rel="noopener">cartuchos R4</a>, acho que não é difícil achar eles em Mercado Livre ou AliExpress. Eles aceitam microSD card e você joga suas ROMs nela, coloca no 3DS e já era.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914152920_20250914_152808.jpg" alt="R4"  loading="lazy" /></p>
<p>Nintendo 3DS teve &ldquo;end-of-life&rdquo; recentemente e desde então todos os jogos estão facilmente disponíveis online. Leia o <a href="https://3ds.hacks.guide/pt_BR/"target="_blank" rel="noopener"><strong>Guia de Hacks do 3DS</strong></a> pra saber como desbloquear o seu. Os jogos estão todos no <a href="https://hshop.erista.me/"target="_blank" rel="noopener"><strong>hShop</strong></a> e quando desbloquear seu 3DS vai instalar o App pra abrir esse site e de lá pode baixar direto as ROMS pra memória interna do aparelho também. Existem várias opções.</p>
<p>Também é possível instalar emuladores no 3DS: vai rodar Gameboy, até Genesis e Master System. Não espere rodar um PS1 ou PSP nele, obviamente, é um hardware fraco.</p>
<p>Só tem uma coisa que me desagrada: as telas são velhas e antiquadas. Tem baixa resolução, baixo brilho, baixo contraste. Comparado com a tela do seu smartphone, nem chega aos pés. Mas pra jogar em dual screen, não tem jeito mais fácil.</p>
<p>Sim, vários fabricantes vieram tentando fazer handhelds com duas telas, como o <a href="https://www.ayaneo.com/goods/9059668426997"target="_blank" rel="noopener"><strong>Ayaneo Flip DS</strong></a> mas é extremamente chato de usar ele. Veja este review do Wulff Den:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/j1TXnfT-zIg"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>São extremamente caros (Android ou Windows) e a experiência de software ainda é extremamente ruim. Não compensa pelo que se paga. Melhor ficar com os originais.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914153857_20250914_153604.jpg" alt="gameboy aluminum"  loading="lazy" /></p>
<p>No caso de Gameboy Advance, já existem dezenas de bons handhelds com emuladores, então é melhor ficar com os RG35XX SP que eu já recomendei antes.</p>
<p>Mas, caso queira explorar a comunidade de mods, recomendo muito o site <a href="https://www.boxypixel.com/"target="_blank" rel="noopener"><strong>Boxy Pixels</strong></a> que fazem cases em alumínio e diversos acessórios pra dispositivos antigos, seja Gameboy, DS, até iPods. Veja este video do canal <strong>Macho Nacho</strong> que demonstra como fazer esse mesmo Gameboy Advance SP em alumínio:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/gJJgnZqpjVE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Foi por causa desse canal que eu comprei o kit e montei o meu. É caro, é um hobby pra entusiastas mesmo. Isso não é pra amadores! Mas se tiver essa vontade, tá aí o site e o canal pra guiar.</p>
<p>Além disso, dá pra jogar ROMs piratas no Advance também. Similar aos cartuchos R4 pra 3DS tem os cartuchos <a href="https://www.ezflash.cn/products/"target="_blank" rel="noopener"><strong>EZ-Flash</strong></a> tanto pra Gameboy DMG/Color quanto Advance. Também são adaptadores de microSD card, onde você joga suas ROMS, pluga no hardware original e ele vai bootar um menu pra escolher as roms.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914154214_20250914_154141.jpg" alt="advance ez-flash"  loading="lazy" /></p>
<p>Eis um exemplo do EZ-Flash no meu Advance SP modificado. A tela está com white balance errado não sei porque, talvez eu tenha cometido algum erro ao montar, mas não parei pra consertar ainda. O importante era só mostrar o menu que aparece no boot pra escolher o jogo.</p>
<p>O cartucho funciona até no Analog Pocket, mas é redundante porque no Pocket posso jogar os ROMs direto nele.</p>
<h3>Os Softwares<span class="hx:absolute hx:-mt-20" id="os-softwares"></span>
    <a href="#os-softwares" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Agora deixa eu resumir o que você precisa saber de emuladores. O primeiro e mais importante de todos é o <a href="https://retroarch.com/"target="_blank" rel="noopener"><strong>RetroArch</strong></a>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914150325_How_to_use_cheats_on_retroarch.webp" alt="RetroArch"  loading="lazy" /></p>
<p>Ele <strong>não é um emulador</strong>, ele é um <strong>front-end pra emuladores</strong>. É uma forma mais fácil de instalar os diversos emuladores individuais, cheats, save states, configurar controles que funcionam em todos, filtros, e muito mais.</p>
<p>Os emuladores mesmo ele chama de &ldquo;Cores&rdquo; que são &ldquo;wrappers&rdquo;/&ldquo;adaptadores&rdquo; pros emuladores de verdade. Cada sistema tem diversos emuladores feitos por diferentes pessoas ou grupos, que focam em coisas específicas (rodar maior quantidade de jogos, rodar menos jogos mas com precisão, conseguir rodar com menos recursos - bons pra handhelds fracos, etc).</p>
<p>Vamos ver uma lista básica (isso muda o tempo todo):</p>
<h3>Nintendo<span class="hx:absolute hx:-mt-20" id="nintendo"></span>
    <a href="#nintendo" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>NES: <strong>Mesen</strong>, Nestopia UE. <a href="https://www.ouma.jp/ootake/?utm_source=chatgpt.com"target="_blank" rel="noopener">Ouma</a></li>
<li>SNES: <strong>bsnes</strong>, Snes9x. <a href="https://www.ouma.jp/ootake/ootake.html?utm_source=chatgpt.com"target="_blank" rel="noopener">Ouma+1</a></li>
<li>N64: <strong>Mupen64Plus-Next</strong> (+ParaLLEl-RDP/Angrylion), Project64. <a href="https://docs.libretro.com/library/mupen64plus/?utm_source=chatgpt.com"target="_blank" rel="noopener">Libretro Docs+2Libretro+2</a></li>
<li>GameCube/Wii: <strong>Dolphin</strong>. <a href="https://dolphin-emu.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">Dolphin Emulator</a></li>
<li>Wii U: <strong>Cemu</strong>. <a href="https://cemu.info/?utm_source=chatgpt.com"target="_blank" rel="noopener">Cemu</a></li>
<li>Switch: <a href="https://yuzuemulators.com/"target="_blank" rel="noopener"><strong>Yuzu</strong></a>, <a href="https://ryujinx.app/"target="_blank" rel="noopener"><strong>Ryujinx</strong></a></li>
<li>GB/GBC: <strong>SameBoy</strong>, Gambatte. <a href="https://sameboy.github.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">sameboy.github.io</a></li>
<li>GBA: <strong>mGBA</strong>. <a href="https://bsnes.org/about/?utm_source=chatgpt.com"target="_blank" rel="noopener">BSNES</a></li>
<li>NDS: <strong>melonDS</strong>, DeSmuME. <a href="https://github.com/flyinghead/flycast?utm_source=chatgpt.com"target="_blank" rel="noopener">GitHub</a></li>
<li>3DS: <strong>Lime3DS</strong> → now <strong>Azahar (successor fork)</strong>. <a href="https://redream.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">redream.io</a></li>
<li>Virtual Boy: <strong>Mednafen VB (Beetle VB)</strong>. <a href="https://emulicious.net/tag/game-gear/?utm_source=chatgpt.com"target="_blank" rel="noopener">Emulicious</a></li>
</ul>
<h3>Sega<span class="hx:absolute hx:-mt-20" id="sega"></span>
    <a href="#sega" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>SG-1000/Master System/Game Gear: <strong>Emulicious</strong>, Genesis Plus GX.</li>
<li>Mega Drive/Genesis: <strong>BlastEm</strong>, Genesis Plus GX. <a href="https://www.airdroid.com/screen-mirror/sega-saturn-emulator/?utm_source=chatgpt.com"target="_blank" rel="noopener">AirDroid</a></li>
<li>Sega CD: <strong>Genesis Plus GX</strong>. <a href="https://www.airdroid.com/screen-mirror/sega-saturn-emulator/?utm_source=chatgpt.com"target="_blank" rel="noopener">AirDroid</a></li>
<li>32X: <strong>PicoDrive</strong>. <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
<li>Saturn: <strong>Beetle/Mednafen Saturn</strong>, Kronos/Yaba Sanshiro (faster). <a href="https://github.com/libretro/neocd_libretro?utm_source=chatgpt.com"target="_blank" rel="noopener">GitHub</a></li>
<li>Dreamcast/Naomi: <strong>Flycast</strong>, Redream. <a href="https://www.mamedev.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">mamedev.org+1</a></li>
</ul>
<h3>Sony<span class="hx:absolute hx:-mt-20" id="sony"></span>
    <a href="#sony" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>PlayStation (PS1): <strong>DuckStation</strong> (accuracy/perf), Beetle PSX HW/SW. <a href="https://emulicious.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">Emulicious</a></li>
<li>PlayStation 2: <strong>PCSX2</strong>. <a href="https://pcsx2.net/docs/setup/linux/?utm_source=chatgpt.com"target="_blank" rel="noopener">pcsx2.net</a></li>
<li>PlayStation 3: <strong>RPCS3</strong>. <a href="https://rpcs3.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">RPCS3+1</a></li>
<li>PSP: <strong>PPSSPP</strong>. <a href="https://rpcs3.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">RPCS3</a></li>
<li>PS Vita: <strong>Vita3K</strong>. <a href="https://github.com/LIJI32/SameBoy?utm_source=chatgpt.com"target="_blank" rel="noopener">GitHub</a></li>
<li>PS4: <strong>shadPS4</strong> (rapid progress; still early). <a href="https://shadps4.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">ShadPS4+2ShadPS4+2</a></li>
</ul>
<h3>Microsoft<span class="hx:absolute hx:-mt-20" id="microsoft"></span>
    <a href="#microsoft" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Xbox (OG): <strong>xemu</strong>, Cxbx-Reloaded. <a href="https://sameboy.github.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">sameboy.github.io+1</a></li>
<li>Xbox 360: <strong>Xenia</strong>. <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
</ul>
<h3>NEC / Hudson<span class="hx:absolute hx:-mt-20" id="nec--hudson"></span>
    <a href="#nec--hudson" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>PC Engine/TurboGrafx-16(+CD): <strong>Mednafen (Beetle PCE Fast)</strong>, Ootake (Windows). <a href="https://emulation.gametechwiki.com/index.php/Neo_Geo_Pocket_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki+1</a></li>
<li>PC-FX: <strong>Mednafen (Beetle PC-FX)</strong>. <a href="https://emulicious.net/tag/game-gear/?utm_source=chatgpt.com"target="_blank" rel="noopener">Emulicious</a></li>
</ul>
<h3>SNK / Arcade &amp; Handhelds<span class="hx:absolute hx:-mt-20" id="snk--arcade--handhelds"></span>
    <a href="#snk--arcade--handhelds" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Neo Geo AES/MVS (arcade): <strong>FBNeo</strong>, MAME. <a href="https://www.ppsspp.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">ppsspp.org+1</a></li>
<li>Neo Geo CD: <strong>NeoCD (libretro)</strong>, MAME. <a href="https://melonds.kuribo64.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">melonds.kuribo64.net+1</a></li>
<li>Neo Geo Pocket/Color: <strong>Mednafen (Beetle NeoPop)</strong>, RACE. <a href="https://github.com/LIJI32/SameBoy?utm_source=chatgpt.com"target="_blank" rel="noopener">GitHub</a></li>
</ul>
<h3>Bandai / Others (handheld)<span class="hx:absolute hx:-mt-20" id="bandai--others-handheld"></span>
    <a href="#bandai--others-handheld" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>WonderSwan/Color: <strong>Mednafen (Beetle WSWAN)</strong>. [sameboy.github.io](<a href="https://sameboy.github.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">https://sameboy.github.io/?utm_source=chatgpt.com</a></li>
<li>Atari Lynx: <strong>Mednafen (Beetle Handy)</strong>. <a href="https://emulicious.net/tag/game-gear/?utm_source=chatgpt.com"target="_blank" rel="noopener">Emulicious</a></li>
</ul>
<h3>Atari (consoles)<span class="hx:absolute hx:-mt-20" id="atari-consoles"></span>
    <a href="#atari-consoles" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>2600: <strong>Stella</strong>. <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
<li>5200/8-bit: <strong>Altirra</strong> / Atari800. <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
<li>7800: <strong>A7800</strong> (or MAME). <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
<li>Jaguar: <strong>BigPEmu</strong>. <a href="https://mednafen.github.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">mednafen.github.io</a></li>
</ul>
<h3>3DO / CD-i / Misc. classic<span class="hx:absolute hx:-mt-20" id="3do--cd-i--misc-classic"></span>
    <a href="#3do--cd-i--misc-classic" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>3DO: <strong>Opera (libretro)</strong>. <a href="https://docs.libretro.com/library/opera/?utm_source=chatgpt.com"target="_blank" rel="noopener">Libretro Docs</a></li>
<li>Philips CD-i: <strong>MAME</strong> (best public option). <a href="https://vita3k.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">Vita3K</a></li>
<li>Vectrex: <strong>ParaJVE</strong>. <a href="https://vectrex-emu.blogspot.com/?utm_source=chatgpt.com"target="_blank" rel="noopener">vectrex-emu.blogspot.com</a></li>
<li>Intellivision: <strong>jzIntv</strong>. <a href="https://intellivision.us/intvgames/jzintv/jzintv.php?utm_source=chatgpt.com"target="_blank" rel="noopener">intellivision.us</a></li>
<li>ColecoVision: <strong>blueMSX (core)</strong> / MAME. <a href="https://docs.libretro.com/library/bluemsx/?utm_source=chatgpt.com"target="_blank" rel="noopener">Libretro Docs</a></li>
<li>Magnavox Odyssey²/Videopac+: <strong>O2EM</strong>. <a href="https://o2em.sourceforge.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">o2em.sourceforge.net</a></li>
<li>Fairchild Channel F, Bally Astrocade: <strong>MAME</strong>. <a href="https://vita3k.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">Vita3K</a></li>
</ul>
<h3>Arcade (general)<span class="hx:absolute hx:-mt-20" id="arcade-general"></span>
    <a href="#arcade-general" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>MAME</strong> (breadth/accuracy), <strong>FinalBurn Neo</strong> (speed/curation). <a href="https://vita3k.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">Vita3K+1</a></li>
</ul>
<h3>Home computers (popular)<span class="hx:absolute hx:-mt-20" id="home-computers-popular"></span>
    <a href="#home-computers-popular" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Commodore 64/128/VIC-20/PET: <strong>VICE</strong>. <a href="https://vice-emu.sourceforge.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">vice-emu.sourceforge.io</a></li>
<li>Amiga: <strong>WinUAE</strong> (Windows), <strong>FS-UAE</strong> (cross-platform). [winuae.net+1](<a href="https://www.winuae.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">https://www.winuae.net/?utm_source=chatgpt.com</a></li>
<li>Atari ST/STE/TT/Falcon: <strong>Hatari</strong>, Steem SSE. <a href="https://www.hatari-emu.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">hatari-emu.org+1</a></li>
<li>ZX Spectrum: <strong>FUSE</strong>, Retro Virtual Machine. <a href="https://fuse-emulator.sourceforge.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">fuse-emulator.sourceforge.net+1</a></li>
<li>MSX: <strong>openMSX</strong>, blueMSX (stale but usable; libretro core still common). <a href="https://openmsx.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">openmsx.org+2msx.org+2</a></li>
<li>PC-98: <strong>Neko Project II kai (NP2kai)</strong> (or DOSBox-X for DOS/V/PC-98 modes). <a href="https://docs.libretro.com/library/neko_project_ii_kai/?utm_source=chatgpt.com"target="_blank" rel="noopener">Libretro Docs+1</a></li>
<li>DOS / Win9x era: <strong>DOSBox Staging</strong> (games), <strong>DOSBox-X</strong> (games + Win3.x/9x).</li>
</ul>
<p>Alguns emuladores são chatinhos, porque estão incompletos ou em desenvolvimento ou bugados ou sem suporte mais. Alguns exemplos:</p>
<ul>
<li>Xemu pra Xbox original funciona bem, mas é bem mal otimizado, portanto é bem pesado. Não vai rodar em nada que não seja pelo menos um handheld PC moderno como o Rog Ally ou um PC de verdade.</li>
<li>Xenia Canary pra Xbox 360 ainda é bem bugado, só funciona em linha de comando (tem uma GUI de terceiros mais ou menos), tem que configurar arquivos pra tunar cada jogo. Meus jogos favoritos como Forza Motorsport 4 rodam com vários bugs visuais e crashes aleatórios que inviabiliza jogar (por isso comprei um Xbox 360 de verdade e desbloqueei).</li>
<li>RPCS3 avançou bastante, mas não chega aos pés do PCSX2 ainda. Muitos jogos exigem configurações especiais - que não são intuitivos pra um amador, tem que ler o Wiki com muito cuidado, pra cada jogo. Jogos favoritos meus como Gran Turismo 6 ainda não rodam direito.</li>
<li>shadPS4, esquece por enquanto, ele começou desenvolvimento recentemente, ainda é mais alpha que beta, quase nada roda nele sem muito trabalho. Não é pra amadores.</li>
<li>Dolphin, até que é bem estável e quase plug and play, mas é mais pesado que um PCSX2. Não vai rodar em hardwares fracos.</li>
<li>Mupen64 roda bem também, até em Android, mas nem todo jogo ainda roda nele e alguns rodam com pequenos glitches. No geral dá pra jogar, mas não espere perfeição.</li>
<li>Emuladores de 8-bits, 16-bits, estão bem completos, estáveis, rodam liso qualquer um deles, pode confiar, incluindo arcades via Mame ou FBNEO. Mas no caso desses últimos, eles exisgem <strong>romsets</strong> (conjuntos de ROMS compatíveis com o emulador), não dá pra pegar qualquer ROM aleatória por aí e esperar que vai rodar. Fuce o <a href="https://archive.org/details/Neo-geoRomCollectionByGhostware"target="_blank" rel="noopener">Internet Archive</a> pra achar alguns desses romsets.</li>
<li>Home Computers como openMSX ou DOSBox, lembre que muitos jogos só funcionam com teclado ou mouse ou os dois e talvez não funcione muito bem mesmo mapeando pra controle. Tem que ler o Wiki de cada jogo pra saber.</li>
<li>Por causa dos processos da Nintendo, emuladores de Switch aparecem e somem, alguém faz um novo fork e reaparece. Yuzu já foi fechado mas forks apareceram. Surgiu Suyu, mas fechou. Ryujinx continua funcionando e é o meu favorito. Android acho que tem Sudachi e outros. Tem que dar uma pesquisada.</li>
</ul>
<p>RetroArch tem suporte pra quase todos esses emuladores. Portanto só instalando ele, já vai te dar acesso à maioria. Alguns é melhor instalar separado como apps individuais, em particular isso é verdade em Android, por isso falo tanto do guia do Russ e como Android é mais chato.</p>
<p>Em Linux, distros como OnionOS, GammaOS, Surwish, Knulli, MinUI, já vem com RetroArch instado e pré-configurado, por isso são mais fáceis de instalar e usar.</p>
<p>Dá pra usar só o RetroArch, seja em handheld, seja em Android, seja no Windows. Mas a interface dele é bem feia, velha, chata de navegar. Talvez você não se importe, mas depois que tem a experiência de console, como Playstation, Xbox, é chato usar uma interface velha. Pra consertar isso existem diversos front-ends pra colocar por cima do RetroArch, o mais famoso e popular de todos acho que é o <a href="https://emulationstation.org/"target="_blank" rel="noopener"><strong>EmulationStation</strong></a></p>
<p>Ele é bonito, dá pra escolher vários temas e fica assim:</p>
<p><img src="https://emulationstation.org/assets/featurettes/theming_list.jpg" alt="ES"  loading="lazy" /></p>
<p>Novamente, o Russ do canal Retro Game Corps tem guias pra isso:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=X-bVwlMwobE"target="_blank" rel="noopener">Emulation Station em Android</a></li>
<li><a href="https://www.youtube.com/watch?v=5upaSxC1wTg"target="_blank" rel="noopener">Emulation Station no SteamDeck</a></li>
<li><a href="https://www.youtube.com/watch?v=05dunYi6hkY"target="_blank" rel="noopener">Emulation Station no Windows</a></li>
</ul>
<p>Tem mais videos, só pesquisar por &ldquo;emulation station&rdquo; direto no canal dele e também no blog dele. Tem dezenas de guias por aí, por isso não vou perder tempo detalhando ele. Pára de ter preguiça e pesquisa. O que não falta é material.</p>
<p>No mundo de handhelds Linux, também existe Emulation Station em distros como <a href="https://knulli.org/pt-BR/"target="_blank" rel="noopener"><strong>Knulli</strong></a>, que é um fork do antigo Batocera. E adivinhe: tem guia do Russ:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/2ZMwdyuAv7o"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Já entendeu a única coisa que você precisa tirar deste artigo né: se tiver alguma dúvida sobre esse assunto, pergunte ao Russ, não a mim!</p>
<p>No mundo de SteamDeck e outros handhelds PC, existe outra distro Linux, o <a href="https://bazzite.gg/"target="_blank" rel="noopener"><strong>Bazzite</strong></a> que é um fork modificado do SteamOS pra rodar fora do SteamDeck.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914152336_asus-rog-ally-bazzite-feature-image.webp" alt="Ally Bazzite"  loading="lazy" /></p>
<p>Assim seu Rog Ally vai funcionar igual um SteamDeck mais potente! Rodando jogos de Steam em Linux via Proton. Eu pessoalmente não fui por essa opção porque já me acostumei com a chatice do Windows 11 e eu gosto de rodar <a href="https://www.wemod.com/"target="_blank" rel="noopener"><strong>WeMod</strong></a> pra rodar jogos com cheats. Além disso eu instalei outros emuladores que só funcionam em Windows, com os de <a href="https://segaretro.org/Model_2_Emulator"target="_blank" rel="noopener">Sega Model 2</a> e <a href="https://github.com/trzy/Supermodel"target="_blank" rel="noopener">Model 3</a>. Sim, tem como rodar em Linux com Wine e tudo mais, mas já tá funcionando, deixa assim. Faz no seu.</p>
<p>Pra Emulation Station e outros front-end como <a href="https://github.com/TapiocaFox/Daijishou"target="_blank" rel="noopener"><strong>Daijisho</strong></a> no Android vão pedir pra você ter uma conta no site <a href="https://www.screenscraper.fr/"target="_blank" rel="noopener">ScreenScrapper</a>. Com essa conta dá pra ler as ROMs no seu microSD card e ir no site buscar coisas como imagem da caixa, video de demonstração e tudo mais pra ficar tudo mais bonito.</p>
<p>Última coisa: se eu tenho tantos handhelds, como faço pra compartilhar os saves entre todos eles pra continuar jogando de outro handheld?</p>
<p>Tem dois jeitos: o mais fácil é só tirar o microSD de um e colocar no outro e vai ter os mesmos saves. A outra forma - bem mais complicada (que é o que eu faço) - é subir um container de <a href="https://github.com/syncthing/syncthing"target="_blank" rel="noopener"><strong>SyncThing</strong></a>, que é um serviço que syncroniza diretórios entre diferentes computadores (pense um mini-Dropbox). Pra variar, o Russ tem um tutorial:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/NPx8FREezR4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Entendeu a mensagem do post? Não pergunte <em>&ldquo;Akita, qual retro-handheld é melhor pra eu comprar?&rdquo;</em> O coitado do Akita não é tech-reviewer pago, patrocinado, nem monetizado, portanto todos os handhelds que eu tenho, comprei só pra mim. Por isso não tenho nenhum Retroid. Não adianta perguntar se Ambernic ou Ayaneo são melhores que Retroid. Akita não vai saber.</p>
<p>Em vez disso perguntem a tech reviewers que são pagos a patrocinados pra falar disso. Eis minhas recomendações:</p>
<ul>
<li><a href="https://www.youtube.com/@RetroGameCorps"target="_blank" rel="noopener">Retro Game Corps</a></li>
<li><a href="https://www.youtube.com/@WulffDen"target="_blank" rel="noopener">Wulff Den</a></li>
<li><a href="https://www.youtube.com/@TechDweeb"target="_blank" rel="noopener">Tech Dweeb</a></li>
<li><a href="https://www.youtube.com/@TakiUdon"target="_blank" rel="noopener">Taki Udon</a></li>
<li><a href="https://www.youtube.com/@ETAPRIME"target="_blank" rel="noopener">ETA PRIME</a></li>
</ul>
<p>Pra quem se interessa por mods:</p>
<ul>
<li><a href="https://www.youtube.com/@MachoNachoProductions"target="_blank" rel="noopener">Macho Nacho Productions</a></li>
<li><a href="https://www.youtube.com/@TheRetroFuture"target="_blank" rel="noopener">The Retro Future</a></li>
</ul>
<p>E pra quem se interessa por consertos:</p>
<ul>
<li><a href="https://www.youtube.com/@Tronicsfix"target="_blank" rel="noopener">TronicsFix</a></li>
</ul>
<p>Todos eles vão dar respostas melhores sobre todas as suas perguntas sobre todos os modelos de handhelds, consoles, consertos, modificações, softwares, OS, customizações, ROMs e muito mais.</p>
<p>Eu fiz esta página só pra poder dar copy e paste do link pra todo mundo que repetir essas mesmas perguntas daqui pra frente. Acho que cobri tudo que eu sei do assunto!</p>
]]></content:encoded><category>games</category><category>emulacao</category><category>retrocomputacao</category><category>off-topic</category></item><item><title>Usando I.A (ComfyUI) pra gerar NPCs em desenvolvimento de games</title><link>https://akitaonrails.github.io/2025/04/23/usando-i-a-comfyui-pra-gerar-npcs-em-desenvolvimento-de-games/</link><guid isPermaLink="true">https://akitaonrails.github.io/2025/04/23/usando-i-a-comfyui-pra-gerar-npcs-em-desenvolvimento-de-games/</guid><pubDate>Wed, 23 Apr 2025 16:25:00 -0300</pubDate><description>&lt;p&gt;Eu andei atualizando BASTANTE meu projetinho de Comfyui com Docker Compose. Eu acho que é o setup mais completo e testado de todos, com a vantagem de ser em Docker, então é repetitível com zero setup. Leia &lt;a href="https://github.com/akitaonrails/ComfyUI-Docker-CUDA-preloaded"target="_blank" rel="noopener"&gt;meu post&lt;/a&gt; pra mais detalhes sobre como ele funciona.&lt;/p&gt;
&lt;p&gt;Resolvi documentar neste post sobre um dos workflow mais complexos que eu testei que funciona nesse meu setup: como desenvolver Character Sheets de personagens aleatórios, em qualquer estilo, seja realista, seja estilo pixar, seja estilo cartoon, o que você quiser. O resultado é um sheet como no exemplo abaixo. Em várias poses, várias iluminações, várias expressões de emoção, com índice de cor, tudo gerado do absoluto zero pela &amp;ldquo;I.A.&amp;rdquo;. Em meia hora de processamento na minha RTX 4090.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu andei atualizando BASTANTE meu projetinho de Comfyui com Docker Compose. Eu acho que é o setup mais completo e testado de todos, com a vantagem de ser em Docker, então é repetitível com zero setup. Leia <a href="https://github.com/akitaonrails/ComfyUI-Docker-CUDA-preloaded"target="_blank" rel="noopener">meu post</a> pra mais detalhes sobre como ele funciona.</p>
<p>Resolvi documentar neste post sobre um dos workflow mais complexos que eu testei que funciona nesse meu setup: como desenvolver Character Sheets de personagens aleatórios, em qualquer estilo, seja realista, seja estilo pixar, seja estilo cartoon, o que você quiser. O resultado é um sheet como no exemplo abaixo. Em várias poses, várias iluminações, várias expressões de emoção, com índice de cor, tudo gerado do absoluto zero pela &ldquo;I.A.&rdquo;. Em meia hora de processamento na minha RTX 4090.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/469eyg4a4pl3ry0z12twg74nlbc8" alt="NPC Design Sheet"  loading="lazy" /></p>
<p>Imagine que você é estag em estúdio de jogos. Seu trabalho: criar 100 personagens de fundo (NPCs). No fim tem que gerar 100 desses. Mas só porque é personagem secundário, não pode fazer de qualquer jeito, tem que ser todos coerentes, em todas as poses. Imagina quantos dias você iria levar. E se desse pra automatizar? É pra esse tipo de cenário que I.A. é interessante. Gaste mais tempo nos personagens principais, faça manualmente, mas não perca tempo nos secundários e não baixe a qualidade final de tudo.</p>
<p>Eu não fiz esse workflow, quem fez foi o Mickmumpitz. Assista o video inteiro dele pra saber como funciona esse workflow, não vou repetir o que ele já explica:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/grtmiWbmvv0"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Também não vou compartilhar o workflow dele, porque ele tem um Patreon pago (é super barato, só USD 10 por mês), que te dá acesso a baixar o pacote de workflow inteiro dele <a href="https://www.patreon.com/posts/free-workflows-120405048"target="_blank" rel="noopener">neste link</a></p>
<p>Mas só isso não adianta, os requerimentos que você precisa:</p>
<ul>
<li>uma máquina parruda com pelo menos uma RTX 3090 com 24GB de VRAM. Importante aqui é VRAM, os modelos usados fácil ultrapassam uso de 20GB. CPU é menos importante, eu uso uma 7950X3D mas uma 7800 já daria conta.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/730safwxqkrsgawu4liw42scoul3" alt="GPU VRAM"  loading="lazy" /></p>
<ul>
<li>caso não tenha máquina assim, dá mais trabalho mas você pode alugar uma na <strong>RUNPOD</strong>. Eles tem várias configurações de GPU, mas você vai precisar saber configurar um pouco Linux ou escolher Windows e fazer o tutorial do Mickmumptiz tudo na mão (vai por mim, você vai sofrer se fizer assim).</li>
<li>precisa ter pelo menos <strong>500GB</strong> de espaço disponível e internet boa pra baixar. Na primeira vez que meu Docker rodar, ele baixa automaticamente todas as extensions de ComfyUI e todos os modelos pra tudo. Dá pra editar o arquivo <code>models.conf</code> antes e remover modelos que sabe que nunca vai usar. Mas só este workflow exige pelo menos uns 30GB de modelos, não tem como fugir disso.</li>
<li>esse workflow é particularmente <strong>PESADO</strong> porque são várias funcionalidades (que podemos desligar partes, pra customizar pro nosso fluxo de trabalho). Mas pra 1 personagem, o fluxo inteiro pode levar <strong>30 MINUTOS</strong>. Mesmo numa RTX 4090 como a minha.</li>
</ul>
<p>Se fez tudo certo até este ponto, tem ComfyUI rodando com todas as dependências já baixadas e comprou o Workflow. Quando carregar vai ter que consertar algumas coisas manualmente.</p>
<p>Primeira coisa é que vai ver um erro em vários Nodes em vermelho, todos de <strong>Ultimate SD Upscale</strong>, basta clicar com o botão direito do mouse em cada um e escolher &ldquo;Fix Recreate&rdquo; que vai consertar automaticamente:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/djblur5g36mw9denng0ht0vvksym" alt="Fix Upscale"  loading="lazy" /></p>
<p>O ComfyUI exige que cada slot de output de um Node se ligue no slot de input de outro Node compatível, mas frequentemente os workflow ficam tão grandes que tem fiozinho conectando coisa espalhado pra tudo que é canto e fica bem difícil de saber o que liga no que. Literalmente fica <strong>macarrônico</strong>.</p>
<p>Mas existe uma extension (que eu já deixei pré-instalado) chamado <a href="https://github.com/chrisgoringe/cg-use-everywhere"target="_blank" rel="noopener">cg-use-everywhere</a>. Toda extension é um projetinho do GitHub, clonado no sub-diretório <code>custom_nodes</code>. Ele permite conectar a saída de Node nesse node <strong>Anything Elsewhere</strong>, digamos a saída &ldquo;clip&rdquo; do Node &ldquo;Load Clip&rdquo;. Agora, todo outro Node que tiver como input o campo &ldquo;clip&rdquo; e não tiver nada conectando explicitamente nele, vai usar esse Anything que foi criado. Funciona super bem.</p>
<p>Só nesse workflow do Mick que, sei lá porque, todos os Anywheres estão quebrados. Mas é fácil consertar. Basta procurar esses Nodes, apagar, criar novos e reconectar. Tem vários logo no começo, anote quem liga em cada um, apague e crie um novo pra reconectar:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/kjjo7u6g58drww1v5f8v88h1iis1" alt="anywhere initial"  loading="lazy" /></p>
<p>Tem também alguns no grupo 02 de Upscale:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/qrkdxs6qjdtmdjs3c463oxetbgyy" alt="anywhere upscale"  loading="lazy" /></p>
<p>Nodes pequenos, só com o título, estão COLAPSADOS. Só clicar com o botão direito e escolher EXPAND pra ver os detalhes. É outra forma de organizar a bagunça.</p>
<p>Por último, tem que rechecar o nome correto dos modelos em todos os Nodes de &ldquo;Load&rdquo; alguma coisa logo no começo do workflow (ainda bem que ele organizou esses nodes tudo junto):</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/y1u93ujz3kq4hz3pik5q4wcgapoa" alt="model path"  loading="lazy" /></p>
<p>No workflow dele, o Node vem procurando por &ldquo;FLUX/flux1-dev-fp8.safetensors&rdquo; mas aí você vai na lista (que puxa o que está mesmo no diretório &ldquo;models/checkpoints&rdquo; na sua máquina) e escolhe o que tem o mesmo nome. Isso acontece frequentemente porque diferentes pessoas organizam sub-diretórios diferentes pros modelos. Mas depois de configurar é só salvar e pronto. Tem que fazer isso pro checkpoint, controlnet, ic-light, etc.</p>
<p>Os erros do ComfyUI não são amigáveis. São stacktraces de Python, que não são amigáveis porque ele mostra que linha do código deu pau, mas não mostra o que tinha nas variáveis passadas pra função que deu pau. Daí não dá pra saber onde foi. Mas normalmente na interface web, o Node fica em vermelho, daí você checa e normalmente é porque esqueceu de baixar o modelo ou escolher o certo da lista.</p>
<p>Última coisa nesse workflow é baixar a image de OpenPose da página de Patreon dele, que linkei no começo do post, e carregar:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/uajcc6ocnr5llzv8wzoowl85c5o3" alt="openpose image"  loading="lazy" /></p>
<p><strong>OpenPose</strong> é um formato de arquivo padrão que descreve poses, formato aberto que pode ser editar em várias ferramentas. E tem diversos modelos pré-treinados pra extrair poses nesse formato a partir de imagens, então nem precisamos editar na mão. Podemos baixar várias poses pré-prontas e abertas neste site:</p>
<p><a href="https://openposes.com/"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/ntvaf9vba1rugg11qn3n14u2t69e" alt="Poses Sites"  loading="lazy" /></a>
Vou repetir várias vezes. mas <strong>assistam o video tutorial do Mick</strong> onde ele explica como mandar gerar personagens do zero ou usar <strong>suas próprias fotos</strong> com suas próprias poses pra continuar o fluxo a partir disso. O workflow dele, depois que roda, tem esta cara (com zoom lá embaixo):</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/jqu4o2c5cenci6au2g8bbny064mm" alt="complete workflow"  loading="lazy" /></p>
<p>Na primeira parte, tem a configuração e checagem manual dos modelos. Só tem que arrumar uma vez e salvar. Depois sempre vai funcionar igual. Nesse primeiro menu também dá pra ligar e desligar alguns dos grupos de Nodes, por exemplo, pra pular a primeira etapa de gerar personagem do zero e poder usar suas próprias fotos:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/s72mrc1ib5o173c9l74vmpsn3js3" alt="menu and setup"  loading="lazy" /></p>
<p>Se optar por gerar personagem do zero, tem em verde uma caixa de prompt pra digitar como quer que seja sua personagem, em que estilo. Prompts de Texto são decodificados por modelos de <strong>CLIP</strong> (Contrastive Language Image Pre-Training), que são específicos pra determinadas categorias de UNETs (como SDXL pra Stable Diffusion ou o melhor e mais popular FLUX agora). Parte do aprendizado é começar a aprender quais sub-modelos (clips, clip_vision, vaes, loras, etc) são compatíveis com quais unets (unet, checkpoints, diffusion_models). Não pode misturar qualquer coisa. Grosseiramente, é meio que se você escolhe fazer um texto em alemão, todos os plugins tem que ser em alemão.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/37oe4dyqr5t0in9ad98bocli6u3w" alt="Character Generation"  loading="lazy" /></p>
<p>Não vou mostrar o workflow completo porque nem cabe, mas dá pra ver em verde os prompts, no meio onde escolhemos que pode queremos (tá no Patreon dele), e em cima a image gerada pelo modelo <strong>flux1-dev-fp8</strong>, um dos melhores e mais populares por ter excelente qualidade e não ser tão pesado (fp8 em vez de fp32, por exemplo).</p>
<p>Isso é uma das vantagens de usar ferramentas fora dos Dalle ou Midjourney da vida: podemos controlar todos os aspectos da geração da imagem não só com prompts de texto, mas com prompts de imagens, como o OpenPose.</p>
<p>Outro detalhe. Expliquei no meu post anterior sobre KSampler ou Samplers em geral, que são o motor que faz todo o trabalho de juntar todos os modelos, imagens, prompts, controlnet, vaes e produz a imagem final. Os parâmetros do KSampler como steps, cfg, denoise, scheduler e mais <strong>DEPENDEM</strong> do modelo escolhido. Tem modelos bem documentados, tem modelos mal documentados.</p>
<p>Por exemplo, digamos que você leu numa thread de Reddit sobre esse outro modelo mais otimizado chamado <a href="https://civitai.com/models/215418?modelVersionId=273102"target="_blank" rel="noopener">&ldquo;TurboVisionXL&rdquo;</a>, que está disponível no site Civit.ai:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/hpcj5e8g0hxvefelvszwf48vsnpf" alt="TurboVisionXL"  loading="lazy" /></p>
<p>Realmente é um bom modelo mas e agora? O que eu configuro no KSampler pra ele? Felizmente se scrolar a página (sempre leia a documentação original!!) vai encontrar estas recomendações:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/57f9vyfh4w9j8bduaomc3aow2sks" alt="TurboVisionXL documentation"  loading="lazy" /></p>
<p>Viu só? Ele explica o que configurar e quais são limitações conhecidas. Mais embaixo vai ter comentários de outras pessoas que podem dar mais dicas ou compartilhar erros que você já tenha visto. É uma enorme comunidade, precisa aprender a participar dela.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/7avk9tl1pop1eexkuu3h8epgs2t5" alt="MultiView"  loading="lazy" /></p>
<p>Mas voltando da tangente, no segundo grupo de nodes do Mick, ele pega a primeira imagem em &ldquo;Pose T&rdquo; e passa por um processo de &ldquo;Multi View&rdquo; usando Diffuser MV que faz isso automaticamente. É a mesma pose, mas como se a câmera desse um 360 graus ao redor dela, pegando ângulos diferentes e, principalmente, gerando novas imagens coerentes com a original (veja como o modelo é usado até pra inventar as costas da personagem).</p>
<p>Nesse passo também ele extrai só o rosto da primeira imagem pra fazer outros tratamentos em paralelo. Reconhecimento e extração de rostos é super comum. Todo sistema de segurança usa, Google Photos usa pra organizar álbuns dinâmicos. E vale você aprender pra usar em seus produtos. É um processo razoavelmente leve e rápido hoje em dia e tem vários algoritmos e modelos pré-prontos pra usar. Nesse caso acho que nem usa I.A. propriamente dito, é um algoritmo mesmo.</p>
<p>Outro detalhe: modelos de geração de imagens normalmente trabalham em <strong>BAIXA RESOLUÇÃO</strong>. Normalmente abaixo de 1024x1024. Não espere gerar imagens 4K logo de cara. Mas não tem problema, porque a solução é primeiro gerar uma image de baixa resolução e depois passar por outro modelo de I.A. especializado em <strong>UPSCALING</strong> como o RealESRGAN que já falei no meu outro post sobre <a href="https://www.akitaonrails.com/2025/04/19/aumentando-resolucao-de-anime-velho-pra-4k-com-i-a"target="_blank" rel="noopener">upscaling de anime</a></p>
<p>Diferente do que faz um Photoshop ou qualquer editor de imagens, se tentar aumentar uma imagem, ele só vai pegar um pixel e tentar duplicar, quadruplicar os pixels ao redor. Mas isso costuma só deixar a imagem maior mas borrada (blurred), porque ele não tem como saber os detalhes, e nem vai tentar &ldquo;inventar&rdquo; detalhes.</p>
<p>Pra &ldquo;inventar&rdquo; detalhes, precisa de um modelo pré-treinado que aprendeu o que desenhar. É como funciona também o DLSS 3 da NVIDIA pra games, onde o jogo renderiza em baixa resolução, como 720p e o DLSS, em tempo real, redesenha a nova tela em 4K. Não fica perfeito, mas jogando a 60fps, você raramente vai notar a diferença. Só vai perceber que ficou mais <strong>NÍTIDO</strong>.</p>
<p>Por isso também, se você usar sua própria foto, ou foto de pessoas conhecidas, vai ver que a nova foto depois de upscaling ficou <strong>levemente diferente</strong>, não é mais a mesma pessoa, porque o modelo <strong>REDESENHA</strong> detalhes que não existiam. É um processo de interpretação e não de descobrir detalhes &ldquo;escondidos&rdquo; (isso não existe, só na ficção de CSI).</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2he2fgmus8vmp3wfp95s3qbh7ztf" alt="Upscale 2"  loading="lazy" /></p>
<p>O workflow do Mick vai um passo além e tem uma segunda passada de upscaling, focando em consertar somente o rosto om um Node de Face Detailer, feito especificamente pra consertar e melhorar rostos. E aqui entramos em território de cirurgia plástica e harmonização mesmo kkkk o rosto final vai ser diferente do original. Mas pra NPC e personagens secundários não importa, ninguém vai saber a diferença mesmo, basta não estar deformado, zarolho ou algo assim que salta à vista.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/3d40a8n9b32mmkub5l8c04oou37h" alt="Emotions"  loading="lazy" /></p>
<p>Existem Nodes especializados em expressões, como o Expression Editor (PHM) que parte de uma única foto de rosto e consegue gerar novas fotos nas mais variadas emoções - que podemos configurar exatamente, numericamente, como queremos. Não vou mostrar, mas note que as imagens geradas estão em baixa qualidade, mas o próximo passo do workflow é justamente fazer upscaling delas também.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/cxdua4dfalu6d68tpaleljie5y1e" alt="Lighting"  loading="lazy" /></p>
<p>Esse passo é interessante. Primeiro a parte de cima, com os vários cenários. Eles foram todos gerados via os prompts em verde abaixo deles, prompts que o Mick deixou mas podemos editar como quisermos OU trocar o node de geração e colocar de Load Image pra carregar nossas próprias imagens de fundo, de fotos de verdade.</p>
<p>O objetivo desse passo é gerar os rostos sob diferentes configurações de luz. Muita gente pensa que &ldquo;luz&rdquo; em jogos é só &ldquo;acender a luz vermelha&rdquo; e todo mundo vai ficar vermelho automaticamente. Em jogos novos, com <strong>RAY TRACING</strong> sim, por isso é SUPER PESADO. Mas em jogos feitos pra máquinas antigas, jogos indie, não dá pra exigir isso de todo mundo.</p>
<p>Daí se usam &ldquo;truques&rdquo; pra falsificar coisas como luzes e sombra. É o processo de <strong>BAKING</strong> onde literalmente &ldquo;estampamos a luz na textura&rdquo; dos objetos e personagens. Com a luz global ligada ou desligada, eles sempre vão estar &ldquo;pintados&rdquo; na luz colorida da cena. Pra mudar de cena, carregam novas texturas com outras luzes &ldquo;baked&rdquo;. Pra programadores, pense em baking como <strong>Caching</strong>. Pra que toda vez recalcular tudo dinamicamente, se a luz da cena nunca muda? Economize esse passo e já deixe &ldquo;cacheado&rdquo;.</p>
<p>Voltando, esse passo usa a tecnologia <a href="https://github.com/lllyasviel/IC-Light"target="_blank" rel="noopener"><strong>IC-Light</strong></a> que é outro projeto open source que vale aprender, mesmo se não se interessa por I.A. Ele consegue manipular a luz de qualquer imagem ou foto. Você, como fotógrafo, pode mudar a luz caso tenha mudado de idéia, em pós-produção. Ferramentas da Adobe ou BlackMagic, acho que já incluem tecnologia similar, mas é bom saber que existe open source e dá pra integrar no seu produto.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/qup2n6vadpc7qrtgokbqbfkpvmjg" alt="final sheet"  loading="lazy" /></p>
<p>Depois de gerar os rostos com diferentes luzes, obviamente tem outro passo de upscaling - que estou pulando de mostrar - e vai pro grupo de nodes final que junta tudo num &ldquo;sheet&rdquo;, uma &ldquo;folha do personagem&rdquo;. O desenvolvedor de jogos pode usar direto num jogo 2D (pense um visual novel game da vida), ou pode servir de base pra UV Mapping de texturas de um modelo 3D simples com Armature pra animar e já tem alguns rostos de emoções. Bom pra colocar no cenário de fundo, pedestres andando na rua, fazendo compras, sentados na praça ou algo assim.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/cgv0qp3slipgw4nrlgnrserl1n8s" alt="Loras"  loading="lazy" /></p>
<p>Além disso, o tutorial do Mick descreve como, é possível criar <strong>LORAS</strong> (Low-Rank Adaptation). Se quiser conseguir gerar personagens com estilo ou mesmo rostos específicos (sem intervenção &ldquo;artística&rdquo; da I.A.), você escolhe um modelo como FLUX ou SDXL e &ldquo;em cima&rdquo; dele adiciona um segundo sub-modelo compatível com informações sobre essa pessoa ou personagem.</p>
<p>Pra isso você tira várias fotos limpas e bem iluminadas da pessoas, nos mais diferentes ângulos, nem precisa de muito, só uma dúzia é suficiente. Pra cada imagem cria prompts que descrevam bem, e é isso. Tem ferramentas pra gerar esses Loras localmente ou sites que fazem isso (assista o video).</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/tk8tbtrr1ealm4c4eu26alk63xlh" alt="Creating Prompts"  loading="lazy" /></p>
<p>Falando em prompts, em vários workflows existem passos pra descrever prompts detalhados de imagens geradas dinamicamente. Em vez de exigir que o usuário (você) faça isso manualmente, é possível usar um modelo de decoding, que decodifica imagens em prompts de texto. O modelo mais usado pra isso é o <strong>FLORENCE 2</strong> da Microsoft.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/dwr87ajtkj7w15ftsy86l5u4hz44" alt="Florence 2"  loading="lazy" /></p>
<p>Esse box de texto embaixo é read-only, você não precisa digitar manualmente. O Node de Florence 2 Run vai ler a imagem e gerar esse texto. Veja como ele descreveu a primeira imagem da mulher na pose de &ldquo;T&rdquo;. Fazendo testes, pro seu caso, você determina se só isso é suficiente, se não for basta colocar um segundo Node de prompt e concatenar os dois antes de mandar pra outros nodes.</p>
<p>Enfim, tem MUITA coisa pra explorar só nesse workflow. O Mick fez um excelente trabalho tanto no workflow quanto no video pra explicar e vale a pena pagar os 10 dólares pra contribuir. Existem dezenas de workflows assim disponíveis na Web, basta procurar. E meu setup está cada vez mais complexo. Pretendo ficar ajustando ele pra cada novo workflow interessante que esbarrar. Já tem vários pré-testados na pasta &ldquo;workflows&rdquo; do meu projeto pra você brincar.</p>
]]></content:encoded><category>midia-generativa</category><category>games</category><category>modelos-locais</category></item><item><title>[Akitando] #137 - Games em Máquina Virtual com GPU Passthrough | Entendendo QEMU, KVM, Libvirt</title><link>https://akitaonrails.github.io/2023/02/01/akitando-137-games-em-maquina-virtual-com-gpu-passthrough-entendendo-qemu-kvm-libvirt/</link><guid isPermaLink="true">https://akitaonrails.github.io/2023/02/01/akitando-137-games-em-maquina-virtual-com-gpu-passthrough-entendendo-qemu-kvm-libvirt/</guid><pubDate>Wed, 01 Feb 2023 08:00:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/IDnabc3DjYY"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Este episódio levou literalmente MESES pra eu conseguir fazer. Entre atualizar o hardware da minha máquina, testar todo tipo de combinação de configuração, até conseguir rodar jogos da Steam, num Windows virtualizado, a quase mesma velocidade que nativo.&lt;/p&gt;
&lt;p&gt;Hoje vamos entender o que é QEMU, KVM, Libvirt, como passar uma GPU da NVIDIA diretamente pra dentro de uma VM, e como garantir a máxima performance na virtualização, incluindo entender como diversos componentes de hardware e do Linux funcionam.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/IDnabc3DjYY"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Este episódio levou literalmente MESES pra eu conseguir fazer. Entre atualizar o hardware da minha máquina, testar todo tipo de combinação de configuração, até conseguir rodar jogos da Steam, num Windows virtualizado, a quase mesma velocidade que nativo.</p>
<p>Hoje vamos entender o que é QEMU, KVM, Libvirt, como passar uma GPU da NVIDIA diretamente pra dentro de uma VM, e como garantir a máxima performance na virtualização, incluindo entender como diversos componentes de hardware e do Linux funcionam.</p>
<p>Este conteúdo vai ser DENSO, então não deixem de usar os capítulos abaixo pra se orientar e consultar todos os links que deixei listado aqui.</p>
<h2>Capítulos<span class="hx:absolute hx:-mt-20" id="capítulos"></span>
    <a href="#cap%c3%adtulos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>00:00:00 - Intro</li>
<li>00:00:44 - Cap 1: Meu Setup (até 2024, senão podem pular)</li>
<li>00:05:51 - Cap 2: Introdução à Virtualização | Por que não Dual Boot?</li>
<li>00:08:26 - Cap 3: O que é IOMMU | Setup das GPUs</li>
<li>00:13:46 - Cap 4: Redes Virtuais | Minha placa 10 Gigabits</li>
<li>00:17:57 - Cap 5: Criando a Máquina Virtual | Virt-Manager</li>
<li>00:19:51 - Cap 6: Recapitulando UEFI | O que é OVMF?</li>
<li>00:23:06 - Cap 7: Entendendo CPUs | Pinagem de CPUs</li>
<li>00:33:01 - Cap 8: O que é QEMU? E KVM? | Libvirt</li>
<li>00:38:58 - Cap 9: Limitando CPUs do Host | Cgroups</li>
<li>00:43:06 - Cap 10: Configurações de Performance | Features Importantes</li>
<li>00:45:32 - Cap 11: Monitor Virtual e Streaming | SPICE e QXL</li>
<li>00:47:22 - Cap 12: Configurando Áudio | Pulseaudio e Pipewire</li>
<li>00:50:01 - Cap 13: PCI Passthrough | NVIDIA GPU</li>
<li>00:50:27 - Cap 14: Keyboard, Video, and Mouse | KVM via EVDEV</li>
<li>00:52:47 - Cap 15: Instalando Windows em Disco VirtIO | Fedora VirtIO ISO</li>
<li>00:57:15 - Cap 16: Demonstrando Performance com Games | GPU Passthrough</li>
<li>00:57:53 - Cap 17: Anti-Cheat em Elden Ring | Dual Boot</li>
<li>01:00:24 - Cap 18: Lidando com Monitor com 2 Inputs de Video | Escolhendo Inputs</li>
<li>01:03:08 - Cap 19: Lidando com Suspend do Host | Desligando Suspend</li>
<li>01:05:04 - Cap 20: Conclusão | Mais Coisas</li>
<li>01:07:49 - Bloopers</li>
</ul>
<h2>Links<span class="hx:absolute hx:-mt-20" id="links"></span>
    <a href="#links" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li><a href="https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF"target="_blank" rel="noopener">https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF</a></li>
<li><a href="https://wiki.gentoo.org/wiki/GPU_passthrough_with_libvirt_qemu_kvm"target="_blank" rel="noopener">https://wiki.gentoo.org/wiki/GPU_passthrough_with_libvirt_qemu_kvm</a></li>
<li><a href="https://github.com/virtio-win/kvm-guest-drivers-windows"target="_blank" rel="noopener">https://github.com/virtio-win/kvm-guest-drivers-windows</a></li>
<li><a href="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.229-1/"target="_blank" rel="noopener">https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.229-1/</a></li>
<li><a href="https://github.com/rockowitz/ddcui"target="_blank" rel="noopener">https://github.com/rockowitz/ddcui</a></li>
<li><a href="https://github.com/rockowitz/ddcutil/issues/35"target="_blank" rel="noopener">https://github.com/rockowitz/ddcutil/issues/35</a></li>
<li><a href="http://www.ddcutil.com/commands/"target="_blank" rel="noopener">http://www.ddcutil.com/commands/</a></li>
<li><a href="https://github.com/olavmrk/usb-libvirt-hotplug"target="_blank" rel="noopener">https://github.com/olavmrk/usb-libvirt-hotplug</a></li>
<li><a href="https://getlabsdone.com/how-to-install-windows-11-on-kvm/#Add-the-windows-11-virtio-driver"target="_blank" rel="noopener">https://getlabsdone.com/how-to-install-windows-11-on-kvm/#Add-the-windows-11-virtio-driver</a></li>
<li><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/virtualization_administration_guide/sect-virtualization-adding_storage_devices_to_guests-adding_hard_drives_and_other_block_devices_to_a_guest"target="_blank" rel="noopener">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/virtualization_administration_guide/sect-virtualization-adding_storage_devices_to_guests-adding_hard_drives_and_other_block_devices_to_a_guest</a></li>
<li><a href="https://linuxhint.com/install_virtio_drivers_kvm_qemu_windows_vm/"target="_blank" rel="noopener">https://linuxhint.com/install_virtio_drivers_kvm_qemu_windows_vm/</a></li>
<li><a href="https://www.tecmint.com/manage-kvm-storage-volumes-and-pools/"target="_blank" rel="noopener">https://www.tecmint.com/manage-kvm-storage-volumes-and-pools/</a></li>
<li><a href="https://passthroughpo.st/simple-per-vm-libvirt-hooks-with-the-vfio-tools-hook-helper/"target="_blank" rel="noopener">https://passthroughpo.st/simple-per-vm-libvirt-hooks-with-the-vfio-tools-hook-helper/</a></li>
<li><a href="https://www.libvirt.org/hooks.html"target="_blank" rel="noopener">https://www.libvirt.org/hooks.html</a></li>
<li><a href="https://archlinux.org/packages/extra/x86_64/qemu-emulators-full/"target="_blank" rel="noopener">https://archlinux.org/packages/extra/x86_64/qemu-emulators-full/</a></li>
<li><a href="https://unix.stackexchange.com/questions/30106/move-qcow2-image-to-physical-hard-drive"target="_blank" rel="noopener">https://unix.stackexchange.com/questions/30106/move-qcow2-image-to-physical-hard-drive</a></li>
<li><a href="https://libguestfs.org/virt-resize.1.html"target="_blank" rel="noopener">https://libguestfs.org/virt-resize.1.html</a></li>
<li><a href="https://www.cyberithub.com/resize-qcow3-image-with-virt-resize-kvm-tools/"target="_blank" rel="noopener">https://www.cyberithub.com/resize-qcow3-image-with-virt-resize-kvm-tools/</a></li>
<li><a href="https://loc-clan.com/files/win10"target="_blank" rel="noopener">https://loc-clan.com/files/win10</a></li>
<li><a href="https://www.reddit.com/r/VFIO/comments/l8g6iy/pc_suspends_itself_while_in_vm_due_to_suspend/"target="_blank" rel="noopener">https://www.reddit.com/r/VFIO/comments/l8g6iy/pc_suspends_itself_while_in_vm_due_to_suspend/</a></li>
<li><a href="https://www.linaro.org/blog/the-evolution-of-the-qemu-translator/"target="_blank" rel="noopener">https://www.linaro.org/blog/the-evolution-of-the-qemu-translator/</a></li>
<li><a href="https://github.com/foxlet/macOS-Simple-KVM"target="_blank" rel="noopener">https://github.com/foxlet/macOS-Simple-KVM</a></li>
<li><a href="https://github.com/foxlet/macOS-Simple-KVM"target="_blank" rel="noopener">https://github.com/foxlet/macOS-Simple-KVM</a></li>
<li><a href="https://passthroughpo.st/explaining-csm-efifboff-setting-boot-gpu-manually/"target="_blank" rel="noopener">https://passthroughpo.st/explaining-csm-efifboff-setting-boot-gpu-manually/</a></li>
<li><a href="https://passthroughpo.st/explaining-csm-efifboff-setting-boot-gpu-manually/"target="_blank" rel="noopener">https://passthroughpo.st/explaining-csm-efifboff-setting-boot-gpu-manually/</a></li>
<li><a href="https://github.com/vanities/GPU-Passthrough-Arch-Linux-to-Windows10"target="_blank" rel="noopener">https://github.com/vanities/GPU-Passthrough-Arch-Linux-to-Windows10</a></li>
<li><a href="https://github.com/rockowitz/ddcutil/issues/35#issuecomment-337919874"target="_blank" rel="noopener">https://github.com/rockowitz/ddcutil/issues/35#issuecomment-337919874</a></li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Video de hoje vai ser mais pra mim do que pra vocês. Quem me acompanha no Insta sabe o que eu ando mexendo e alguns meses atrás viram que eu estava brincando com upgrade no meu PC, NAS e, principalmente, PCI passthrough da GPU pra máquinas virtuais. Quero mostrar como ficou, como estou usando, mais ou menos os principais conceitos envolvidos. Embora não seja um passo a passo, vou explicar coisas que normalmente não se vê numa instalação normal de Linux e detalhes sobre como um PC funciona. Mais importante, vou explicar todos os componentes pra rodar máquinas virtuais em Linux e como elas funcionam. Se queria aprender mais sobre virtualização, hoje é o dia.</p>
<p>(&hellip;)</p>
<p>Eu já fiz dois videos falando do meu setup anterior então assistam depois. Mas agora estou com um PC bem potente, com CPU AMD Ryzen 9 5950X de 16 núcleos ou cores e 32 threads, 2 pentes de memória DDR4 de 4 Ghz funcionando com perfil XMP, ou seja, com overclock, da G.Skill, placa mãe Aorus X570S. Não é a melhor placa mas dá conta do recado. Ela tem 2 slots M.2 pra NVME que é SSD muito mais rápido, um Samsung 970 Evo Plus de 2TB onde tá instalado Windows 11 nativamente como dual boot e outro NVME primário Samsung também de 1 TB onde está meu Manjaro GNOME.</p>
<p>Além deles preenchi 3 slots SATA com SSDs normais Samsung modelos 860 e 870 de 1 TB que uso só pra cache do DaVinci Resolve, outro de 4TB que era meu antigo drive pra jogos da Steam e que recentemente encheu então comprei um de 8TB pra mover tudo pra lá. Vou fazer esse de 4TB ser meu novo cache pro DaVinci por enquanto. Óbvio que não precisa de tudo isso só pra cache, mas não tenho outro uso pra ele por enquanto, então beleza.</p>
<p>O Linux boota usando a GPU primária da AMD, um modelo fraquinho que é o RX 6400. Essa placa não é muito melhor que uma antiga NVIDIA GTX 1050 de 2016. Mas é mais do que suficiente pra coisas como tocar video 4K sem perder frames, renderizar aplicativos de produtividade como terminal ou editor de texto. Só pra programar e navegar na Web é muito mais do que suficiente. Mas obviamente é  imprestável pra games mais pesados que um CS:Go. </p>
<p>Pra renderização pesada de video quando edito os episódio do canal com DaVinci Resolve, ou pra brincar de modelagem 3D com Blender ou pra jogos pesados como God of War da vida, aí tenho uma GPU secundária que fica desligada no Linux. A NVIDIA RTX 3090 com 24 Gigabytes só de memória de video. Esse sim é um monstro. </p>
<p>Recentemente saiu a RTX 4090 que tem quase o dobro da performance da minha, mas também custa o dobro do preço, usa muito mais energia e ocupa quase o dobro do espaço dentro do gabinete, e pra funcionar decentemente o certo seria trocar minha placa mãe pra uma que suporte memória DDR5 e trocar minha CPU da série 5000 pra nova série 7000 que também acabou de sair pra não ter gargalo. Na prática o custo-benefício ainda não compensa. Vou fazer esse upgrade só daqui mais uns 2 anos.</p>
<p>Falando em resolução, eu uso setup de dois monitores, a principal é a Asus ROG TUF de 31&quot;, resolução de 2160 por 1440 pixels, ou seja, 2K a 144 hz. O topo de linha pra gamer seria um monitor de micro LEDs 4K de 300 hz HDR+, mas pro meu uso tá mais que bom. Eu não participo de esports então mais que 1440p e 144hz eu nem ia perceber tanta diferença e só ia pesar mais na GPU. Nessa configuração consigo jogar qualquer jogo pesado da Steam em Ultra High com Ray Tracing e ainda ter mais de 100 frames por segundo.</p>
<p>Meu monitor secundário é um Samsung de 29&quot; 4K e 60hz. Esse eu exagerei um pouco. É o monitor que uso na vertical pra deixar coisas como meu Discord, Gmail, gráficos da bolsa e coisas assim pra ficar dando uma olhada. Poderia ser um monitor de 24&quot; e não precisava ser 4K porque uso em 1440p pra ficar igual ao principal. Enfim, o resto não é importante pro video de hoje mas só pra ficar completo, tenho um microfone BM 800 e uma webcam Logitech Brio de 1080p de resolução. Não sou, nem quero ser podcaster nem streamer. Pra calls de Zoom tá mais que bom.</p>
<p>Pra áudio, em vez de usar o que vem na placa mãe liguei um DAC externo da Topping via USB. DAC é um conversor digital pra analógico. Ele recebe o áudio digital via USB e converte em onda pra mandar pra um pre-amp, que pega esse áudio analógico convertido com sinal baixo e amplifica pra nível de linha pra mandar pras caixas de som ou fone de ouvido. As caixas de som não nem nada de especial, são 2 Edifier. Pra usar na mesa perto de mim é o suficiente. Já o fone que uso é um Sennhaiser HD 650 que é um modelo de entrada pra quem quer um som de referência, não modificado.</p>
<p>Meu mouse é um Logitech MX Master 3 sem fio, o melhor mouse de produtividade que existe. Super confortável e excelente pra trabalhar em edição de video por exemplo. Ele não é feito pra jogar, embora nada impeça. Um mouse gamer tem metade do peso desse Logitech Mas como falei, não participo de esports e também não jogo FPS. Não curto Valorant, Apex Legends, Overwatch nem nada disso. Só jogo single player e com gamepad. E gamepad os meus preferidos são o de Xbox One X, depois o modelo SN30 pro+ da 8BitDo que compartilho com meu notebook, e o de PS4 pra emuladores como Dolphin ou CEMU pra jogos da Nintendo porque gamepad de PS4 tem acelerômetro e giroscópio, coisa que do Xbox não tem.</p>
<p>Todo mundo que acompanha o canal sabe que sou um sommelier de teclados e meu favorito até hoje é o Moonlander da ZSA. Dá bastante trabalho pra treinar e se acostumar, mas depois que aprendi realmente a usar um teclado split, separado no meio, com layout ortolinear, não consigo mais voltar pra um teclado normal. Eu sofro um pouco quando preciso usar do notebook. Quem não sabe o que é isso, assista meu terceiro video sobre teclados, que explico em detalhes.</p>
<p>O objetivo hoje é eu conseguir instalar uma máquina virtual Windows em cima do meu Manjaro e passar a GPU da NVIDIA inteiramente pra ele. Meu Manjaro continua funcionando normalmente via a GPU da AMD, e na máquina virtual a RTX 3090 vai ficar exclusiva só pro Windows virtualizado. Muitos podem se perguntar &ldquo;ué, mas não é mais fácil só fazer um dual boot?&rdquo; E sim, é mais fácil mesmo. Mas vejam esta tela do programa Virt Manager que eu instalei. </p>
<p>Tudo isso são máquinas virtuais. Eu tenho uma instalação de Garuda que é outra versão de Arch Linux mais voltado pra gamers. Eu tenho um Ubuntu que uso pra testes e eu tenho 4 instalações de Windows 11. Uma que está como dual boot, instalado numa NVME e outras 3 que rodam num disco virtual em rede. Eis porque eu não queria só depender de dual boot: queria poder instalar outros Windows pra tarefas ou testes diferentes em separado, sem ter que reparticionar meu SSD toda hora e ficar reconfigurando dual boot. Do jeito que fiz, posso instalar um novo OS virtualizado a qualquer momento, ou destruir também, sem afetar a estabilidade do meu sistema.</p>
<p>Veja que tenho um MacOS também. Infelizmente é lento porque Apple parou de dar suporte pra GPU da NVIDIA faz alguns anos. Só GPUs antigas da NVIDIA funcionariam, como a GTX série 1000 de mais de 5 anos atrás, e só até o MacOS Mojave de 2021. Simplesmente não existem drivers pra usar a RTX 3090 num Mac. Pra conseguir acelerar esse MacOS virtualizado precisaria passar a GPU da AMD, mas como é minha principal, que o host Manjaro usa, ia ficar complicado então por enquanto não vai rolar Mac.</p>
<p>Falando em suporte de hardware e abrindo a página de PCI passthrough do ArchWiki, a primeira coisa que ele vai explicar é que precisa checar se o meu hardware suporta o que precisa. A primeira coisa é mais óbvia, minha CPU precisa suportar instruções de virtualização o VT-x ou VT-d. Tem que entrar na BIOS e checar se tá ativado. Muitas vezes vem desligado. Hoje em dia toda CPU suporta sem problemas, mas CPUs de uns 5 anos ou mais pra trás, é bom checar. No Wiki também fala sobre modelos de placa mãe. Mas de novo, só se preocupa com isso se seu hardware for muito velho.</p>
<p>Os passos 1, 2 e 3 do Wiki podem ser automatizados por essa ferramenta <code>gpu-passthrough-manager</code>, instala com <code>yay</code> ou <code>pacaur</code> ou seja lá qual gerenciador de AUR você usa. Eu gosto do <code>yay</code>. Ele vai fazer duas coisas importantes: configurar a linha de comando que carrega a kernel no boot pra habilitar IOMMU e depois que rebootar, vai separar a GPU da NVIDIA pra não carregar mais os drivers no boot, já que precisa estar desligado pra passar pra máquina virtual. Vamos entender.</p>
<p>IOMMU, ou Input Output Memory Management Unit é um recurso que ligamos na kernel e que a CPU por baixo precisa suportar. A grosso modo é assim, a CPU e dispositivos como teclado ou placa de video, normalmente se comunicam via endereços de memória direta entre um e outro. O problema é que se a CPU de verdade já está falando com o dispositivo, não teria como outra CPU virtual compartilhar os mesmos dispositivos. </p>
<p>Em vez disso o controlador de IOMMU cria endereços virtuais que mapeiam pros reais e esses endereços virtuais podem ser passados pra máquinas virtuais, dando acesso direto aos dispositivos sem ter que passar pela CPU host pra intermediar essa comunicação. Isso é crucial pra máquina virtual conseguir falar diretamente com a GPU ou com outros dispositivos, por exemplo se colocar uma segunda placa de rede de verdade no PC, poderia passar inteira pra máquina virtual.</p>
<p>O Wiki explica como ligar isso, mas depois pede pra criar um script com esse código aqui e executar. O resultado vai ser algo parecido com isso aqui. Esses são os diversos grupos de IOMMU que meu sistema organiza. O que me importa é este Grupo 30 que tem só dois dispositivos, a RTX 3090 e um controlador de áudio também da NVIDIA. E o importante é que não tem mais nenhum outro dispositivo compartilhando o mesmo grupo. Se tivesse, na hora de passar a NVIDIA pra máquina virtual precisaria passar o outro dispositivo nada a ver junto, e dependendo do que fosse, poderia ter problemas. O ideal é estar assim: o que eu quero passar, isolado num grupo separado. Significa que passamos pelos pré-requisitos, meu hardware suporta o que quero fazer.</p>
<p>Até esse ponto, se fizer uma instalação normal de Manjaro, o identificador de hardware acha tanto minha AMD RX 6400 quanto a RTX 3090 e carrega os drivers dos dois. Mas pra poder passar pra máquina virtual, preciso que no boot, o driver da NVIDIA não seja carregado. Pra isso vamos usar um truque: carregar um driver dummy, de mentira, que vai se pendurar e bloquear a GPU. Pra isso usamos um driver VFIO que é um módulo que vem na kernel do Linux. Aquela ferramenta que falei antes, o <code>gpu-passthrough-manager</code> vai fazer isso pra gente, só selecionar os dois dispositivos da NVIDIA e deixar ele fazer o trabalho. Na Wiki tem o jeito manual também, mas vou pular.</p>
<p>Agora chegou a hora de instalar e configurar o software de virtualização propriamente dito. Precisamos dos pacotes <code>qemu-desktop</code>, <code>libvirt</code>, <code>edk2-ovmf</code> e o <code>virt-manager</code>. Pra rede precisa do pacote <code>dnsmasq</code>. Quando instalar tudo, só habilitar o libvirt pro SystemD carregar no boot com <code>sudo systemctl enable libvirtd</code> e já dar start nele também. Pronto, do ponto de vista de preparo e instalação já tá tudo pronto. Agora é a parte divertida, configurar a máquina virtual propriamente dita.</p>
<p>Uma máquina virtual vai se conectar com os mesmos dispositivos que seu Linux Host, o que boota nativamente de verdade, no caso o meu Manjaro. Coisas como os NVME  posso deixar outra máquina usar, se e somente se, não estiverem montadas. Lembra a diferença? Uma coisa é um dispositivo como <code>/dev/nvme1n1</code> outra coisa é o ponto de montagem <code>/mnt/blabla</code> que aponta pra uma partição no device. Se ficou confuso é porque você pulou meus videos de Linux onde explico isso. Se não sabe como Linux boota e como funciona por baixo, não vai entender nada deste video também. </p>
<p>Enfim, o ponto é que é possível passar dispositivos de armazenamento entre meu host e o guest contanto que só um deles tenha pontos de montagem. Aliás, pra facilitar, vou dizer host sempre que me referir ao meu Manjaro principal, e guest ou convidado é a máquina virtual. Continuando, dispositivos USB como teclado, mouse, hubs e tudo mais suportam hot swap. Isso deve ser intuitivo, podemos desconectar e reconectar que o OS reinicializa a quente, sem precisar rebootar. Quando ligamos um dispositivo USB no guest, é como se estivéssemos tirando o cabo do host e ligando no guest.</p>
<p>Placa de video só dá pra passar via grupo de IOMMU e se estiver descarregado, ou seja, com o driver stub de VFIO bloqueando. O driver VFIO é como se fosse um plugue esperando a tomada da máquina virtual ligar nele, saca? Só aí que a placa mãe vai ser ativada. Os monitores, por sua vez, via cabo HDMI ou DisplayPort estão conectados fisicamente nas placas de video e não na placa mãe, então quem controla os monitores são as placas de video. </p>
<p>Cada monitor suporta ligar vários cabos de entrada neles. Normalmente só ligamos um, mas já devem ter visto este menu que permite selecionar input sources diferentes, as diferentes portas na parte de trás. É assim que dá pra compartilhar um monitor com mais de um computador e ficar alternando os sinais de entrada. Meu monitor secundário vertical, o Samsung, tá ligado na placa da AMD. Meu monitor principal, o Asus, também tá ligado no AMD, então no boot o Wayland vê os dois e configura setup de extensão do meu desktop. </p>
<p>Antes que alguém pergunte, pra ter papel de parede que enche os dois monitores desse jeito uso um programa chamado HydraPaper. Ele funciona via esse programa gráfico mas também dá pra chamar via linha de comando, daí não é difícil fazer um script pra colocar no cron e assim mudar o papel de parede de tanto em tanto tempo. Fica de exercício pra vocês. Voltando, esse monitor Asus também tem outro cabo HDMI ligado nele, que se conecta com a placa de video da NVIDIA, que neste momento permanece desligado. Já já vamos acordar ele.</p>
<p>Mas não é só com placa de video que preciso me preocupar. Esqueci de mencionar, mas minha placa mãe X570S vem com uma placa de rede embutida de 2.5 Gigabits por segundo, que é excelente já que a maioria dos PCs e notebooks no máximo vem com placa de 1 Gigabit. E lembrando que 1 Gigabit é mais que suficiente pra maioria das pessoas porque a conexão de internet de provedores ainda é faixa de 100 megabits, ou seja, 1 Gigabit é 10 vezes mais banda do que precisa pra uma pessoa assistindo YouTube. Mas pra editar video via rede é pouco. Eu explico sobre isso nos videos da mini-série de redes vejam lá depois.</p>
<p>Eu queria poder guardar os videos que gravo pro canal, que são em 4K formato DNxHR, que é pouco comprimido pra manter qualidade, no NAS e apontar o DaVinci Resolve direto pra uma pasta de rede aberto nesse NAS. Assim não preciso ficar copiando os arquivos pro meu PC e depois copiando de volta pro NAS. Pra isso a velocidade entre os dois precisa ser alta. Por isso resolvi comprar um switch e uma placa de video PCI Express de 10 Gigabits, que é 1000 vezes mais rápido que seu plano de internet de 100 megabits.</p>
<p>Eu não vou passar essa placa diretamente pra máquina virtual porque uso ela no host também. Como quero compartilhar a mesma placa entre duas máquinas, preciso tipo criar uma placa de rede virtual, como o dispositivo TAP que expliquei no episódio de VPN e uma rede entre a placa virtual ou a placa real, aí tenho algumas opções. Vamos abrir o aplicativo Virt-Manager, que é uma interface gráfica que facilita configurar as coisas. Essa interface é opcional porque tudo que vou mostrar graficamente pode ser feito via linha de comando usando o comando virsh. Por exemplo, no meu terminal posso digitar <code>sudo virth net-list --all</code> e mostra as duas redes virtuais que já tinha configurado na minha máquina: default e network.</p>
<p>Voltando pro Virt-Manager, posso abrir no menu &ldquo;Edit&rdquo; e &ldquo;Connection Detail&rdquo; e olha só as mesmas duas redes aparecendo. Clicando em &ldquo;+&rdquo;  posso criar uma nova rede virtual, mas não preciso porque já tenho essa daqui que chamei de &ldquo;network&rdquo;, podia ser um nome mais criativo. Mas o importante é o nome do dispositivo virtual, a placa de rede de mentira, que dei o nome de &ldquo;virbr1&rdquo; porque na rede &ldquo;default&rdquo; já tinha &ldquo;virbr0&rdquo;. Configurei pra ser uma rede usando NAT pra sair pela minha placa real cujo nome é &ldquo;enp4s0&rdquo;. E como sei esse nome?</p>
<p>Lembram dos videos de rede? No terminal posso usar o comando &ldquo;ip&rdquo; pra mexer na rede. Se fizer <code>ip link show</code> mostra todos os dispositivos de rede. Lembram que falei que minha placa mãe já vinha com rede embutida de 2.5 Gigabits, esse é o dispositivo &ldquo;enp8s0&rdquo; que aparece logo embaixo do loopback. Estou escondendo o MAC Address deles, claro. Em seguida temos o &ldquo;enp4s0&rdquo; que falei que é a placa externa de 10 Gigabits. Em seguida temos dispositivos virtuais, &ldquo;virbr0&rdquo; e &ldquo;virbr1&rdquo;. No fim tem um &ldquo;wl&rdquo; alguma coisa que é o Wi-Fi que não uso, mas também veio embutido.</p>
<p>Do ponto de vista do sistema operacional, tanto &ldquo;enp4s0&rdquo; quanto esse &ldquo;virbr0&rdquo; são placas de rede. Posso criar quantos dispositivos virtuais quiser. Posso criar um separado pra cada máquina virtual ou conectar várias máquinas na mesma placa. E cada placa pode usar diversas estratégias pra se conectar na rede. Vamos entender essa opção &ldquo;mode&rdquo;. Olha só, isolated é fácil, impede a placa virtual de se conectar na rede e na internet. Só vai conseguir enxergar outras máquinas virtuais, mas como o nome diz, ficam isoladas do resto do mundo.</p>
<p>Todas as outras permitem acessar tanto a rede interna quanto a internet. Se escolher Bridge, vai se comportar como se fosse uma nova máquina de verdade conectada na rede. Vai procurar e encontrar o DHCP do modem da Vivo, igual meu PC de verdade faz no boot, pegar um IP e navegar normalmente. Se escolher NAT, como eu fiz, ele pega um IP privado atrás do meu PC de verdade e usa NAT pra falar na rede e acessar a internet. </p>
<p>Routed nunca precisei usar então não sei os detalhes e Open acho que é se quisesse que a máquina virtual ficasse exposta diretamente na internet pública, que não é nosso caso. Então na prática ou escolho Bridge ou NAT. Tecnicamente, Bridge deveria ser mais performático, já que não precisaria passar por um NAT intermediário. Mas não lembro se tive problemas ou se não senti nenhuma diferença, mas vale testar entre os dois.</p>
<p>Pronto. Rede tá ok. Agora podemos começar o processo de criar a máquina virtual. É com esse ícone de &ldquo;mais&rdquo; no topo. Escolho a primeira opção pra procurar a ISO de instalação do Windows. Ele detecta corretamente. Caso fosse uma distro de Linux que não detectasse,  precisaria escolher manualmente o mais próximo, mas pra agora vamos pro próximo passo. </p>
<p>Agora posso escolher quanto de RAM e quantas threads da minha CPU quero dar pra máquina virtual. Não vou mexer aqui porque isso vou mudar mais pra frente, então vamos pro próximo passo. E agora é a parte pra criarmos um HD virtual ou apontarmos pra um SSD de verdade na máquina. Vou só criar um HD virtual. </p>
<p>Nos meus videos, como de WSL, mostrei como faz pra criar um HD virtual formato de VMWare ou Hyper-V que é o formato VHD ou VHDX, literalmente Virtual HD. Mas o QEMU gosta de usar outro formato, o QCOW2 que significa QEMU Copy-On-Write versão 2.</p>
<p>COW permite que esse HD virtual seja usado simultaneamente por duas ou mais máquinas virtuais diferentes, cada uma vai continuar criando blocos novos tipo num snapshot diferente. Isso também significa que esse HD virtual suporta snapshots, suporta voltar pra versões anterioes, mesmo se dentro não estivermos usando BTRFS. O formato QCOW2 acho que é mais avançado que um VHD. Além de snapshots também suporta compressão e encriptação.</p>
<p>Posso escolher deixar gravar no diretório padrão, mas prefiro criar num diretório que separei só pra isso no meu NAS. Então escolho &ldquo;Manage&rdquo; e nessa janela escolho um pool, que é um diretório e mando criar um novo volume, dou um nome qualquer, formato qcow2 e uns 100 gigabytes. Tanto faz o tamanho porque esse arquivo é dinâmico, na realidade só vai realmente gastar o que precisar, então no começo não ocupa espaço nenhum. Ele não precisa já pré-reservar o espaço todo. E agora no último passo mando deixar customizar mais antes de fazer o primeiro boot.</p>
<p>Esta é a tela mais detalhada que mostra tudo que vai ter nesta nova máquina virtual. Vamos um a um nos itens que importam. Logo no Overview tem uma mudança importante. Precisamos garantir que estamos com o Chipset Q35 em vez do antigo legado i440FX e que o Firmware seja UEFI mas a versão OVMF com secboot, que é secure boot. Fodeu, um monte de letrinhas né? Vou explicar. Chipset, como o nome diz, é o conjunto de chips na placa mãe que controla memória, processador, I/O e tudo mais. Queremos os chips mais novos.</p>
<p>UEFI já expliquei nos videos de armazenamento. Muita gente ainda chama de BIOS, mas UEFI é a evolução da BIOS. Dentre outras coisas,  é quem dá suporte a HDs com partições GPT, que permite partições de tamanho superior a 2 terabytes e um número enorme de partições. Toda UEFI moderna nem precisa de um bootloader como Grub. Se a partição tiver uma pasta EFI, vai conseguir bootar direto. Na minha placa-mãe, por exemplo, é só apertar F12 no boot que me dá um menu pra escolher de qual partição quero bootar, o que facilita fazer dual boot.</p>
<p>OVMF significa Open Virtual Machine Firmware. É um firmware, o UEFI propriamente dito, ou seja o software que boota primeiro logo que liga o computador e é responsável por checar e inicializar todos os dispositivos do sistema, achar o bootloader da kernel do sistema operacional em alguma partição GPT e passar o controle pra continuar o boot. Numa placa mãe de verdade esse firmware costuma ser mais complexo porque tem uma interface gráfica. Meu Aorus por exemplo, se apertar a tecla Delete no boot, abre essa tela gráfica fancy aqui. O OVMF tem telas em modo texto bem mais simples e com bem menos opções, porque é pra máquinas virtuais.</p>
<p>Escolhi a versão com Secure Boot porque Windows 11 passa a exigir a existência de um chip de segurança TMP e o firmware precisa ter suporte pra conseguir falar com esse chip. Pronto, podemos confirmar e agora precisamos adicionar uma versão virtual desse chip. Só adicionar novo hardware, escolher TPM, que vai ser emulado, mas selecionar as opções avançadas pra ser modo TIS e versão 2.0 que é o que o Windows 11 não vai reclamar. </p>
<p>Um secure enclave como esse TPM, no mundo real, é um chip separado da CPU que vai conter coisas como chaves privadas que jamais vai dar pra ler diretamente, incluindo outras credenciais como certificados digitais. Também vai ter gravado a configuração da sua máquina que a firmware vai informar pra ele, assim nos próximos boots dá pra detectar se alguém modificou o hardware, que é o que normalmente se reclama com Secure Boot. </p>
<p>Muitos gamers odeiam Secure Boot e TPM não porque eles são ruins, mas porque software de Anti-cheat, de detecção de trapaças que muitos jogos instalam justamente fazem modificações muito semelhantes ao que um vírus, malware ou rootkit faria na kernel do sistema. O problema é a existência de anti-cheats mau feitos. </p>
<p>Enfim, isso é assunto pra outro dia. O importante é que temos como adicionar um TPM virtual pro Windows achar a aceitar. Mas já aproveito pra avisar que o anti-cheat de alguns jogos, como o Easy usado no Elden Ring, conseguem detectar que está rodando em máquina virtual e não permite entrar online, só dá pra jogar offline. Pra mim isso não é problema, mas pra alguns pode ser.</p>
<p>Agora chegou a hora de configurar a CPU. Problema que essa interface gráfica não permite modificar tudo que preciso. O que vou fazer é abrir a configuração de outra máquina que já tenho, copiar o XML do trecho de CPU e colar nessa nova máquina. Olha só, por padrão tenho uma linha pra quantas vcpus, depois o OS que é o firmware que acabamos de configurar, daí temos features da CPU e modo da CPU. Tudo isso precisamos mexer. Abrindo outra máquina que já tenho, começo copiando essas configurações de vcpu e cputune. </p>
<p>VCPU é simples: quantas threads vou dar pra máquina virtual. Como  tenho uma Ryzen 5950X, posso dar bastante. Decidi dar metade, ou seja, 16 threads pra máquina virtual. O que é essa configuração longa que colei aqui? Eu dei 16 threads, e se não colocar esse bloco de &ldquo;cputune&rdquo;, essas threads vão ser controladas pelo scheduler de threads do Linux Host por baixo. É ineficiente porque no Windows ou outro OS guest do lado de dentro já tem um scheduler e por baixo vai ter outro scheduler e no final as 16 threads vão ficar embaralhadas entre as 32 totais, podendo mudar dependendo se o Host tiver alguma carga pra processar. </p>
<p>Essa configuração depende do uso. No meu caso, se estou com um guest aberto, normalmente não estou fazendo nada pesado no host. 16 threads pra cada dá e sobra na real. Mas essa pinagem de vcpu pra thread real não é aleatório. De onde vem esses números? Pra isso preciso saber a topologia de núcleos e caches deste processador em particular.</p>
<p>Vamos lá, quando falamos CPU, estamos falando deste quadradinho aqui. Seja da Intel ou da AMD, é o processador central. Porém, quando o sistema operacional fala em &ldquo;CPU&rdquo; está se referindo a um único núcleo ou a uma única thread. Vocês já devem ter visto que a CPU do seu PC ou notebook pode ter 4 núcleos e 8 threads. Isso porque a maioria das CPUs modernas suporta um troço chamado HyperThreading, onde cada núcleo é compartilhado por até 2 threads. As duas ao mesmo tempo não conseguem funcionar em capacidade máxima, claro. </p>
<p>Só uma única thread consegue saturar um núcleo. Mas no dia a dia, raramente você está saturando tudo, então 2 threads conseguem compartilhar os recursos de um núcleo e simular 2 processamentos paralelos. Enfim, quando ver em Linux falar em CPU pense que é a thread. Meu Ryzen 9 tem 16 núcleos e 32 threads ou 32 CPUs. Isso porque bem antigamente, de fato uma CPU era só um núcleo. Só dos anos 2000 pra cá que começamos a explorar múltiplos núcleos no mesmo die, ou processador, que é o quadradinho na minha mão.</p>
<p>Aproveitando, num terminal todo mundo sabe que se digitar <code>ls</code> vai listar os arquivos no diretório, certo? Mas sabiam que existem vários programas <code>ls</code> -alguma coisa? Faz o teste, abre um terminal, digita <code>ls</code> e dá &ldquo;tab&rdquo;. Olha no meu, vários comandos diferentes. Nos videos de Linux já mostrei o <code>lsblk</code> lembram? Que lista os dispositivos de bloco do sistema, no caso seus HDs ou SSDs. Olha só os meus. E se você usa Snap pra instalar programas vai ter essa poluição de dispositivos de loop aqui, mas pode ignorar isso.</p>
<p>Pra agora nos interessa <code>lscpu</code> com a opção &ldquo;-e&rdquo;. Ele lista todas as threads disponíveis no meu processador, o clock máximo e mínimo que aguenta e o clock atual no final. Não sei se sabiam disso mas hoje em dia os clocks são controlados dinamicamente. Eles aumentam ou diminuem dependendo da carga que mandarmos. Isso é importante pra economizar energia. Se estamos fazendo quase nada, o chip elege deixar as threads em clock mais baixo.</p>
<p>Alguém poderia pensar: &ldquo;boa, quer dizer que quando eu mandar fazer coisas pesadas como renderizar video, vai subir todo mundo pra esse máximo aqui então?&rdquo; E na realidade não. Depende do governador do sistema operacional, depende dos algoritmos e sensores de Precision Boost da AMD ou Turbo Boost da Intel. Eles tentam ser mais inteligentes do que só subir tudo pro máximo ou desligar tudo pro mínimo. </p>
<p>Se eu forçasse todos pra ficar em 5Ghz, não ia aguentar muito tempo, porque todos os núcleos iam consumir mais energia, e esquentar muito mais. E todos atingindo temperaturas altas demais, tipo mais de 90 graus Celsius, o processador vai entrar em modo de proteção e fazer o que se chama de throttling, que é diminuir a energia e diminuir o clock pra conseguir resfriar.</p>
<p>Por isso que parece contra o bom senso, mas muitos fazem undervolting. Que é limitar a energia e evitar de chegar em clocks tão altos. Mas qual a vantagem disso, não fica mais lento? Pensa assim, é melhor todas as threads funcionarem por mais tempo abaixo de 4Ghz do que ir pra 5Ghz, esquentar demais, e daí a CPU forçar todo mundo pra baixo de 2Ghz até esfriar. Entenderam? Devagar e sempre é melhor que pico rápido e cansa rápido. Em notebook que não tem espaço, undervolting é a única solução. Em PC com espaço a solução é colocar um cooler melhor.</p>
<p>Enfim, clocks não importam pra hoje, mas se não conheciam é legal estudar as configurações de Precision Boost ou Turbo Boost que tem na UEFI da sua placa mãe. Placas baratas não permitem mexer muita coisa, mas as placas mais avançadas e mais caras costumam dar mais opções de tensão, corrente, e tudo mais que afetam os clocks. Mas vamos voltar pro <code>lscpu</code>. Pra fazer a tal pinagem de VCPU pra CPU real precisamos saber o número real das CPUs que é a primeira coluna, de 0 até 31. Mas os núcleos ou cores de verdade é a 4a coluna. Veja como cada núcleo tem 2 threads como expliquei agora pouco.</p>
<p>Mas e aí, é só pegar 16 quaisquer, colocar lá naquele XML e já era? Não, pra saber baixamos o pacote hwloc. Execute <code>lstopo</code> no terminal e vai aparecer uma janela gráfica parecida com essa. No lado direito mostra os dispositivos conectados em pistas ou lanes de PCI. São coisas como SSDs. Isso também não interessa, o importante é bloco maior na esquerda. Entenda, pra uma CPU, uma thread, funcionar de forma eficiente, ela precisa ter acesso aos dados que vai processar no momento em que for processar.</p>
<p>Se toda instrução tiver que pausar e esperar procurar na RAM e trazer pra CPU, tudo seria lento, a CPU ia desperdiçar clocks não fazendo nada além de esperar. Isso porque RAM é super lenta comparado com um registrador, que é quase instantâneo. Mesmo minha CPU rodando na média a 3.4Ghz e estar usando DDR4 de 4 Ghz, não é só o clock. O barramento é lento, tem distância física da CPU até os pentes de memória, tudo isso afeta o desempenho. Inclusive é uma das razões de notebooks modernos soldarem RAM na placa mãe: pra diminuir a distância física.</p>
<p>Pra evitar que uma CPU fique com fome de dados e pause, cada uma delas tem um pequeno cache L1, nesse caso de 32 kilobytes e um cache L2 de meio megabyte. Parece pouco, mas é bastante coisa pra uma única CPU e elas ficam literalmente grudados a milimetro de distância só. Se tudo correr bem, esses caches vão ter os dados que as CPUs precisam, na hora que precisam e nada pausa. L1 é a memória mais rápida e mais cara de todas, por isso tem tão pouco. L2 é um pouco menos rápido, e L3 é mais lento que L2. Preste atenção nesse diagrama.</p>
<p>A parte importante é que diferente de L1 e L2 que são exclusivos por CPU, o cache L3 é compartilhado com um grupo de CPUs, no caso temos dois blocos de L3 de 32 megabytes cada, compartilhado entre 8 núcleos cada. Digamos que tem uma thread de C ou Java rodando no núcleo 0. Por alguma razão o scheduler do Linux gostaria de usar o núcleo 0 pra outra coisa e resolve mover a thread que ainda não acabou do núcleo 0 pro núcleo 3. </p>
<p>Como ambas compartilham o mesmo cache L3, se o estado dessa thread, quer dizer, imagine as variáveis dentro da thread, estiverem no L3, basta parar a thread do núcleo 0 e reiniciar no núcleo 3 que vai continuar de onde parou sem problemas. Mas digamos que o scheduler do Linux fosse burro e mandasse pro núcleo 15, o último.</p>
<p>Antes de conseguir iniciar a thread no núcleo 15, ele precisa primeiro copiar o bloco de memória do 1o cache L3 pro segundo cache L3, senão a nova thread não sabe como continuar o trabalho. Sacaram? Um scheduler de threads tem que ser inteligente pra gerenciar esse tipo de coisa. E essa é a dica pra podermos pinar, ou seja, reservar CPUs pra nossa máquina virtual: queremos pegar todas as CPUs embaixo do mesmo cache L3. No meu caso, os núcleos de 0 a 7 ou de 8 a 15. Vamos voltar pro terminal e ver a saída do comando <code>lscpu</code> de novo.</p>
<p>Eu arbitrariamente escolho usar os núcleos de 8 a 15 e nessa listagem significa pegar as threads de 8 a 15 e de 24 a 31. Agora vamos voltar pra configuração XML. Estão vendo aqui os atributos &ldquo;cpuset&rdquo;? São exatamente as threads de 8 a 15 e de 24 a 31. Eu mapeei pras CPUs virtuais ou VCPUs de 0 a 15. Essa configuração vai variar se eu quiser passar menos CPUs, ou se o processador tiver menos núcleos e com outra topologia de caches L3, por isso precisa usar os comandos <code>lscpu</code> e <code>lstopo</code> pra decidir no seu sistema. Cada um vai ser diferente dependendo do modelo de processador.</p>
<p>Essa opção &ldquo;emulatorpin&rdquo; é pra dizer pro controlador da máquina virtual onde rodar as tarefas que permitem a máquina virtual funcionar. Mas até aqui só dissemos pra máquina virtual, quais CPUs usar. Meu host Manjaro ainda enxerga todas as 32 threads e pode querer usar as mesmas que mandei o guest usar. Como fazer pro host só usar os núcleos do primeiro cache L3? De 0 a 7? Vamos de volta pra Wiki.</p>
<p>Tem várias formas diferentes,  poderia permanentemente limitar meu Linux a só usar os núcleos de 0 a 7, mas isso seria um desperdício quando não estiver usando máquina virtual. Em vez disso quero forçar o Manjaro a se limitar só quando iniciar a máquina virtual e pra isso  posso usar o SystemD. Lembra que SystemD faz bem mais que só gerenciar daemons no boot? Aqui ele gerencia os cgroups do sistema. Chegou a hora de explicar mais alguns termos que vocês não conhecem.</p>
<p>Antes de criarmos a máquina virtual falei que precisava instalar os pacotes do virt-manager, que é a interface gráfica pra criar a máquina virtual, mas também instalei qemu e libvirt sem explicar. Tentando ser curto é assim, o emulador propriamente dito é o QEMU que literalmente significa &ldquo;Quick Emulator&rdquo;. Ele quem vai simular a máquina virtual, rodar os programas virtualizados e passar instrução a instrução pra máquina de verdade por baixo. O equivalente VirtualBox ou VMWare ou Hyper-V seria o QEMU.</p>
<p>Na realidade ele faz bem mais que isso. Uma das principais funções é fazer tradução binária dinâmica. Pra quem usa Mac é o equivalente ao Rosetta. E pra quem não usa Mac, o que é Rosetta? 2 anos atrás a Apple saiu fora de usar processadores da Intel, que é padrão x86-64 e passou a usar chips M1 que eles mesmos desenvolveram, derivado de ARM. É meio como pular de um chip que fala português pra outro que fala chinês.</p>
<p>Funciona assim, digamos que eu tenha um programa compilado pra x86. Um trecho desse programa, em assembly poderia ser como esse aqui na tela. Não sei assembly de x86 então pedi pro ChatGPT gerar esse trecho pra mim, de bater o olho parece fazer sentido. Daí pedi pra escrever como seria a tradução que o QEMU faria pra  ARM64 e ele me deu esse outro trecho.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>
; x86-64

mov rax, [rdi] ; Load the value at the address in rdi into rax

mov rbx, [rsi] ; Load the value at the address in rsi into rbx

cmp rax, rbx   ; Compare the values in rax and rbx

jg greater     ; If rax is greater than rbx, jump to the &#34;greater&#34; label

jmp done       ; Jump to the &#34;done&#34; label

  

greater:

  mov [rdi], rbx ; Store the value in rbx at the address in rdi

  jmp done       ; Jump to the &#34;done&#34; label

  

done:

  ret            ; Return from the function</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>
; arm64

ldr x0, [x1] ; Load the value at the address in x1 into x0

ldr x2, [x3] ; Load the value at the address in x3 into x2

cmp x0, x2   ; Compare the values in x0 and x2

b.gt greater ; If x0 is greater than x2, jump to the &#34;greater&#34; label

b done      ; Jump to the &#34;done&#34; label

  

greater:

  str x2, [x1] ; Store the value in x2 at the address in x1

  b done       ; Jump to the &#34;done&#34; label

  

done:

  ret          ; Return from the function</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Estão vendo como os mnemônicos são diferentes? Em Intel existe a instrução <code>mov</code> pra carregar valores, mas em Arm a instrução se chama <code>ldr</code>. Se assistiram meus videos da playlist de Como Computadores Funcionam eu falo mais sobre como Assembly e instruções de baixo nível como esses funcionam, assistam lá depois.</p>
<p>Naquele pacote <code>qemu-desktop</code> que instalamos vem só dois emuladores: o <code>qemu-system-x86_64</code> e o <code>qemu-system-i386</code> que são os emuladores de plataforma Intel de 64 bits e 32 bits. Mas existem outros emuladores pra diversas plataformas como ARM. Pra isso tem que instalar o pacote <code>qemu-emulators-full</code> ou direto tudo com <code>qemu-full</code> e aí ganhamos emuladores como <code>qemu-system-aarch64</code> pra ARM, mas olha a lista: tem os antigos MIPS, Alpha ou até Motorola 68000 mas tem coisa nova como Risc V. Quem tem interesse em programar baixo nível pra Risc V, pode criar máquina virtual com esse emulador. Leiam também a página de Wiki específica de QEMU depois pra aprender tudo.</p>
<p>Traduzir de uma arquitetura pra outra é bem lento mas no caso, pra rodar Windows de Intel em cima de um Linux compilado pra Intel, não tem tradução nenhuma envolvida. Só precisa pegar a instrução da máquina virtual e passar direto pra máquina real embaixo, é bem menos trabalhoso e por isso a performance é quase inteira mantida. Uma CPU virtual funciona uns 15 a 20% mais devagar por conta dessa intermediação do QEMU no meio. Mas sem configurar nada, mesmo de Intel pra Intel, um Windows rodaria lento emulado, e o culpado não é o QEMU.</p>
<p>A culpa são dos dispositivos da máquina: memória, HD, rede, e tudo mais é virtualizado em software, porque a máquina virtual não pode acessar o hardware diretamente, só a kernel do Linux rodando de verdade no metal é que pode. Por isso a AMD e Intel criaram as instruções VT-d, pra permitir passar acesso aos dispositivos reais diretamente, sem precisar gambiarrar com software no meio. Por isso lá no começo o Wiki manda checar se seu sistema suporta VT-d e VT-x.</p>
<p>Tendo essas instruções agora é tarefa da kernel do sistema operacional usar. No Windows isso é responsabilidade do Hyper-V. No MacOS é o &ldquo;Hypervisor.framework&rdquo;. Num BSD Unix o nome é bizarro, se chama &ldquo;bhyve&rdquo;, que significa &ldquo;BSD Hypervisor&rdquo;. Um hypervisor dá acesso às instruções VT-d e VT-x da Intel ou AMD-V da AMD, permitindo criar e gerenciar múltiplas máquinas virtuais rodando em cima deles. No Linux, o módulo responsável por isso se chama KVM, que significa &ldquo;Kernel Virtual Machine&rdquo;.</p>
<p>Eu detesto esse nome porque KVM também significa Keyboard, Video and Mouse e é uma caixinha onde conectamos, teclado, video e mouse, e podemos ligar em vários PCs diferentes, tipo numa lan house ou data center. Daí é só virar uma chavinha pra escolher qual PC queremos controlar. O nome deve ter sido de propósito porque o Kernel Virtual Machine ou KVM de Linux serve pra justamente gerenciar múltiplas máquinas também, só que virtuais.</p>
<p>Só o QEMU sozinho seria lento, pela falta de acesso ao hardware. Mas ele aceita usar aceleradores. E o KVM pode ser usado como acelerador e por isso chamamos a solução de &ldquo;QEMU/KVM&rdquo;. Entendido isso falta só mais um componente, o tal do &ldquo;libvirt&rdquo; que é o daemon que habilitamos no SystemD. KVM não é o único hypervisor que existe no Linux. Um pouco antes dele, existia outro chamado Xen, e tem alternativas comerciais, como o VMWare. </p>
<p>Seria um saco ter que saber os comandos específicos de cada um, e é pra isso que o libvirt serve: ele é o intermediário que fala com hypervisors de Linux. Eu posso controlar qualquer um com o mesmo comando <code>virsh</code> que mencionei antes. A interface gráfica &ldquo;Virt Manager&rdquo; que usei pra criar a máquina virtual de exemplo, por baixo, provavelmente usa esse comando, e eu poderia ter criado a máquina direto do terminal com esse comando também, só fazer <code>virsh create ...</code></p>
<p>O comando virsh é complexo, posso controlar todos os aspectos de um ambiente virtual come ele. Criar redes virtuais, pools de storage, snapshots e mais. Vale a pena estudar depois, mas pra hoje eu preciso de bem pouca coisa dele. Enfim, agora vocês sabem o que é libvirt, KVM e QEMU.</p>
<p>Antes dessa longa tangente eu tinha parado no problema onde já configuramos a máquina virtual pra só falar com as threads de 16 a 31 e agora precisamos obrigar o scheduler do Linux host a só falar com as threads de 0 a 15. Dessa forma cada sistema tem seu grupo de núcleos isolados. Isso é importante porque senão do nada o guest pode começar a engasgar quando o host ficar roubando as threads do guest.</p>
<p>Como falei antes, o libvirt é responsável por falar com o KVM pra fazer coisas como iniciar ou parar uma máquina virtual. Depois que minha máquina estiver configurada direitinho, é só fazer <code>virsh start</code> e o nome da máquina e pra desligar forçado, equivalente a apertar o botão de força de um PC, é só executar <code>virsh destroy</code>.  Felizmente o libvirt tem eventos e hooks, ou ganchos, onde podemos pendurar scripts. </p>
<p>A Wiki nos manda criar o script <code>/etc/libvirt/hooks/qemu</code>. Toda vez que o QEMU iniciar ou parar, o libvirt vai chamar esse script. Se receber o comando <code>started</code> usamos o systemd pra ajustar a propriedade AllowedCPU de 3 cgroups pra permitir usar só as threads de 0 a 15. Dessa forma finalmente garantimos que de 16 a 31 vai mesmo ser só pra máquina virtual. E quando vier o comando &ldquo;release&rdquo;, ajustamos pra voltar a permitir usar todos os núcleos. Agora é só reiniciar o serviço <code>libvirtd</code> e pronto. Isso termina a longa configuração de pinar VCPUs.</p>
<p>Vamos testar pra ver se funciona. Primeiro, sem nenhuma máquina virtual rodando, vou executar o programa GeekBench, que todo canal no YouTube que faz reviews de processador usa, e pular direto pros testes de multi-core. Olha o htop rodando em outro terminal e sim, todas as minhas 31 threads estão sendo trabalhadas. Podemos cancelar e agora abrir uma máquina virtual qualquer que já tenho configurado. Fazendo isso o libvirt vai atirar o evento de started pro hook e executar aqueles comandos de systemd.</p>
<p>Pronto, o guest tá carregado, voltamos pro terminal e executamos o GeekBench de novo. Vou pular pros testes de multi-core como antes. Voltamos pro htop: só as threads de 0 a 15 estão saturados. As threads de 16 a 31 estão sem fazer nada, reservados pro guest poder usar sem ninguém atrapalhando. Sacaram? É assim que garantimos que se eu estiver jogando na máquina guest e o Host decidir processar alguma coisa, não vai sequestrar uma thread minha e causar engasgos no meu jogo. Conseguimos controlar o processador com sucesso!</p>
<p>Mas o que são aqueles system.slice, user.slice e init.scope? São control groups, ou cgroups. Cgroups é um recurso de Linux pra organizar processos em agrupamentos, daí podemos limitar acesso a recursos pro grupo todo. Nesse caso estamos limitando acesso à CPU pra esses 3 grupos e a kernel vai enforçar isso. Aliás, pra quem não sabia, é combinando cgroups com outro recurso da kernel, namespaces, que começa a formar as bases pra containers como Docker. Mas isso fica pra outro episódio.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#!/bin/sh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">command</span><span class="o">=</span><span class="nv">$2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="s2">&#34;</span><span class="nv">$command</span><span class="s2">&#34;</span> <span class="o">=</span> <span class="s2">&#34;started&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    systemctl set-property --runtime -- system.slice <span class="nv">AllowedCPUs</span><span class="o">=</span>0-15
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    systemctl set-property --runtime -- user.slice <span class="nv">AllowedCPUs</span><span class="o">=</span>0-15
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    systemctl set-property --runtime -- init.scope <span class="nv">AllowedCPUs</span><span class="o">=</span>0-15
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">elif</span> <span class="o">[</span> <span class="s2">&#34;</span><span class="nv">$command</span><span class="s2">&#34;</span> <span class="o">=</span> <span class="s2">&#34;release&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    systemctl set-property --runtime -- system.slice <span class="nv">AllowedCPUs</span><span class="o">=</span>0-31
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    systemctl set-property --runtime -- user.slice <span class="nv">AllowedCPUs</span><span class="o">=</span>0-31
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    systemctl set-property --runtime -- init.scope <span class="nv">AllowedCPUs</span><span class="o">=</span>0-31
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">fi</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Mais um detalhe, esse hook vai rodar toda vez que qualquer máquina for iniciada ou parada pelo QEMU. No meu caso sempre pretendo criar máquinas virtuais com exatamente os mesmos núcleos pinados, então pode rodar sempre. Mas se você quiser máquinas com mais ou menos núcleos, precisa de um hook diferente pra cada máquina. E isso é simples. Em vez do script anterior de systemd em <code>/etc/libvirt/hooks/qemu</code> eu colocaria este outro script mais complicadinho:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>
GUEST_NAME=&#34;$1&#34;

HOOK_NAME=&#34;$2&#34;

STATE_NAME=&#34;$3&#34;

MISC=&#34;${@:4}&#34;

  

BASEDIR=&#34;$(dirname $0)&#34;

  

HOOKPATH=&#34;$BASEDIR/qemu.d/$GUEST_NAME/$HOOK_NAME/$STATE_NAME&#34;

  

set -e # If a script exits with an error, we should as well.

  

# check if it&#39;s a non-empty executable file

if [ -f &#34;$HOOKPATH&#34; ] &amp;&amp; [ -s &#34;$HOOKPATH&#34; ] &amp;&amp; [ -x &#34;$HOOKPATH&#34; ]; then

    eval \&#34;$HOOKPATH\&#34; &#34;$@&#34;

elif [ -d &#34;$HOOKPATH&#34; ]; then

    while read file; do

        # check for null string

        if [ ! -z &#34;$file&#34; ]; then

          eval \&#34;$file\&#34; &#34;$@&#34;

        fi

    done &lt;&lt;&lt; &#34;$(find -L &#34;$HOOKPATH&#34; -maxdepth 1 -type f -executable -print;)&#34;

fi</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Não vou explicar linha a linha, é um script de shell. Se você entende de Linux é fácil. Toda vez que o QEMU iniciar uma máquina virtual, esse script vai rodar. Vai pegar o nome da máquina, digamos que seja  <code>win11-video</code> e vai procurar o esse script <code>/etc/libvirt/hooks/qemu.d/win11-video/qemu</code> e lá podemos colocar aquele script anterior de systemd mas agora ajustando exatamente quais CPUs vou permitir pro host pra essa máquina virtual em particular, sacaram?</p>
<p>O perfil de boost da CPU é controlado por uma coisa chamada Governador da Kernel. Sabe nas configurações de energia de qualquer sistema operacional, especialmente em notebooks, que você escolhe Balanceado, Modo de Economia ou Alta Performance? É isso. Normalmente o Linux se configura em perfil Balanceado, mas eu gostaria de forçar pra perfil de performance antes de iniciar meu Windows de games. Pra isso existe o comando <code>cpupower</code>. Só rodar <code>cpupower frequency-set -g performance</code> e pronto. Estude sobre <code>cpupower</code> depois pra descobrir se sua CPU tá em modo balanceado ou economia e você nem sabia. </p>
<p>Voltando pra configuração XML, vou copiar e colar vários blocos. Isso tudo tá explicado na Wiki mas não compensa ir um a um. Em resumo, o bloco de features declara quais funcionalidades essa máquina vai ter, como ACPI que é um padrão pra controlar energia da máquina. Relevante aqui é esse trecho de KVM com estado escondido. Isso é uma tentativa do KVM de tentar esconder do sistema virtualizado que ele está numa máquina virtual. Antigamente GPUs da NVIDIA davam erro se descobriam que estavam sendo virtualizados, mas nos modelos mais novos isso não acontece. Talvez se tentar usar algo mais velho que uma GTX talvez precise, e também desse outro atributo de vendor_id em cima.</p>
<p>Nos blocos de baixo, importante é deixar CPU em modo &ldquo;host-passthrough&rdquo; e checar que a topologia está de acordo com todo o trampo que fizemos no bloco de pinagem antes. Aqui tá certinho, 1 soquete, com 1 processador, 8 núcleos e 2 threads cada, totalizando as 16 threads que pinamos. No meu caso que estou usando AMD Ryzen, precisa dessa feature &ldquo;topoext&rdquo;, senão não dá pra usar hyperthreading. Em Intel não precisa. E pronto, acho que isso resolve a configuração da CPU. O Virt-manager podia já fazer tudo isso automaticamente pra gente, mas até lá precisa saber esses detalhes todos pra tirar o máximo do processador. Por isso precisa ler a Wiki em detalhes.</p>
<p>Continuando, o Virt-manager já adicionou alguns dispositivos que podem ser estranhos como esse Display Spice e Video QXL. QXL significa &ldquo;Qemu eXtended Logical&rdquo; e é uma placa de video virtual. Podemos escolher outros modelos e eu preferi deixar em Virtio que tem essa opção de aceleração 3D. Não espere nenhuma mágica disso ser capaz de rodar games, mas já é alguma coisa. Esse dispositivo é necessário em máquinas onde não temos ou não queremos dedicar placa de video de verdade só pra ela como estou fazendo.</p>
<p>Na real, fiz um teste bem besta. Bootei o Ubuntu virtualizado com Video QXL e testei abrir o firefox e carregar um demo de WebGL. Daí eu desligo, mudo de QXL pra Virtio com aceleração 3D e não faz nenhuma diferença, tenho os mesmos quadros por segundo. Das duas uma, ou o QXL também faz aceleração 3D ou o Virtio não tá acelerando nada, mas seja lá qual for o caso, o resultado parece o mesmo então meio que tanto faz. Até porque o objetivo de usar esses dispositivos virtuais não é fazer nada pesado graficamente como animação 3D ou jogos. Pra renderizar a interface gráfica de janelas, a velocidade é mais que suficiente.</p>
<p>SPICE é um protocolo pra acessar a interface gráfica remotamente, mais ou menos como um VNC ou Remote Desktop de Windows ou mesmo passar X via SSH pra quem é de Linux, mas é mais performático. Nunca vai ser rápido o suficiente pra games, mas pro dia a dia é suficiente. Então, Display SPICE é o monitor virtual que vai mostrar o que sai da placa virtual com Virtio. E vai aparecer aqui nessa aba com ícone de monitor. Deixa eu mostrar como é com outra máquina virtual que já tinha configurado que é um Ubuntu. Nesse Ubuntu não passei minha NVIDIA, então só tem a placa virtual mesmo, já que uso pra testes e não pra jogar nem nada mais pesado. (liga máquina)</p>
<p>No meu caso, salvo pra casos de sistemas de testes como esse Ubuntu, pretendo passar a placa de video real da NVIDIA pra dentro do guest. Então depois que instalar o sistema operacional e os drivers, vou tirar o Video Virtio e o Display SPICE. Mas um terceiro dispositivo que ainda tenho um pouco de dúvidas é o Console PTY. Isso é um terminal virtual de texto que conecta num pseudo-terminal PTY do host. É uma das formas do host se comunicar com o guest e vice-versa. Antes podia arrancar isso fora, mas não sei se teve alguma atualização que sem o console eu não tava conseguindo bootar a máquina virtual direito, então só deixo lá agora.</p>
<p>Agora vem o dispositivo de som. Pra maioria dos casos pode deixar o que vem por padrão já. Ele emula um dispositivo ICH9 que permite entrada e saída em estéreo. Se precisar usar microfone, acho que essa é a melhor opção. Mas se tiver um home theater, no caso um receiver ligado no PC com configuração de surround ou 5.1, que significa duas caixas laterais frontais, duas caixas traseiras surround, um central pra voz e um sub-woofer que é esse .1, daí precisa mudar no XML pro modelo ser &ldquo;usb&rdquo;. Áudio via USB desse dispositivo suporta saída 5.1 mas não fornece entrada.</p>
<p>Áudio em Linux é outro ninho de ratos chato mas no geral, na maioria das distribuições Linux funciona assim: primeiro tem os drivers pro hardware de áudio, seja o que vem embutido na sua placa mãe ou dispositivos externos. Esses drivers são chamados de ALSA, que significa Advanced Linux Sound Architecture. Mas os aplicativos, como um tocador de música ou video, não fala diretamente com esses drivers.</p>
<p>Entre os aplicativos e os drivers existe um intermediário que roda em userland que normalmente é o Pulseaudio. Tem também o Jack mas nunca vi o Jack em distros populares. O Pulseaudio é quem permite múltiplos aplicativos acessarem saída de áudio, organiza e centraliza o controle de múltiplos streams. Sabe quando abre a configuração de som num GNOME  e ele deixa controlar o volume independente pra cada aplicativo? É o Pulseaudio. </p>
<p>Eu não acompanhei a evolução, mas parece que o Pulseaudio, sendo um sistema antigo e legado, envelheceu mal pra lidar com o aumento no uso de multimídia de aplicativos modernos, especialmente necessidades profissionais, como editores de música que precisam trabalhar com dezenas ou centenas de streams de áudio de uma só vez e exigem baixíssima latência. Latência em áudio é crucial. Imagina um notebook de DJ no meio de um show enorme, e do nada latência dá um pico, trava e quebra o som no meio do show por 1 segundo. É o tipo de coisa que jamais pode acontecer. É um dos pontos fortes do MacOS, por isso todo mundo usa Macbooks em shows.</p>
<p>Pra combater isso nasceu um novo projeto, o Pipewire. Algumas distros modernas, como meu Manjaro, já começaram a substituir o Pulseaudio pelo Pipewire. Parece que Pipewire também tem suporte melhor a áudio via Bluetooth, então quem tinha problemas com fones sem fio, deve ter uma experiência melhor agora. Outra vantagem do Pipewire é ter uma camada de compatibilidade de API, daí aplicativos que esperam trabalhar com Pulseaudio conseguem se comunicar com o Pipewire. De qualquer forma, na configuração do QEMU não precisamos mexer nada. No XML que ele nos deu já vem esse canal de áudio apontando pra pulseaudio. Eu estou usando Pipewire no Manjaro e tá tudo funcionando então acho que funciona plug and play.</p>
<p>Áudio é um troço que dependendo do seu caso de uso, pode dar dor de cabeça. No Wiki que estamos seguindo, ele detalha direitinho como configurar pra pulseaudio, pipewire, jack, scream e mais. Se precisar muito tem como configurar na mão coisas como latência, bitrate. Por exemplo, pode dar problemas se no guest o som estiver configurado pra sair em 48 mhz e no host estiver pra 44 mhz. Se tiver sorte, como eu, não vai precisar mexer em nada. Mas só lembrando que se tiver problemas, tem que fuçar essa parte da documentação.</p>
<p>Chegamos no evento principal: passar a placa de video real NVIDIA pra dentro da máquina virtual. E se fez tudo direitinho lá no começo com IOMMU e VFIO, agora é só clicar em &ldquo;adicionar hardware&rdquo; aqui embaixo, escolher categoria PCI, e selecionar a RTX 3090 que tá separadinha já pra gente. Lembram como no mesmo grupo de IOMMU tinha esse dispositivo de áudio da NVIDIA? Precisa adicionar também, senão a máquina não vai bootar. Mas é só isso. </p>
<p>Comparado com os outros dispositivos que tivemos que configurar, a GPU é a mais fácil. Mais fácil ainda que teclado e mouse, que é nosso próximo passo. O ideal seria ter dois teclados e dois mouses, um conjunto ligado no host, e o outro pra passarmos pra máquina virtual, mas seria bem pouco prático fazer isso. Lembra quando falei sobre o KVM que não é o módulo de virtualização do Linux? O KVM que permite usar um conjunto de teclado e mouse e monitor e ficar chaveando pra mudar de um PC físico pra outro PC físico? É o que vamos fazer.</p>
<p>O chaveador virtual de teclado e mouse se chama EVDEV que é acrônimo pra &ldquo;event device&rdquo;. Olha no Wiki o que ele manda fazer. Temos que listar o que tem no diretório <code>/dev/input/by-id</code>. No meu caso tem todos esses aqui, o mais importante são os dois primeiros. Basta no XML, dentro do bloco de &ldquo;devices&rdquo; adicionar o seguinte:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&#34;evdev&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;source</span> <span class="na">dev=</span><span class="s">&#34;/dev/input/by-id/uinput-persist-mouse0&#34;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/input&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&#34;evdev&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;source</span> <span class="na">dev=</span><span class="s">&#34;/dev/input/by-id/uinput-persist-keyboard0&#34;</span> <span class="na">grab=</span><span class="s">&#34;all&#34;</span> <span class="na">repeat=</span><span class="s">&#34;on&#34;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/input&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&#34;mouse&#34;</span> <span class="na">bus=</span><span class="s">&#34;virtio&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&#34;keyboard&#34;</span> <span class="na">bus=</span><span class="s">&#34;virtio&#34;</span> <span class="nt">/&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Com isso, posso mover meu teclado e mouse pra dentro do guest ou pra fora no host apertando as teclas control da esquerda e da direita do teclado de uma só vez. No Wiki explica também se quiser mudar essa combinação de teclas. Só que na minha configuração de hardware em particular, o mouse não passa como deveria. Vamos entender porque. No terminal, podemos dar <code>cat</code> nesses dispositivos. Olha o que acontece se der <code>cat</code> no teclado.</p>
<p>Viram? Toda tecla que digito aparece o código aqui. É isso que o sistema operacional fica recebendo antes de traduzir pra letras. Vamos fazer a mesma coisa no primeiro dispositivo de mouse. Dou <code>cat</code>  e mexo o mouse e nada acontece. Isso porque estou usando um receptor sem fio USB que é esse outro dispositivo Logitech USB Receiver aqui em baixo. Tem 4 deles, mas depois de tentativa e erro descobri que é esse que termina com &ldquo;event-mouse&rdquo;. Só dar <code>cat</code> nele e olha só recebendo eventos. Portanto devo mudar o XML pra ficar assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&#34;evdev&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;source</span> <span class="na">dev=</span><span class="s">&#34;/dev/input/by-id/usb-Logitech_USB_Receiver-if01-event-mouse&#34;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/input&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&#34;evdev&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;source</span> <span class="na">dev=</span><span class="s">&#34;/dev/input/by-id/uinput-persist-keyboard0&#34;</span> <span class="na">grab=</span><span class="s">&#34;all&#34;</span> <span class="na">repeat=</span><span class="s">&#34;on&#34;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/input&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&#34;mouse&#34;</span> <span class="na">bus=</span><span class="s">&#34;virtio&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&#34;keyboard&#34;</span> <span class="na">bus=</span><span class="s">&#34;virtio&#34;</span> <span class="nt">/&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Pronto, agora sim o meu mouse vai funcionar. Por isso precisa entender o que realmente está acontecendo e o que cada configuração significa. Falta só mais uma coisinha pra continuar que é baixar a imagem ISO de CD com os drivers pra todos os dispositivos virtuais que configuramos. Sabe, todo lugar que selecionamos a opção de &ldquo;virtio&rdquo;? O que é VirtIO? Como o nome diz é &ldquo;Virtual I/O&rdquo;, é um nome genérico pra um conjunto de drivers pra esses dispositivos virtuais. O instalador do Windows não tem idéia de que diabos são dispositivos virtio, então precisamos dar os drivers pra ele.</p>
<p>O link vai estar nas descrições abaixo, mas quem mantém esses drivers é a RedHat e tem todas as versões nesta página da comunidade do Fedora. Só escolher a versão mais recente aqui embaixo e agora baixar este arquivo de ISO de 500 mega. Todos os drivers que vamos precisar estão aqui.</p>
<p>Baixado, vamos voltar pra tela de configuração do Virt Manager. Adicionamos um novo hardware de storage, selecionamos o ISO que acabamos de baixar e configuramos pra ser um CD-ROM SATA. Olha aqui que tem outras opções, tem SCSI, tem USB e tem Virtio. Virtio não pode ser, porque Windows não sabe ainda o que é Virtio sem os drivers que estão justamente nesse ISO. USB não sei pra que serve. SCSI também não rola, porque o instalador do Windows também não detecta SCSI. Por eliminação vai ser SATA.</p>
<p>Padrão SATA é o mais comum e genérico e até o Windows consegue entender na instalação. Por isso tanto o ISO do instalador de Windows quanto o ISO dos drivers, vamos configurar como dispositivos de CD-ROM SATA. Mas o HD virtual, formato qcow2 que criamos, está como SATA, mas Virtio tem performance melhor, então mudamos. Só que assim o instalador não vai detectar o HD. Não tem problema, pra isso baixamos os drivers. Finalmente, chegou a  hora de bootar essa máquina.</p>
<p>Olha só como o video sai pelo Display SPICE que mostra aqui na própria janela. É basicamente um streaming do video gerado pela placa de video virtual Virtio. Ele vai detectar o CD-ROM e podemos fazer o boot, exatamente como faria se fosse instalar via pendrive no seu PC de verdade. Vou passar rapidinho essas primeiras telas porque todo mundo já viu isso antes.</p>
<p>Pronto, chegamos na parte que o instalador tenta achar o HD pra particionar, formatar e copiar os arquivos. Mas não acha nada, porque como expliquei antes, não tem nenhum HD SATA. Mas tem essa opção de &ldquo;Load Driver&rdquo;. Podemos navegar pro CD do Virtio e ir pra pasta &ldquo;amd64&rdquo; logo no começo. Meio burro que o Windows não vasculhe o CD inteiro pra achar os drivers, mas beleza. E olha só, achou o driver da RedHat de controlador SCSI Virtio. E uma vez carregado, sucesso, agora sim ele acha o HD virtual e vai conseguir formatar e instalar. A partir daqui vou acelerar bastante a instalação pra terminar rápido. Terminando em, 3 &hellip; 2 &hellip; 1 &hellip;.</p>
<p>Terminou! Eis que estou no novo Windows virtualizado. Mas não acaba aqui. Primeira coisa a fazer é abrir o Gerenciador de Dispositivos. Olha só que coisa feia, um monte de dispositivos que o Windows não tem idéia do que fazer. Pra resolver isso temos que manualmente clicar com botão direito e mandar instalar o driver a partir do CD do Virtio. E pronto, um dispositivo configurado, vamos pros próximos.</p>
<p>Agora sim, o Windows detectou corretamente tudo que precisava. Esses drivers Virtio são o que chamamos de drivers paravirtualizados. Em uma virtualização completa, o Windows não saberia que tá sendo virtualizado, ele ia ser iludido a achar que tá numa máquina de verdade. E todo driver responderia como se fosse um dispositivo de verdade por baixo e não um arquivo formato qcow2 fingindo ser um HD de verdade. Ou uma ponte com NAT fingindo ser uma placa de rede.</p>
<p>Já drivers paravirtualizados falam pro Windows: &ldquo;ow, tu sabe que isso não é de verdade né?&rdquo; e o Windows &ldquo;porr, sérião? beleza, valeu por avisar, vamos trabalhar juntos nisso então&rdquo;. E sabendo que é virtualizado ele pode se comportar diferente de um driver normal pra otimizar performance. É uma explicação bem grosseira, mas o importante é que o Windows guest sabe que tá numa máquina virtual e vai agir de acordo e cooperar com o host por baixo pra ter mais performance.</p>
<p>A partir daqui é vida normal que segue. Vamos deixar o Windows Update atualizar o que precisa e baixar o resto dos drivers. Enquanto isso podemos ir no site da NVIDIA e baixar o GeForce Experience, que serve pra otimizar as configurações da GPU pra cada jogo. Ele também serve pra monitorar atualizações dos drivers e vamos instalar por ele. De novo, baixar e instalar é demorado então vou acelerar e terminar em 3 &hellip; 2&hellip; 1&hellip;</p>
<p>Com todos os drivers instalados e tudo atualizado, rebootamos a máquina e tá tudo funcionando. O que podemos fazer agora é desligar a máquina e remover a placa de video virtual Virtio e o monitor virtual SPICE. A partir de agora o Windows vai usar direto só a RTX 3090 de verdade. Então vamos fazer isso. Sei lá porque sempre dá erro pra remover esses dispositivos e o mais fácil é entrar na configuração XML e apagar manualmente. Olha só que chato.</p>
<p>Feito isso, vamos bootar de novo. Mas dessa vez vou bootar outro Windows que já tá configurado, com Steam e tudo só pra demonstrar como fica. Nesse caso vou deixar o OBS também rodando por trás pra gravar o jogo.</p>
<p>(jogo)</p>
<p>O que acham? Isso é um game pesado rodando com velocidade normal como se estivesse num PC de verdade. Mas isso só é possível porque estou usando uma CPU parruda, a Ryzen 9 5950. Estou usando só metade dos núcleos, que são 16 threads, com uns 20% menos performance por thread. Mas isso é quase o equivalente a   rodar um processador Ryzen 5 por exemplo, que já é mais do que suficiente pra maioria dos jogos. </p>
<p>Agora deixa mostrar um jogo incompatível com máquina virtual por causa do anti-cheat. Vamos carregar Elden Ring, esperar um pouco  e &hellip; olha só, dá pau e fecha. Ainda bem que no caso específico do Elden Ring a gambiarra pra carregar offline é simples. Basta ir com o explorer no diretório do jogo, apagar esse executável que carrega o anti-cheat e renomear o executável do jogo propriamente dito com o mesmo nome. Pronto. Vamos carregar de novo e olha só, não deixa entrar online mas pelo menos posso jogar sozinho, que é o que eu queria.</p>
<p>Eu não jogo online, mas quem joga uns Valorant da vida, não vai funcionar em máquina virtual pelo mesmo motivo: o anti-cheat vai detectar que tá em máquina virtual e se não tomar cuidado você pode ser banido. Assim como Elden Ring, alguns jogos tem jeitos de burlar isso mas de novo, tome cuidado pra não ser banido. Mas existe uma última saída caso eu quisesse muito jogar isso. Vamos abrir a configuração desta máquina virtual no Virt Manager.</p>
<p>Diferente da máquina virtual de testes que tava montando pra esse video, essa outra máquina que mais uso não foi instalado num HD virtual qcow2. Eu já tinha esse Windows em dual boot instalado direto no SSD NVME. Era meu sistema principal antes de instalar o Manjaro. Olha aqui a configuração de armazenamento no Virt-Manager. Em vez de apontar pra um arquivo .qcow2 está apontando direto pro dispositivo <code>/dev/nvme0n1</code>. </p>
<p>Digamos que eu queria muito jogar Elden Ring ou qualquer outra coisa que tenha anti-cheat online. Não tem jeito, a única forma é rodar num Windows nativo sem virtualizar. Nesse caso tenho que desligar meu Manjaro, rebootar e no Grub escolho Windows. Vamos acelerar aqui o boot e olha só, notaram? É exatamente o mesmo Windows que tava funcionando virtualizado. Felizmente, até o Windows é inteligente o suficiente pra detectar os dispositivos de verdade e carregar os drivers nativos certos em vez dos VFIO da máquina virtual. Eu posso usar o mesmo Windows tanto em dual boot nativo quanto virtualizado pelo QEMU/KVM.</p>
<p>E a partir daqui é um dual boot normal, sem nada de virtualização, com o Windows tendo acesso a 100% da CPU e às minhas duas placas de video. No caso de games, é onde vou ter o máximo possível de performance, caso precise. Mas se precisar de alguma coisa do Linux, preciso fechar tudo e rebootar de novo, um puta saco. Mas vamos voltar pro Manjaro de novo e abrir o Virt Manager, quero mostrar uma última coisa.</p>
<p>Se eu iniciar o Windows virtualizado por aqui, veja no gráfico que tá carregando, mas meu teclado e mouse páram de funcionar e não vejo nada no monitor. Isso porque o EVDEV que configurei sequestra meu teclado e mouse, mas isso é simples, basta apertar as duas teclas de control ao mesmo tempo, e o controle volta pro host Linux, olha só. E o Windows tá mandando sinal de video pela RTX 3090 que liga na segunda entrada de video do monitor. Eu preciso apertar o botão de menu aqui atrás e navegar até achar o lugar que muda qual sinal de HDMI o monitor vai mostrar. Olha só, tá aqui o Windows.</p>
<p>Vamos voltar pro cabo que sai da placa AMD e ficar no Linux um pouco. Notaram uma coisa irritante? Toda vez que eu abrir uma máquina virtual que usa a placa da NVIDIA precisa botar a mão atrás do monitor, caçar o botãozinho às cegas e mudar o input. Não, tem que ter jeito melhor, e de fato tem. Pesquisando, esbarrei nesta ferramenta chamada &ldquo;ddcutil&rdquo;. Vale ler toda a documentação, mas deixa demonstrar o que ela faz.</p>
<p>Primeiro, vamos abrir o terminal e rodar <code>ddcutil detect</code> com sudo. E  detectou meus dois monitores. O primeiro é o Samsung vertical e o segundo é o Asus principal. Agora posso fazer <code>ddcutil capabilities --display 2 --verbose</code> e  lista todos os comandos que meu monitor Asus suporta. Olha só, posso mexer no brilho, contraste, cores, mas o que me interessa é esse comando hexadecimal <code>60</code> que é input source.</p>
<p>Teoricamente, se rodar <code>ddcutil setvcp 60 0x01</code> deveria mudar pra entrada de DisplayPort e com <code>0x03</code> deveria ir pra entrada DVI. Mas por alguma razão essa lista tá errada ou incompleta, porque não listou os HDMIs. Eu não lembro mais onde foi que achei mas pro meu monitor Asus ROG TUF encontrei em algum lugar que os valores corretos são <code>0x0f</code> e <code>0x12</code>. Olha só, <code>ddcutil setvcp 60 0x0f</code>. Viram só? Mudou pra saída da placa NVIDIA. Podemos repetir o comando só que com <code>0x12</code>  e olha só, voltou pra saída da placa AMD. </p>
<p>Antes que alguém comente, sim, o que fiz com <code>ddcutil</code> teoricamente era pra funcionar com o comando <code>xrandr</code> mas por alguma razão não  funciona. Por isso procurei alternativas. Essas porcarias de servidor X.org e Wayland e essa transição até hoje ainda não tá 100%. Aliás, uma das razões de estar usando essa placa pequena AMD RX 6400 é justamente pra conseguir usar Wayland decentemente em vez de X.org. Dizem que NVIDIA já suporta ou vai suportar XWayland, mas ainda não parei pra ver isso. NVIDIA é um dos responsáveis pelo atraso na adoção de Wayland nas distros. Se for usar primariamente Linux, o recomendado é escolher placas de video da AMD.</p>
<p>Por último mesmo, tem um problema. Meu Manjaro eu deixo configurado pra depois de algum tempo, 1 ou 2 horas sem usar, fazer o sistema dormir pra economizar energia. Não gosto de desligar a noite antes de dormir e ter que esperar bootar de manhã. O problema é que enquanto estou usando a máquina virtual, o host tá como se ninguém estivesse usando. Então depois de 1 ou 2 horas, o host resolve que quer dormir. Só que quando isso acontece, congela a máquina virtual, porque o hypervisor vai dormir também, e aí trava tudo e eu preciso forçar um reboot no botão do PC.</p>
<p>Então criei um script chamado <code>bin/suspend</code> que aceita opção &ldquo;on&rdquo; ou &ldquo;off&rdquo; pra ligar ou desligar a função de dormir do GNOME usando o comando <code>gsettings</code>. Tem outras formas de fazer, se estiver em KDE ou outro gerenciador vai ser diferente, mas isso deve dar uma dica pra quem estiver interessado. Com esse comando, antes de ligar a máquina virtual eu rodo <code>bin/suspend off</code> e isso vai desligar a suspensão. E quando desligar a máquina virtual rodo <code>bin/suspend on</code> pra religar a função de suspensão da máquina e pronto.</p>
<p>Aproveitando, resolvi criar um script chamado <code>bin/vmstart</code> onde passo o nome da máquina. Olha o que ele faz: primeiro muda o governador das CPUs pro modo de performance. Em seguida desliga a configuração de suspensão do host. Finalmente, usa o comando <code>virsh start</code> pra iniciar a máquina virtual. Nesse momento a máquina vai bootar mas não adianta mudar a entrada do monitor já pra placa da NVIDIA porque até o Windows carregar não vai ter nenhum sinal de video. Então forço um sleep de 30 segundos e depois rodo o comando <code>ddcutil</code> pra mudar a entrada automaticamente. Vamos ver funcionando?</p>
<p>Rodo <code>bin/vmstart win11-real</code> que é minha máquina Windows principal onde tem meu DaVinci Resolve, Photoshop e onde edito os videos aqui do canal. Mais alguns segundos &hellip; e pronto, olha só, Windows carregado. Agora posso iniciar qualquer das minhas máquinas virtuais via linha de comando, sem precisar abrir o Virt-Manager. </p>
<p>Esse video já tá longo pra caramba, e isso porque pulei o que são Huge Pages na configuração de memória RAM, pulei falar de I/O threads e como reservar threads só pra operações de I/O, pulei falar de como dinamicamente mover coisas como meus gamepads USB pra máquina virtual automaticamente via &ldquo;udev&rdquo;, pulei falar sobre como é mais fácil plugar um hub USB. Enfim, o Wiki tem um montão de detalhes a mais. É uma aula de como configurar seu hardware e mesmo que você não vá montar uma configuração complicada como a minha, recomendo dar uma boa lida com muita atenção.</p>
<p>Além da página de Wiki do Arch também recomendo ler a página de Wiki do Gentoo. Ele tem informações extras que complementam a do Arch e uns truques e correções importantes. Como eu disse, esses dois Wikis são excepcionais e pra montar configurações complicadas assim, toda informação extra é bem vinda. </p>
<p>Com isso, finalmente consegui fazer uma coisa que vinha querendo faz mais de uma década: ter uma máquina com duas placas de video e conseguir passar uma delas pra máquinas virtuais funcionarem com performance máxima, especialmente pra games. Essa solução é melhor que dual boot porque posso subir quantas instalações de Windows ou Linux quiser, destruir quando não quiser mais, sem me preocupar em estragar o boot ou perder alguma coisa. Meus arquivos de HD Virtual qcow2 ficam no meu NAS que tá conectado com rede de 10 Gigabits, então mesmo bootando remotamente, a performance é muito boa. </p>
<p>Como falei no começo, o objetivo era documentar tudo que tive que pesquisar pra montar esse setup antes que começasse a esquecer os detalhes. A partir daqui vou sempre ficar mexendo scripts, coisinhas aqui e ali pra ajustar performance ou conveniência.</p>
<p>O mais bizarro que não vou mostrar no video é que hypervisors suportam nesting, ou seja, máquina virtual rodar outra máquina virtual. Eu consigo virtualizar o Windows e, de dentro dele, instalar WSL e rodar Linux via Hyper-V em cima do Windows que tá em cima do QEMU/KVM. É Inception na veia. Além disso posso rodar o Garuda Linux, abrir o Steam que roda via Proton, que é uma camada que usa Wine e várias outras bibliotecas pra emular Windows. </p>
<p>E falando em emulador, no outro Windows só pra jogos também instalei vários emuladores como o PCSX2 de PS2 ou RPCS3 de PS3 ou Yuzu de Nintendo Switch e mais. Emulador rodando dentro de emulador. Esse é o nível que eu esperava atingir 21 anos atrás quando comecei a mexer com máquinas virtuais. E por hoje é isso, se ficaram com dúvidas ou tiverem sugestões em cima desse setup, mandem nos comentários abaixo, se curtiram o video deixem um joinha, assinem o canal e não deixem de compartilhar o video com seus amigos. A gente se vê, até mais!</p>
]]></content:encoded><category>games</category><category>hardware</category><category>performance</category><category>akitando</category></item><item><title>[Akitando] #98 - A Longa História de CPUs e GPUs | Jogos de Windows em Linux??</title><link>https://akitaonrails.github.io/2021/05/26/akitando-98-a-longa-historia-de-cpus-e-gpus-jogos-de-windows-em-linux/</link><guid isPermaLink="true">https://akitaonrails.github.io/2021/05/26/akitando-98-a-longa-historia-de-cpus-e-gpus-jogos-de-windows-em-linux/</guid><pubDate>Wed, 26 May 2021 12:26:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/JEp7ozWqIps"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Finalmente parei pra brincar de jogos de Steam/Windows rodando em Linux na mesma (ou melhor) performance. LSI Steam + Wine + DXVK + Proton-GE. Qual é a história que nos trouxe até aqui? Hoje quero contar 30 anos de história de CPUs e GPUs pra você ter um panorama de como as coisas evoluíram no mundo gráfico até hoje. E a partir de 01:01:26 falar mais especificamente de como configurei NVIDIA Optimus no meu laptop.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/JEp7ozWqIps"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Finalmente parei pra brincar de jogos de Steam/Windows rodando em Linux na mesma (ou melhor) performance. LSI Steam + Wine + DXVK + Proton-GE. Qual é a história que nos trouxe até aqui? Hoje quero contar 30 anos de história de CPUs e GPUs pra você ter um panorama de como as coisas evoluíram no mundo gráfico até hoje. E a partir de 01:01:26 falar mais especificamente de como configurei NVIDIA Optimus no meu laptop.</p>
<h2>Conteúdo:<span class="hx:absolute hx:-mt-20" id="conteúdo"></span>
    <a href="#conte%c3%bado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>00:00:00 - Intro</li>
<li>00:02:08 - Games rodando no Linux</li>
<li>00:04:24 - pós-Intro</li>
<li>00:04:56 - ThinkPad X1 Extreme</li>
<li>00:05:17 - Solução térmica de laptops</li>
<li>00:08:56 - Boost e Throttling</li>
<li>00:11:08 - Diferentes tipos de CPUs</li>
<li>00:13:42 - AMD Ryzen acelerando!</li>
<li>00:16:11 - Apple e AMD vs Intel</li>
<li>00:17:33 - Intel atira no pé: Samsung avança</li>
<li>00:17:55 - Apple: jornada pra independência</li>
<li>00:21:28 - AMD quase compra NVIDIA?</li>
<li>00:21:59 - História dos GPUs</li>
<li>00:22:11 - 1990 - SGI, Rare e Nintendo</li>
<li>00:25:06 - 1994 - arcades e consoles 32-bits</li>
<li>00:26:04 - mundo monocromático</li>
<li>00:28:09 - cores: ATI e VESA</li>
<li>00:29:12 - entendendo resoluções</li>
<li>00:30:35 - entendendo interlacing</li>
<li>00:31:46 - workstations SGI</li>
<li>00:33:29 - 1995 - entra a 3DFX</li>
<li>00:34:10 - o fator Carmack</li>
<li>00:34:47 - o fim da 3DFX - libglide</li>
<li>00:36:54 - o fim da SGI - IrisGL</li>
<li>00:38:05 - 2000 - ATI vs NVIDIA</li>
<li>00:38:38 - 3D no desktop</li>
<li>00:39:51 - Shaders</li>
<li>00:40:28 - Cel Shading</li>
<li>00:41:09 - Vertex Shader</li>
<li>00:42:16 - Shader Languages</li>
<li>00:45:17 - GPGPU e nomenclaturas</li>
<li>00:47:43 - Cuda, OpenCL</li>
<li>00:48:25 - 2014 - Apple Metal</li>
<li>00:49:24 - Chegamos no Vulkan!</li>
<li>00:50:08 - MoltenVK, Angle, DX12</li>
<li>00:51:57 - Bytecode de shaders</li>
<li>00:53:19 - DXVK</li>
<li>00:54:33 - A API pra unificar todas as APIs</li>
<li>00:57:06 - Entra a Valve!</li>
<li>00:57:34 - Evoluindo do Wine</li>
<li>00:59:06 - 2018 - de DirectX pra Vulkan</li>
<li>01:00:25 - Finalmente, Proton!</li>
<li>01:01:26 - NVIDIA vs open source (config começa aqui)</li>
<li>01:04:11 - Decepticon: Optimus Prime</li>
<li>01:10:54 - (libusb com xow usa muita CPU, cuidado!)</li>
<li>01:11:31 - Resumão</li>
<li>01:13:28 - O outro legado da SGI</li>
<li>01:14:01 - Conclusão</li>
</ul>
<h2>Links:<span class="hx:absolute hx:-mt-20" id="links"></span>
    <a href="#links" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>Why did SGI (Silicon Graphics) fail? (<a href="https://www.quora.com/Why-did-SGI-Silicon-Graphics-fail"target="_blank" rel="noopener">https://www.quora.com/Why-did-SGI-Silicon-Graphics-fail</a>)</li>
<li>Why did AMD buy out ATI? ((8) Why did AMD buy out ATI? - Quora)</li>
<li>The History of the Modern Graphics Processor (<a href="https://www.techspot.com/article/650-history-of-the-gpu/"target="_blank" rel="noopener">https://www.techspot.com/article/650-history-of-the-gpu/</a>)</li>
<li>3Dfx History: The GPU’s Great Turning Point? (<a href="https://tedium.co/2018/02/14/3dfx-history-failure/"target="_blank" rel="noopener">https://tedium.co/2018/02/14/3dfx-history-failure/</a>)</li>
<li>Chapter 34. PRIME Render Offload (<a href="https://download.nvidia.com/XFree86/Linux-x86_64/440.44/README/primerenderoffload.html"target="_blank" rel="noopener">https://download.nvidia.com/XFree86/Linux-x86_64/440.44/README/primerenderoffload.html</a>)</li>
<li>proton-ge-custom - GitHub (<a href="https://github.com/GloriousEggroll/proton-ge-custom"target="_blank" rel="noopener">https://github.com/GloriousEggroll/proton-ge-custom</a>)</li>
<li>DXVK - GitHub (<a href="https://github.com/doitsujin/dxvk"target="_blank" rel="noopener">https://github.com/doitsujin/dxvk</a>)</li>
<li>MetalAngle - GitHub (<a href="https://github.com/kakashidinho/metalangle"target="_blank" rel="noopener">https://github.com/kakashidinho/metalangle</a>)</li>
<li>MoltenVK - GitHub (<a href="https://github.com/KhronosGroup/MoltenVK"target="_blank" rel="noopener">https://github.com/KhronosGroup/MoltenVK</a>)</li>
<li>Angle - GitHub (<a href="https://chromium.googlesource.com/angle/angle"target="_blank" rel="noopener">https://chromium.googlesource.com/angle/angle</a>)</li>
<li>An interview with the developer of DXVK, part of what makes Valve&rsquo;s Steam Play tick (<a href="https://www.gamingonlinux.com/articles/an-interview-with-the-developer-of-dxvk-part-of-what-makes-valves-steam-play-tick.12537"target="_blank" rel="noopener">https://www.gamingonlinux.com/articles/an-interview-with-the-developer-of-dxvk-part-of-what-makes-valves-steam-play-tick.12537</a>)</li>
<li>The story of WebGPU — The successor to WebGL (<a href="https://eytanmanor.medium.com/the-story-of-webgpu-the-successor-to-webgl-bf5f74bc036a"target="_blank" rel="noopener">https://eytanmanor.medium.com/the-story-of-webgpu-the-successor-to-webgl-bf5f74bc036a</a>)</li>
<li>Vulkan and Metal (some observations) (<a href="https://developer.apple.com/forums/thread/38469"target="_blank" rel="noopener">https://developer.apple.com/forums/thread/38469</a>)</li>
<li>3 Years of Metal (<a href="https://blog.roblox.com/2020/05/3-years-metal/"target="_blank" rel="noopener">https://blog.roblox.com/2020/05/3-years-metal/</a>)</li>
<li>A Comparison of Modern Graphics APIs (<a href="https://alain.xyz/blog/comparison-of-modern-graphics-apis"target="_blank" rel="noopener">https://alain.xyz/blog/comparison-of-modern-graphics-apis</a>)</li>
<li>Thread Rare/SGI (<a href="https://twitter.com/GameAnim/status/1077359488657612800?s=20"target="_blank" rel="noopener">https://twitter.com/GameAnim/status/1077359488657612800?s=20</a>)</li>
<li>The 8-bit Guy: CGA Graphics - Not as bad as you thought!(<a href="https://youtu.be/niKblgZupOc"target="_blank" rel="noopener">https://youtu.be/niKblgZupOc</a>)</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Algumas pessoas me perguntam em DMs como eu faço pra conciliar jogar, estudar, trabalhar e tudo mais. Na real, eu nunca conciliei bem não. Nunca tive dias e horários bem definidos pra fazer as coisas, sempre fui fazendo de acordo com a prioridade da época. Mas vocês esquecem de outra coisa: eu não estou mais no começo de carreira. Vira e mexe eu falo de games porque só agora é que tô tendo um pouco mais de tempo sobrando. Eu sempre gostei de games desde criança, mas na faixa dos 20 e poucos aos 30 e poucos anos eu quase não jogava. Cansei de começar jogo e nunca ter tempo de continuar.</p>
<p>Essa foi uma fase mais ou menos do começo dos anos 2000 até alguns poucos anos atrás, pulei a metade final do PS2, pulei o Xbox original, Wii, Wii U, PS3, Xbox 360. Só fui voltar na metade final da era do PS4 e Xbox One. Jogos de PC então, a última vez que tive um desktop foi lá pra 2001 ou 2002. Pra piorar, de 2004 a 2015 eu usei quase exclusivamente Macs, então esquece games. Pulei totalmente a fase do World of Warcraft ou Skyrim por exemplo. A última vez que eu tinha jogado FPS foi na época do Half Life II original e mesmo assim não acabei.</p>
<p>Mesmo assim sempre fiquei acompanhando a evolução das coisas, e finalmente de uns 3 anos pra cá que voltei a jogar mais. Só que aí comecei o canal e acabou meu tempo livre de novo. Como eu disse no episódio passado, eu tenho mais cabeça de colecionador do que propriamente jogador. Eu não jogo e-sports porque sou tão ruim num Counter Strike quanto num futebol de verdade e prefiro jogos single player. Eu não jogo pra socializar, pra mim é mais que nem ler um livro ou ver um filme.</p>
<p>De qualquer maneira empolguei pra fazer esse episódio porque meu notebook tava me irritando. É um notebook bom na real. Mas no Windows 10 ele superaquecia muito rápido, ventoinha ficava a milhão e pra usar no colo era bem ruim, mesmo fazendo undervolting. Já faz um tempo que queria colocar Linux nele, resolvi fazer isso esses dias.</p>
<p>Aproveitei pra testar uma coisa que já tinham me falado mas que só agora resolvi ver com os próprios olhos: o suporte a games de Windows rodando em Linux com praticamente a mesma performance, ou às vezes até um pouco melhor. E dêem uma olhada!</p>
<p>(&hellip; games)</p>
<p>Pois é, todas as cenas que vocês acabaram de ver foram gravadas via OBS na mesma máquina rodando os jogos, tudo do Steam, nativo num Linux, sem máquina virtual, sem dual boot nem nada! Se você já é gamer experiente, o que vou falar hoje provavelmente vai ser arroz com feijão, mas acho que a maioria das pessoas, incluindo a maioria dos programadores desconhece a história de como chegamos nesse ponto, vamos voltar no tempo de novo!</p>
<p>(&hellip;)</p>
<p>Esse notebook é um Thinkpad X1 Extreme. Quem assistiu o episódio sobre teclados mecânicos já viu ele. É um notebook muito bom no papel, mas a Lenovo pisou um pouco na bola na solução térmica. Eu li que o X2 também superaquece fácil. A gambiarra pra ajudar um pouco é trocar a pasta térmica. Pelo menos o processo pra isso é bem simples.</p>
<p>A maioria dos fabricantes usa uma pasta que tem mais durabilidade, pra você nunca ter que abrir a máquina pra trocar. Mas o problema é que esses tipos não dissipam tão bem o calor quanto deveriam. E pra piorar tenho uma GPU discreta, a GTX 1050 Max Q, que também esquenta bastante. Quando as duas funcionam juntas, rapaz, fica quente. Não recomendo usar no colo muito tempo se não quiser ficar estéril. CPU e GPU e qualquer chip na real, incluindo RAM, SSD, tudo dissipa a maior parte da eletricidade que consome na forma de calor.</p>
<p>Quanto mais você quer forçar um chip pra ir mais rápido, mais energia vai consumir e muito mais calor vai dissipar. Quando se fala em diminuir o tamanho dos transistores é pra consumir menos energia pra fazer o mesmo trabalho e aí dissipar menos calor. Produção de chips é sempre um trade off entre performance, consumo de energia e dissipação de calor. Quanto mais rápido você quer um chip, precisa dar mais energia, e precisa dar um jeito de esfriar, senão queima o chip.</p>
<p>O problema de dissipar é que quanto menor o chip e mesmo assim consumindo mais e mais energia, menos área tem pra dissipar. Por isso a gente estende essa área com heat pipes, canos de calor, que são troços de metal que vão de um lado pro outro do notebook. Daí os fans ou ventoinhas são colocados estrategicamente pra remover o calor que esses canos vão dissipando pro ar e pra carcaça do notebook.</p>
<p>Mesmo o material do cano sendo altamente condutor, ele precisa estar 100% encostado no chip, mas isso não é possível só encostando um metal no outro. Pra isso a gente coloca um material viscoso entre os dois, a tal pasta térmica, cujo trabalho é pegar o calor do chip e passar pros canos com a menor resistência possível. E por isso queremos uma pasta de boa qualidade. Você pode economizar onde quiser, menos na pasta térmica. Muita gente recomenda marcas como da Noctua, da Artic e eu escolhi a Thermal Grizzly Kryonaut. Que eu tinha usado já no meu PC e tinha sobrado.</p>
<p>Isso resolve parte do problema. Se você já pesquisou notebooks gamers e ultrabooks de produtividade não sei se já se perguntou porque os gamers como Predators costumam ser maiores e mais grossos do que ultrabooks como um Macbook Air. Porque aplicativos como Word, Excel, e navegadores raramente puxam 100% da CPU e da GPU o tempo todo. Se você abrir o Task Manager do Windows agora, vai ver que fica na faixa de 30% de uso pra menos. A realidade é que no dia a dia você não precisa de muito.</p>
<p>Só quando vai fazer processamento mais pesado, como compilar um programa grande, processar imagens, renderizar video ou jogar games, é que realmente vai puxar a máquina. Ultrabooks evitam colocar GPUs e preferem usar gráfico integrado como o Intel Irix. Fica tudo num chip só, a solução térmica pode ser mais simples, e no caso de um Macbook Air nem coloca ventoinha.</p>
<p>Já um notebook gamer parte do princípio que um dos usos principais vai ser jogar então é mais pesado porque vai ter mais canos de dissipação de calor, os heat pipes e até usar soluções mais agressivas como vapor chambers, que são canos que usam a dinâmica de fluidos internamente pra ajudar na dissipação. É o que videogames novos como o Xbox Series X usa.</p>
<p>Mais do que isso, além de usar pasta térmica, máquinas mais caras e modernas preferem usar metal líquido. Lembram do Exterminador do Futuro 2? É tipo isso, mais parecido em aparência com mercúrio. É altamente condutor de calor mas diferente de pasta normal, também condutor de eletricidade, por isso precisa ficar garantidamente isolado e nunca vazar na placa, porque senão vai dar curto circuito e queimar tudo. Eu mesmo não me animo a arriscar. Mesmo porque não pretendo brincar de overclocking.</p>
<p>Quem monta PCs e faz overclocking se diverte com essas coisas, mas foi só pra mencionar que existem essas coisas. Isso deriva de uma época onde clock, a velocidade da CPU, era fixa. Mas faz anos já que chips como CPU e GPU conseguem se auto-regular. Quando eles vêem que tem pouca demanda, tentam diminuir o clock pra usar menos energia, até o ponto onde o sistema não vai ficar muito lento. E quando começa um processamento maior, tipo renderizar um vídeo, daí aumenta até o máximo e se precisar de mais, ativa modo de Turbo Boost no caso da Intel ou Precision Boost da AMD.</p>
<p>Por isso é difícil comparar máquinas hoje em dia só olhando o gigahertz nominal da CPU. Existe clock base que é o mínimo que o CPU faz, por exemplo 1.5Ghz, existe um intervalo de clocks que ele pode ter, tipo subir pra 2Ghz, pra 3Ghz. E existe Turbo Boost, onde pode ir pra 4 Ghz ou mais. O problema quando entra em Turbo é que vai puxar consideravelmente mais energia, o que é ruim pra bateria num notebook, e é super ruim pra solução térmica. A temperatura que na média fica ali nos 40 graus rápido pode subir pra 90, 100 graus. E quando isso acontecer a CPU vai tentar se proteger.</p>
<p>Mesmo se seu trabalho ainda não tenha terminado, o CPU vai se capar e diminuir drasticamente dos 4Ghz que ele tava de volta pra baixo de 2Ghz. Mais da metade da performance pode ir pro saco até a temperatura voltar ao normal. Isso que chamamos de throttling. O que vai determinar até quanto um chip pode ir é a configuração de TDP que é thermal design power, medido em watts.</p>
<p>Quanto maior o TDP, mais energia o chip vai receber, mais quente fica. O mesmo processador Intel i5 de fabricantes diferentes de notebook pode sair configurado com TDPs diferentes, dependendo da solução térmica. O problema é que nenhum fabricante quer capar demais os chips pra não parecer que a máquina dele é mais lenta que a do concorrente. Só que se você usa mesmo a máquina pra fazer coisas pesadas, rápido vai chegar no limite térmico e a máquina vai passar mais tempo em throttling do que em turbo boost e no geral você vai sentir a tudo lento, bateria acabando rápido, muito quente, e barulhento com ventoinha sempre ligada no máximo.</p>
<p>Exemplo mais notório eram os Macbooks de 2015 até agora. O design industrial da Apple foi feito pra um certo nível de dissipação térmica. A carcaça de alumínio até ajuda um pouco a dissipar comparado com carcaças de plástico. Mas nos últimos anos todo novo Macbook esquentava pra caramba e fazia throttling o tempo todo, perdendo pra maioria dos concorrentes. Isso porque a Intel vinha prometendo melhorar os chips e nunca conseguiu fazer isso. E a Apple ficou vendida nessas promessas. Por isso ela passou os últimos anos melhorando o próprio chip que vinha usando nos iPhones, até chegar no ponto de inflexão com os A14 bionic, que dá origem ao M1 de hoje.</p>
<p>A Intel usa processo de fabricação de 10 nanômetros, mas isso só a partir de 2018 ou 2019, com a série Cove de processadores, que é o nome das microarquiteturas de 10 nanômetros deles. Palm Cove, Sunny Cove e agora Willow Cove que é a arquitetura dos chips de codenome Ice Lake e Tiger Lake. Você vai reconhecer como os chips da geração 10 e 11, que saiu recentemente.</p>
<p>A gente consumidor, vendo nos sites, só enxerga que existe Core i3 que é considerado o mais fraquinho, Core i5 que povo enxerga como o melhor custo benefício, Core i7 pra quem precisa trabalhar mais pesado e Core i9 que é o top de linha. Mas esses são os nomes de marketing. Um Core i5 atual da décima primeira geração, codenome Tiger Lake, pode ser mais performático do que um Core i7 de 2011, codenome Sandy Bridge.</p>
<p>Nem vou perder tempo tentando explicar a diferença de i3, i5, i7 e i9. Dentro de uma mesma geração, do i3 ao i9 vai variar preço, lógico. Mas isso porque o i3 vai ser o que tem menor clock, menos quantidade de cores, menos cache - que faz bastante diferença no dia a dia, mas também vai consumir menos energia e ser mais econômico. Daí o i9 no outro extremo vai ser o mais caro, mais bebedor de energia e o mais quente, e por isso você não vai ver em notebooks, mas também vai ter mais cores pra processamento paralelo, e mais cache, com clocks mais altos. Por isso depende do seu uso.</p>
<p>O do meu PC é um i9-9990K, o primeiro 9 é porque é da 9a geração Coffee Lake, ainda usando processo de 14 nanômetros. O modelo é 990 e o K é porque é desbloqueado pra overclocking. O do meu notebook Thinkpad X1 é um i7-8850H, então é 8a geração por acaso também codenome Coffee Lake, modelo 850 e esse H é de High Performance Graphics, porque a GPU integrada da Intel é um pouco melhor do que a média.</p>
<p>A Intel já vinha apanhando por causa da AMD desde quando começou a série Ryzen em 2016. Pra você não se confundir, eles também usam uma nomenclatura parecida de gerações e classes. Um Ryzen 3 é posicionado como concorrente do Intel i3, o Ryzen 5 concorrente do i5 e assim por diante. A primeira geração de 2016 era a série 1000 e hoje estamos na série 5000.</p>
<p>Eu acho que a primeira geração 1000 já era boa mas ainda não era tão ameaçadora pra Intel. Em 2016 ambos ainda usavam processo de fabricação MOSFET e tecnologia de 14 nanômetros. A Intel sempre teve as próprias fábricas, a AMD terceirizava pra GlobalFoundries. A arquitetura da AMD também tem nome, assim como Coffee Lake é o nome da microarquitetura da Intel, o da AMD é o Zen, na época Zen Plus.</p>
<p>Em 2018 a série 2000 da AMD saltou pra 12 nanômetros e a Intel ainda tava em 14. Eles já deviam ter avançado dos 14 e nada. Daí veio a bomba com a geração 3000 em 2019: a AMD se juntou com a fabricante chinesa de semicondutores TSMC que é a mesma que fabrica os chips de iPhone pra Apple. A necessidade de ter fabricantes com pontos fortes diferentes talvez tenha levado ao design de chiplets, um chip composto por chips menores, chiplets, de fabricantes diferentes. Chiplets de 7 nanômetros da TSMC com chiplets de 12 nanômetros da GlobalFoundries. Aqui começou o nocaute na Intel, ainda nos 14 nanômetros.</p>
<p>A série 3000 usa arquitetura Zen 2, que é o que a Sony e a Microsoft escolheram pra montar o novo Playstation 5 e Xbox Series X. A série Ryzen 4000 continua melhorando a arquitetura Zen 2 e a AMD não parou e lançou a arquitetura Zen 3 com a série 5000 em 2020. Enquanto isso a Intel pulou do antigo processo de 14 nanômetros MOSFET, finalmente pra FINFET mas ainda em meros 10 nanômetros.</p>
<p>MOSFET e FINFET são processos de como você monta o transistor no waffle de silício. Povo chama de transistor planar e transistor tridimensional, respectivamente. Pra gente que não é de eletrônica é detalhe demais, mas vou deixar link abaixo pra quem tiver interesse. Importante é entender que FINFET é um processo mais complicado e mais caro. E a Intel demorou pra adaptar as fábricas deles, mas a TSMC de Taiwan já tinha dominado essa tecnologia, porque já faziam chips de iPhone com processo de 5 nanômetros.</p>
<p>Essa é uma das razões de porque o chip M1 da Apple e os Ryzen da AMD consomem menos energia e têm mais performance que o equivalente da Intel. Só em termos de tamanho do transistor, o da Apple é metade do tamanho da Intel. O da AMD é 30% menor. Fora várias outras diferenças de arquitetura como o design mais drástico do M1 ser um SoC que é system on a chip, com memória e GPU tudo integrado pra maximizar a velocidade dos componentes.</p>
<p>A Intel tem pelo menos dois grandes problemas: sendo ela a maior do mercado, se deixou ser ultrapassada pela TSMC chinesa como a melhor fabricante de semicondutores, pelo menos aos olhos do público. Ela inventa uma desculpa atrás da outra faz alguns anos. Na prática faz parecer que quando chegaram nos 14 nanômetros, já dominava no desktop, nos notebooks e nos servidores. Fatia enorme do mercado, e quando tudo tá bom demais, você fica complacente. Porque ir mais rápido se o que já temos é bom o suficiente?</p>
<p>Daí a AMD que parecia estar decaindo deu 180 graus e voltou com tudo. E faz sentido, quando você não tem nada pra perder é quando vai arriscar as melhores idéias. E a parceria com a GlobalFoundries e depois com a TSMC selou o acordo. Eu não conheço a história deles direito, mas se fosse pensar numa hipótese eu diria que isso também foi culpa indireta da própria Intel. Deixa eu explicar.</p>
<p>Quando a Apple tava atrás de fornecedores pros componentes do iPhone antes do lançamento de 2007, eles foram pra Intel, afinal eles tinham acabado de migrar dos processadores PowerPC da IBM pra Intel em 2005. Mas como eu disse, pra um gigante que fornecesse milhões de chips pra data centers e desktops, um mercado de fones, em 2005, era irrisório e eles deixaram passar.</p>
<p>Quem ganhou foi a Samsung que começou a fabricar chips pra iPhone. A Samsung ganhou o know how não só de fazer chips como melhorar as telas que já tinham, antes de começarem a lançar a linha Galaxy. Lógico que depois que o iPhone literalmente explodiu no mundo e os Androids começaram a chegar, a Samsung, que também é uma gigante, não bobeou. Ao mesmo tempo virou concorrente e fornecedor pra Apple. Uma relação bem bizarra mesmo.</p>
<p>Lógico que a Apple precisava de plano B. E foi quando eles começaram a fazer pelo menos os designs dos próprios chips em vez de depender de propriedade intelectual da Samsung. Foi quando saiu o chip A4 em 2010, baseado na licença da ARM Cortex V8. Nesse ponto quem ainda fabricava o chip era a Samsung e ia continuar sendo assim por mais algum tempo.</p>
<p>Nessa época a Apple tava numa boa convergência de boas tecnologias. Se você assistiu meu video sobre Apple e GPL entende que fazia alguns anos que ela vinha melhorando suas tecnologias de compiladores e linguagens. Foi assim que conseguiram migrar de PowerPC pra Intel, foi assim que conseguiram modernizar do Objective-C pra Swift. O investimento em LLVM da Apple ia começar a se pagar.</p>
<p>Entenda. Quando você tem compiladores ruins, muita coisa depende da arquitetura do chip, mais especificamente do conjunto de instruções de baixo nível, porque eventualmente você acaba tendo que escrever trechos em assembler onde o compilador de C ou outra linguagem não consegue cuspir binários otimizados. Mas o LLVM ajudou a dividir os esforços em pesquisa de linguagens e pesquisa de otimização em coisas separadas, e fez cada um dos lados andar bem mais rápido.</p>
<p>Quem pesquisava linguagens não se preocupava como o binário ia ser cuspido, só em criar funcionalidades que facilitem a ergonomia do programador. E quem se preocupava no baixo nível do binário podia se concentrar em otimizar uma única linguagem intermediária que todos usam. Isso facilitou a vida de programadores de Mac pra criar código que funciona tanto nos Macs Intel quanto num iPhone ou iPad.</p>
<p>Do A4 até acho que o A7, a Apple foi refinando o design ARM dela e a fabricação ficou nas mãos da Samsung, mas no A8 de de 2016, que equipou os iPhone 6 e 6 Plus elas migraram pra TSMC, a mesma que faz os Ryzen pra AMD. Mais do que isso, essa era a 2a geração onde os chips da Apple pularam pra 64-bits e pegou todo mundo de surpresa. Em 2015 o mundo ainda tava na vergonha da transição lenta de 32 pra 64-bits e um mísero fone já tinha um chip de 64-bits e muita gente ficou coçando a cabeça, tipo, pra que 64-bits??</p>
<p>Do A7 foram 13 gerações até o atual A14 Bionic. 13 gerações diferentes sendo lançados um atrás do outro no espaço de 5 anos. Nesse meio do caminho o MacOS e o iOS e as ferramentas de desenvolvimento embaixo do XCode foram refinados constantemente. O ritmo deles tava muito bom. O que viria a ser A14X Bionic acabou sendo renomeado e virando o M1 que saiu no fim de 2020 e pegou o mundo de surpresa.</p>
<p>O plano B da Apple foi além, ela desenhou a própria CPU baseada no ARM Cortex e a GPU em PowerVR. E no lado de GPUs a Intel sempre teve a porcaria integrada dela que serve pra mostrar planilha, mas qualquer coisa mais complicada que isso espana. A AMD já tinha GPUs desde a era da ATI e investiu até a arquitetura Vega ficar muito melhor que a da Intel e mais próxima da NVIDIA.</p>
<p>Já que falamos do erro da Intel. Teve uma época que a AMD quase comprou a NVIDIA em vez da ATI, mas parece que o CEO da AMD na época tinha ego grande e o Jenssen da NVIDIA todo mundo sabe que tem um ego grande também daí o negócio não rolou. Imagina que time vermelho e time verde quase estiveram debaixo da mesma bandeira. A NVIDIA era outra empresa pequena que ninguém dava muita bola nos anos 90 e cresceu pro nível de hoje. Agora que vocês entenderam o resumo da história dos CPUs, vamos entender GPUs.</p>
<p>Nos anos 90 a gente tava começando a flertar com 3D no mundo não-profissional. Em tech a gente entendia a revolução da computação gráfica por causa de filmes e games. Isso era começo dos anos 90. Todo mundo ouvia que os efeitos mais sofisticados eram feitos em workstations como da SGI, a poderosa Silicon Graphics. No meio dos anos 90, começando a era de 32-bits com Saturn e Playstation, a gente lia em revistas tipo a Electronic Gaming Monthly que a Nintendo tinha uma parceria com a SGI pra lançar o Project Reality, que era o codinome do Ultra 64 que viria a ser o Nintendo 64.</p>
<p>A SGI ficou mais conhecida no meio dos gamers por causa da empresa Rare da Inglaterra, que tinha feito o inimaginável no fim da era dos 16-bits criando os sprites do jogo Donkey Kong Country usando workstations da SGI. A ideia era pré-renderizar todos os modelos e animações como bitmaps pra colocar no cartucho. Era um conceito ainda pouco explorado na época porque uma workstation Silicon Graphics não era menos que uns 100 mil dólares, em dólares dos anos 90!!</p>
<p>Isso catapultou a Rare pra se tornar um dos nomes mais conhecidos de produtores de games e o Donkey Kong pra se tornar o 3o jogo mais vendido do Super Nintendo, atrás só do Super Mario World e Super Mario All Stars, com o detalhe que ele saiu quase no fim da era de 16-bits, quando consoles de 32-bits como 3DO já tinham saído e Sega Saturn ia sair no mesmo ano. O Donkey Kong tinha gráficos que ninguém nunca tinha visto antes num videogame.</p>
<p>A Nintendo não foi boba nem nada e trouxe a Rare pra junto pra ajudar a hypar o Ultra 64. Eles fizeram jogos pra arcade como Cruisin&rsquo; USA e Killer Instinct. Mesma estratégia, não eram jogos totalmente em 3D como num Playstation e sim um híbrido. Mesma estratégia do Donkey Kong: pré-renderizar num Silicon Graphics e importar os sprites bitmaps no jogo pra dar impressão de 3D. Aí os gráficos ficavam impressionantes.</p>
<p>Quando Donkey Kong Country e Killer Instinct saíram, era fim de 1994. Virtua Racing, Virtua Fighter da Sega e Ridge Racer da Namco tinham acabado de sair em 92 e 93. Nessa época eles sabiam fazer polígonos mas sem texturas. A Namco começou a usar textura, depois o Virtua Fighter 2, e isso em hardware de arcade que era muito mais caro e mais potente. Num Sega Saturn os gráficos em 3D com texturas ainda tinham resolução muito baixa.</p>
<p>No horizonte tava o Playstation, mas com a propaganda e vendo no arcade o Killer Instinct, a gente chegava a acreditar que o Nintendo 64 podia ter níveis de Toy Story. Óbvio que a realidade foi bem menos do que o esperado. Tecnicamente o Nintendo 64 era melhor que o Playstation, mas ele escolheu usar cartuchos em vez de CD, então tinha bem menos espaço e era bem mais caro ter texturas, que ocupam muito espaço. Video então nem se fala. Por isso jogos de Nintendo 64 tem aparência mais pobre mesmo conseguindo ter mais resolução do que o Playstation.</p>
<p>Essa história é pra outro dia, o importante é entender o seguinte: a era 32-bits ia ser marcada por chips 3D. Em 92 esse movimento começou nos arcades. E pra fazer 3D rudimentar naquela época não tinha aplicativos de modelagem sofisticados nem nada, os modelos em 3D eram simples porque alguns eram desenhados na mão, vértice a vértice ajustando os números na munheca. Já existia CAD mas nada perto de 3D Max ou Maya.</p>
<p>O que a Rare fez com Donkey Kong ou Killer Instinct foi modelar e animar num Silicon Graphics de 100 mil dólares. Cada quadro de animação podia levar de segundos a minutos ou mais pra renderizar dependendo da complexidade. Não era em tempo real. Mas aí a demanda pra fazer 3D começou a aumentar porque filmes e games trouxeram essa possibilidade pra imaginação dos consumidores, então todo mundo que queria parecer moderno precisava ter alguma coisa em 3D. Music videos, comerciais, propaganda e tudo mais.</p>
<p>Nesse momento a gente já tinha passado pela revolução dos microcomputadores de 8-bits dos anos 70 até começo dos 80, os Apple II, Sinclair e a IBM entrou no páreo e revolucionou o mercado padronizando e abrindo a especificação das máquinas, assim qualquer empresa podia montar máquinas compatíveis com IBM PCs. A era dos 16-bits foi dos PCs. Mas nos micros a gente podia ligar em TVs analógicas, aquelas caixas com tubos enormes. E mesmo a resolução sendo uma droga, a qualidade de imagem sendo terrível, a gente tinha cores.</p>
<p>Os IBM PCs originais se tornaram famosos por trazer os monitores monocromáticos de fósforo verde ou âmbar da era dos terminais de mainframe que gigantes como a NEC, Burroughs ou a própria IBM fabricavam. Então PC e monitor monocromático era meio que a imagem padrão de uma máquina de trabalho. Bem o tipo que a gente via em bancos. Quem trabalha não precisa de cores. Uma cor é mais que suficiente.</p>
<p>Nem todo mundo achava isso e outros mercados de nicho já começaram a crescer, embora eu não tivesse acesso na época. Militares ou agências como a NASA, indústria em geral, empresas de engenharia tanto civil ou mecatrônica queriam dar um jeito de usar esse troço novo chamado microcomputador pra acelerar pesquisas, designs, projetos e tudo mais. Em particular programas de simulação e CAD começaram a aparecer. Mas os PCs do começo dos anos 80 ainda não eram suficientes.</p>
<p>A Intel daquela época e seus concorrentes como a Cirrus passaram a construir chips pra acelerar cálculos mais complexos. Números inteiros pequenos não eram suficientes, porque design e simulação precisavam de pontos flutuantes, números quebrados, e muitos deles. Pra isso surgiram os co-processadores matemáticos como o 80387. Naquela época processadores tinham funções simples, que recebiam um ou dois números e calculavam algum outro. Pensa tipo ADD de soma ou MUL de multiplicação e com esses co-processadores você ganhava instruções como FADD ou FMUL pra lidar com floats.</p>
<p>Em paralelo a isso, surgiram empresas como a ATI ou mesmo a gigante NEC do Japão pesquisando o próximo passo: monitores verdes são chatos, precisamos de mais cor, de mais resolução. Um consórcio chamado de VESA foi criado, a Video Electronics Standards Association. A ATI, ou Array Technologies Inc, foi um dos fundadores desse consórcio que servia pra especificar e padronizar componentes de monitores e gráficos. Hoje você associa o nome VESA ao padrão de parafusos atrás do monitor pra pendurar na parede, por exemplo, mas esse é só um dos padrões da VESA.</p>
<p>Com o consórcio formado, o interesse do mercado aparecendo, era hora de vitaminar os PCs verdes e aí foi surgindo o padrão CGA de 4 cores, que eu recomendo que você veja o video no canal do The 8-Bit Guy pra entender como funcionava. Depois veio o padrão EGA de 16-cores que eu mesmo não cheguei a ver na minha época e finalmente o supra sumo que tava na lista de coisas que eu mais queria em 1990: um monitor VGA colorido de 800 por 600 pixels e 256 cores!</p>
<p>Lembrem-se, micros antigos e videogames ainda estavam na faixa de resolução de 320 por 240 pixels, mesmo os da era de 32-bits como Playstation, eram só 256 por 224 pixels. Da geração de 8-bits até 32-bits de consoles, aumentou cores, aumentou recursos, mas a resolução não era muito mais que isso, principalmente porque numa TV normal de tubo, da época, não adiantava ir muito mais por causa do padrão NTSC ou PAL de TV.</p>
<p>Aliás, tentar entender os padrões antigos de TV analógica é um exercício de frustração. Porque a quantidade de frames por segundo é o número bizarro 29.97 quadros! Nem vou tentar explicar mas recomendo dar uma pesquisada pra entender sobre NTSC e PAL. O que você talvez não lembre é que o nintendinho de 8-bits e o Super Nintendo de 16-bits tinham a mesma resolução: 256 colunas por 240 linhas.</p>
<p>240 linhas é pouca coisa a mais que as 192 linhas horizontais do antigo Atari 2600. Um Playstation já suportava alguns modos a mais de resolução mas o normal dele era 256 por 224, menos linhas que um Super Nintendo. Ele tinha um modo mais esticado de 640 por 240 linhas e modo entrelaçado que dava pra ir até 640 por 480.</p>
<p>Pensa assim. Hoje você usa um monitor que a gente chama de Full HD, que tem 1080 linhas. HD são 720 linhas. E antes das telas planas tinha 480p que é progressivo, ou seja, cada quadro tem 480 linhas. Tinha 480i que é interlaced ou entrelaçado. Em modo entrelaçado você faz quadros com 240 linhas, mas um deles preenche as linhas pares e no quadro seguinte as linhas ímpares. Se você projetar elas rápido, na animação parece que tem 480 linhas, mas na verdade só tem metade. A vantagem era poder renderizar só metade do quadro de cada vez, a desvantagem é que em animações muito rápidas você ia ter um shimmer, dava pra ver os quadros desalinhando entre as linhas.</p>
<p>Mas esse era o modo máximo do primeiro Playstation. Não dava pra mostrar muito mais que isso numa TV comum. O conceito de HD, ou High Definition, que é só 720p, ainda não tinha aparecido pra gente. Mas em monitores de computador depois de 480 linhas já fomos pra 600 e até 1024 linhas bem rápido até. Nos anos 90 a gente já tinha quase o equivalente horizontal do Full HD de hoje, só que em formato mais quadrado de 4 por 3 de proporção, que era o comum. Wide screen ainda não era conhecido.</p>
<p>De qualquer forma, no mundo doméstico foi no começo dos anos 90 que começamos a entrar na era da multimídia, mas no mundo dos workstations como os IRIS da Silicon Graphics, custando dezenas de milhares de dólares, estava outro mercado de nicho que tinha empresas mais novas como a Sun Microsystems e a própria Microsoft querendo um pedaço. A SGI demorou muito pra se reinventar depois dos anos 80. Empresas como SGI e Sun, e a NEXT que o Steve Jobs fundou depois de sair da Apple em 1985, pensavam em workstations meio como a antiga IBM pensava em mainframes: como um conjunto único de hardware e software que eles precisavam controlar tudo.</p>
<p>Eu acho que a Apple é a única empresa que sobrou com essa filosofia ainda. Mas elas sofreram com o advento do PC porque em vez de ter que escolher um sistema inteiro proprietário de processadores, placas gráficas, monitores, sistemas operacionais, era mais acessível pegar pedaços de cada coisa separado de diversos fabricantes. Era mais difícil de montar e configurar tudo, mas o custo compensava. Processador da Intel, placa gráfica da Trident, MS-DOS ou OS/2 ou depois Windows e ir montando assim.</p>
<p>Eu não participei desse mercado de workstations então só sei o que ouvi falar, mas a SGI ia implodir sozinha depois de ter trabalhado no projeto do processador do Nintendo 64. Nessa época, do começo pro meio dos anos 90, empresas como a ATI já tinham entrado no mercado gráfico, ajudado a definir padrões da indústria pra coisas como monitor e tava começando a fabricar placas aceleradoras de 2D. Uma das famosas era a S3, acho que da VIA, e alguns já explorando a ideia de placas 3D.</p>
<p>Quem ia despontar do nada foi uma empresa que começou fazendo arcades, a 3DFx. A época era 1995, com Playstation, Nintendo 64 e o pobre Sega Saturn iniciando a era de 3D nos videogames. A Microsoft comprou uma empresa chamada RenderMorphics pra ter a tecnologia que viria a ser a base pro Direct3D. A Id Software, depois do sucesso absurdo do primeiro Doom tava criando uma engine 3D pra tirar o máximo dos Pentiums da época e suas instruções MMX. E a 3DFx trouxe a placa aceleradora Voodoo. Mais importante, trouxe a API Glide, um conjunto de instruções pra tirar proveito dessa placa 3D.</p>
<p>A 3DFx focou pesado em 3D. Naquela época o Windows ainda não era unanimidade, maioria dos games era lançado pra DOS, usando extensões como o 4Dos, a Microsoft tava atrasada pra entrar no vagão de 3D e a 3DFx tomou a dianteira com um conjunto de APIs mais fácil de programar. Mais importante: ela conseguiu conquistar ninguém menos que o lendário John Carmack e o Quake se tornou o killer app pra placas Voodoo. Sim, dava pra rodar só usando CPU Pentium porque o Carmack é um gênio, mas se ligasse no driver Glide com uma placa Voodoo o jogo ficava infinitamente mais bonito.</p>
<p>Mas a 3DFx foi o famoso caso da startup inovadora que cresceu super rápido e no seu pico começou a tomar decisões erradas, a prometer demais e entregar de menos, tentou mudar o business model e no final os concorrentes começaram a chegar.</p>
<p>Tinha vários fabricantes de placas competindo como a Matrox com a Mystique, a Cirrus Logic, as Rage da ATI, as TNT da NVIDIA. Assim como hoje havia várias OEMs. Por exemplo, pra comprar uma placa NVIDIA hoje, tipo minha RTX 3080, você escolhe OEMs como a EVGA, Gainward, Asus e outros. Em vez de comprar direto da NVIDIA, você vai num integrador. Minha RTX 3080 é da Gainward. É como nos computadores, onde você pode até comprar chips direto da Intel porque hoje ela é grande, mas normalmente você compra um computador de um OEM integrador como Dell ou HP ou Acer.</p>
<p>E naquela época tinha vários OEMs diferentes que você não ouve mais falar como a Diamond que vendia em nome da 3DFx. E um dos erros da 3DFx foi tentar cortar o intermediário e vender direto. Só que naquela época não tinha capilaridade de e-commerce e marketplace. A Internet tava só começando. Não existia nem Google nem Amazon ainda.</p>
<p>A Microsoft acelerou o Direct3D. Windows 95 foi um estrondoso sucesso e todo mundo ia querer jogos pra ele. A Voodoo 2 ainda era a mais performática, mas os concorrentes como a ATI e NVIDIA foram fechando a distância pouco a pouco. Some a isso as diversas decisões erradas e a 3DFx ia tomar o caminho da SGI. No fim dos anos 90 ambos iam desaparecer.</p>
<p>Se você quiser jogar jogos dos anos 90, que você pode baixar ou da Steam ou do GOG e rodar num DOXBox da vida, provavelmente vai precisar de um emulador do driver Glide. No caso de plataforma como a Steam, o jogo já vem com o DOSBox e os drivers todos. Nos anos 90 a 3DFx processava qualquer um que tentasse emular seus drivers, mas quando tava pra fechar eles resolveram abrir suas APIs como código aberto. E por isso hoje você tem projetos que traduzem as chamadas proprietárias da Glide pra outra biblioteca como DirectX.</p>
<p>A mesma coisa aconteceu com a SGI. Em Tech a gente sempre ouvia falar das workstation Silicon Graphics rodando sistema operacional UNIX que era o Irix e as APIs de programação pra 3D que era o IrisGL ou Integrated Raster Imaging System Graphics Language, que é mais uma abreviação inventada só pra formar a palavra Iris, claro. Mas o GL você já viu em outro lugar. O IRIS GL era a API proprietária da Silicon Graphics e um belo dia eles refatoraram essa API pra tirar coisas proprietárias e lançaram como um padrão aberto, a OpenGL.</p>
<p>A Glide acabou no passado e só existe hoje no mundo dos retrogames. E acredite, são muitas dezenas de games que suportavam Glide. Desde os Quakes e Unreal originais, FIFA, Need for Speed, Mechwarrior, vários jogos clássicos de Star Wars como X-Wing vs Tie Fighter. Todo jogo que não foi portado pra APIs mais modernas num remaster da vida, ainda roda emulando Glide. Depois de 1999 praticamente só sobrou DirectX e OpenGL e a era do dueto NVIDIA vs ATI.</p>
<p>A gente entrou no Século XXI com a ATI Radeon DDR vs a NVIDIA GeForce 2 GTS. As outras foram aos poucos desaparecendo, a VIA, Matrox, Cirrus. Eu lembro do começo dos anos 2000 ser bem pouco empolgante, em parte porque quase todos os concorrentes foram sumindo, em outra parte porque eu tava trabalhando pra caramba e sem tempo pra jogar. Mas o mundo dos games continuou crescendo. Foi o começo da era dos e-sports com Starcraft, o Counter Striker original, Unreal Tournament, Quake III.</p>
<p>Quando Jobs voltou pra Apple em 1997 e trouxe o know how da NEXT e tecnologias de workstation pros novos iMacs, ele também ajudou a empurrar a era de usar 3D nas interfaces gráficas de todo desktop com o framework Aqua, acelerado por placa gráfica. No mundo Linux a gente queria a mesma coisa e começou a ideia de compositors como o compiz. No mundo Microsoft eles tentaram o Aero Glass. Apple e mundo Linux começaram a adotar OpenGL nos sistemas operacionais. Microsoft obviamente continuou evoluindo, portando as coisas da antiga API de bitmaps GDI pra DirectX, e isso ia levar muitos anos. E fabricantes de placas como ATI e NVIDIA um funcionava melhor com OpenGL, outro com DirectX e ficava nessa disputa.</p>
<p>Eles foram tentando algumas coisas que não deu certo no mercado como o CrossFire da ATI e SLI da NVIDIA pra rodar mais de uma GPU na mesma máquina. Mas isso nunca foi estável e nem pegou muita tração. Ainda bem que já desistiram dessa ideia. Mas uma que pegou foi no lançamento da GeForce 3 que passou a suportar Pixel Shaders. Isso já existia no mundo das workstations mais caras, mas no mundo consumidor comum ainda era super novidade.</p>
<p>Falando bem a grosso modo, pensa em shaders como um filtro de Instagram ou plugins de Photoshop. Você parte de uma imagem e aplica um filtro pra dar blur. Ou pra mudar a cor. Ou pra criar efeitos. O termo shader nasceu na Pixar, na especificação do Renderman, o pai de todo software de modelagem e animação 3D como o Blender ou Cinema4D. Ed Catmull e os programadores originais da LucasArts que depois virou Pixar criaram toda a fundação da computação gráfica moderna. As estruturas de dados, os algoritmos, os workflows, tudo. E acho que shaders foi uma dessas coisas.</p>
<p>Eu não sou profissional dessa área mas resumindo você tem pixel shaders, como cel shading por exemplo, que a gente viu pela primeira vez em jogos como Jet Set Radio, que faz um modelo 3D ficar parecendo um desenho em 2D e você vê até hoje em jogos como Guilty Gear da Arc Software, pra mim a empresa que melhor domina essa técnica. Mas assim como Photoshop, você tem todo tipo de shader que é aplicado e transforma pixel a pixel de uma imagem.</p>
<p>Daí existem shaders 3D como os vertex shaders. Vertex ou vértice é uma estrutura de dados que contém metadados espaciais, posição, cor e muito mais. Todo mundo já viu um modelo 3D em wireframe, pense em vértices como cada um dos traços que monta o mesh do modelo. Um triângulo, por exemplo, tem 3 vértices e cada vértice é uma estrutura de dados. E em cima de cada vértice podemos aplicar filtros pra transformar esses vértices, os vertex shaders. O Hello World de vertex shader é o Gouraud shader, que é um método de interpolação.</p>
<p>Em poucas palavras você consegue pegar um modelo com poucos polígonos e ficaria aquele aspecto quadradão e aplicando esse shader ele alisa o shading e faz parecer contínuo, sem quebras bruscas, como se o modelo originalmente tivesse bem mais polígonos do que realmente tem. Então a gente consegue criar modelos menos quadrados sem aumentar a quantidade de polígonos, aplicando esse filtro em cada vértice. É uma das centenas de técnicas pra economizar processamento e ainda assim conseguir boa qualidade final.</p>
<p>Fora vertex shaders tem tesselation shader, geometry shader, primitive e mesh shaders e agora ray tracing shaders. Esses shaders são programas, código mesmo, e você escreve em linguagens parecidas com C como GLSL pra OpenGL ou HLSL pra DirectX, mas não é só isso. Você acha chato que hoje existe um monte de linguagens como Java, Python, Javascript, Rust, e por aí vai? Bom, existem diversas linguagens pra shaders também. A Apple tem o Metal Shading Language ou MSL, a Sony tem o PSSL que é o Playstation Shader Language, compatível com o HSLS da Microsoft. Isso no mundo de tempo real, pra renderização offline, tem o Gelato e o VEX da Houdini que se inspiram no original do Renderman da Pixar.</p>
<p>E existem vários tradutores de uma linguagem pra outra, tipo transpilers mesmo. Todos eles são parecidos com C ou C++. A Apple usa Clang do LLVM pra compilar o Metal Shading Language, que é baseado em C++14. Por isso é mais fácil usar ferramentas como Unity ou Unreal Engine. Porque eles vem com um editor visual de shaders baseados em Nodes. Se você já usou o sistema de Nodes de material do Blender ou o de Nodes de colorização do DaVinci Resolve, é parecido. Você vai montando visualmente uma árvore que depois é compilada num shader, sem precisar escrever uma linha de código.</p>
<p>Mas o importante é entender que shaders são aplicados per pixel ou per vertex. Pensa um jogo moderno rodando em Full HD, ou seja, 1920 por 1080 pixels. Um Pixel shader vai rodar nos 1920 vezes 1080 ou seja mais de 2 milhões de pixels. Pelo menos 30 a 60 vezes por segundo. Então com a GeForce 3 em diante as GPUs ficaram velozes ao ponto de processar 2 milhões de pixels num shader em menos de 16 milissegundos por frame, até menos que isso porque nesse tempo pode ser processado múltiplos shaders.</p>
<p>Calcular o shader pra cada pixel é uma tarefa altamente paralelizável e é isso que faz uma GPU. Em vez de poucos cores ou núcleros muito rápidos, como 4 cores de 4Ghz num Intel i5. Uma GPU como minha RTX 3080 vai rodar entre 1.4 a 1.7 Ghz. Parece pouco comparado com minha CPU i9 de 8 cores que pode ir até perto de 5Ghz cada um. Só que essa RTX tem quase 9 mil shading units, micro-cores pra rodar shaders. Basta eu quebrar minha imagem de 2 milhões de pixels em batches pra dividir pros 9 mil shading units.</p>
<p>Processar pixels e processar vértices é algo facilmente paralelizável, porque eu posso rodar o shader pra cada pixel individualmente em paralelo, sem precisar esperar. Numa CPU Intel com 8 cores eu quebraria os 2 milhões de pixels em 8 batches de 250 mil pixels cada. Ia levar ordens de grandeza mais tempo pra processar tudo. CPUs são boas pra processar linearmente, trabalhos grandes sem parar. GPUs são boas pra processar milhares de pequenos trabalhos em paralelo. Por isso elas se complementam. Nem todo trabalho dá pra ser paralelizado.</p>
<p>Quando DirectX chegou lá pra versão 10 e a NVIDIA lançou a GTX 280 eles já estavam começando a empurrar outro conceito. Em vez de chamar as coisas de shaders e os cores de shading unit, começaram a falar mais sobre unificação dos shaders e o conceito de GPGPU ou GPU de uso geral. Fica confuso porque em vez de falar de pixels ou vértices a gente passa a falar em stream de dados, uma corrente contínua de estruturas como pixels ou qualquer coisa que vai passar por esse monte de unidades de processamento, que antes era shading unit e agora, no caso da NVIDIA, chama de CUDA Cores ou, no caso da AMD, de Stream Cores. E em vez de passar por um programa pixel shader ou vertex shader, o nome mais moderno é compute kernels ou só kernels.</p>
<p>Pensa hoje numa CPU normal. Se você tem um arquivão gigante pra processar, por exemplo fazer limpeza removendo ou adicionando caracteres em cada linha. Você abre o arquivo e faz um loop pra ler linha a linha. E dentro do loop <code>while</code> ou <code>for</code> vai ter um código pra manipular o string. O programa de um shader ou kernel é só o que vai dentro desse <code>for</code>. Você não controla o loop, quem controla é a GPU. Você só fala &ldquo;tó o arquivão, e toma o código, se vira&rdquo;, ele vai jogar cada linha num CUDA core e seu kernel vai processar a linha que receber naquela core. Até pouco tempo atrás a linguagem de kernels ou shaders não tinha nem condicionais como <code>if-else</code>.</p>
<p>Daí você tem funções gerais da GPU como os famosos <code>map</code> e <code>reduce</code> derivadas de linguagens funcionais. Com <code>map</code> você diz qual shader rodar pra cada input num core e <code>reduce</code> pra agregar o resultado de um batch de processamento num stream menor. Tem scan filter pra remover alguns resultados. Tem scatter, gather - que é o inverso -, sort, search. Mas no final são técnicas de pixel e vertex shaders com nomes mais atraente pro povo acadêmico de computação.</p>
<p>Quem pesquisava computação distribuída e paralela, cientistas de dados, povo que já usava coisas como Fortran entenderam que dava pra usar a GPU pra programar essas tarefas matemáticas paralelizáveis pra coisas como machine learning, por exemplo. A NVIDIA enxergou o caso de uso e tornou as APIs mais amigáveis pra aplicações fora do mercado de gráficos e games. Hoje você vai achar extensões pra várias linguagens, de C a Fortran, pra dar acesso a criar kernels e rodar nos CUDA Cores.</p>
<p>Como tudo em computação, sempre tem o jeito do fabricante e o jeito mais compatível com todas as alternativas. Você pode baixar as bibliotecas de CUDA da NVIDIA se tiver uma placa GeForce. Mas se quiser ser compatível com as Radeon da AMD talvez prefira usar um framework como OpenCL pra desenvolver kernels que podem ser compilados pra shaders pra ambos.</p>
<p>Por muito tempo a Apple desenvolvia a parte gráfica com OpenGL e depois a parte computacional pra GPU com OpenCL. Programas como Blender pra modelagem 3D permitem escolher interfacear com OpenCL ou direto CUDA, assim como num game você podia escolher usar os drivers de Glide, DirectX ou OpenGL.</p>
<p>Em 2014 a Apple começou a mudar a estratégia. O problema é que depois de quase duas décadas, plataformas como OpenGL e DirectX cresceram muito em escopo, ficaram bloated mesmo. Eles não são só interfaces pra falar com a GPU, elas controlam muito mais, o estado da renderização, a configuração dos pipelines. É como um framework web que cresceu demais e agora é pesado pra fazer sites pequenos. É o destino de todo software que faz sucesso e dura tempo demais.</p>
<p>Como as tecnologias de compiladores melhoraram drasticamente graças ao LLVM e compiladores como Clang, a Apple resolveu tirar o intermediário do caminho e criou uma API moderna, orientada a objetos, que é mais baixo nível e, mais importante, usa muito menos recursos do que OpenGL. Esse é o Metal. Você precisa entender um pouco mais sobre shaders, pipelines, mas a grande vantagem é que em Macs e iOS a performance é nitidamente maior tirando OpenGL e OpenCL da jogada.</p>
<p>Do lado de fora da Apple também tivemos mudança semelhante. Surgiu a API Vulkan, do grupo Khronos, dois anos depois, em 2016. Ele parece ser um pouco mais baixo nível até do que o Metal da Apple, também com objetivo de usar menos recursos quanto possível pra ser performático e diferente da Apple tem objetivo de ser independente de plataforma pra poder rodar em Android e qualquer coisa com uma GPU.</p>
<p>Pra ilustrar pense assim. Você é um desenvolvedor de jogos ou qualquer aplicativo gráfico, tipo um Photoshop. Se programar direto pros drivers da NVIDIA ou AMD, vai ficar bloqueado em um ou outro. Se usar Metal só vai rodar só em Mac e iOS. Se usar DirectX vai rodar só em Windows e XBox. Agora você tem algumas alternativas.</p>
<p>Num mundo ideal você vai programar usando as APIs do Vulkan. Daí pode usar um projeto com o MoltenVK que facilita compilar pras chamadas do Vulkan chamarem o Metal e converter a linguagem intermediária de shaders do Vulkan, o SPIR-V pro MSL que é o Metal Shading Language.</p>
<p>Se for um aplicativo que já existe escrito em GLSL de OpenGL dá pra usar o projeto Angle do Google, o Almost Native Graphics Layer Engine que traduz OpenGL pra Vulkan e outros backends. Tem um projeto ainda inacabado que é um fork desse Angle, o MetalAngle que adiciona backend de Metal. Ele suporta fazer aplicativos antigos escritos em OpenGL ES - que é um sub-conjunto menor do OpenGL) pra rodar em Metal sem alterar muita coisa, porque vai traduzir chamadas de OpenGL em chamadas de Metal.</p>
<p>E finalmente se for um aplicativo que já existe escrito em DirectX 9 a 11, dá pra usar o DXVK que traduz chamadas de DirectX pra chamadas de Vulkan. A própria Microsoft tava atenta a essas mudanças e por isso o DirectX 12 tenta ser uma alternativa um pouco menos pesada e mais perto do metal. DirectX é uma API mais madura, menos difícil de aprender e usar do que Vulkan, que é um pouco mais baixo nível.</p>
<p>Se não tá claro, um OpenGL é como se fosse Java. Antigo, estável mas pesado. Metal é como se fosse Objective-C ou Swift mesmo, mais baixo nível, mais leve. Um DirectX até o 11 é como se fosse C#, mais fácil de usar, mais estável mas mais pesado. Vulkan é como se fosse C++. E o DirectX 12 é como se eles pulassem de C# pra C++ também. É meio que o caminho inverso de sair de uma plataforma de mais alto nível pra ficar no baixo nível.</p>
<p>Mas isso é no nível das APIs, ainda tem os shaders. Shaders pra OpenGL são escritos numa linguagem de mais alto nível (pensa um Javascript) que é GLSL. Em DirectX é o HLSL, também de mais alto nível. A sigla HLSL justamente é High Level Shading Language. O DirectX compila o HLSL em um bytecode intermediário - tipo bytecodes de Java - que é DXBC ou DirectX ByteCode. Já o Vulkan lida com binários intermediários um pouco maiores e com mais metadados, que é o SPIR-V, foi originalmente feito pra OpenCL.</p>
<p>Se você já se aventurou em rodar um emulador de Wii U como Citra ou mesmo rodar Steam no Linux como eu mostrei no começo, já deve ter esbarrado ou com stutters, engasgadas ao jogar. Ou da primeira vez teve que esperar uma hora compilar “shaders de Vulkan”, e agora você sabe porque.</p>
<p>O esquema de shader do OpenGL era chatinho porque os shaders eram entregues em formato texto, daí cada driver de OpenGL precisava embutir literalmente um compilador pra compilar o shader antes de mandar pra GPU. Já drivers de DirectX e Vulkan usam um JIT, ou just in time compiler, que pega esse bytecode intermediário e transforma no binário final pra GPU, que é um passo menos complexo do que um compilador inteiro.</p>
<p>Quando você roda Steam no Linux usando a camada Proton - que já vou explicar - ele provavelmente vai usar o driver de Vulkan pra falar com a GPU. Mas a maioria dos jogos de PC ainda dependem do DirectX. Então ele usa o projeto DXVK pra converter chamadas de DirectX ou DX pra Vulkan ou VK, por isso chama DXVK. Mas ainda tem os shaders em DXBC. Antes de mandar pro Vulkan, o DXVK vai converter o bytecode de DXBC em SPIR-V e por isso ou o jovo vai ficar dando travadinhas no começo, que é quando os shaders são convertidos em tempo real ou, o jeito mais prático, o jogo vai primeiro checar se tem os shaders de Vulkan no cache. Se não tiver, vai converter todos antes de abrir o jogo justamente pra não ficar travando. E agora você sabe porque isso existe.</p>
<p>Por muitos anos em PC a preferência era fazer jogos usando DirectX, primeiro porque é mais conveniente porque em Windows todo mundo vai ter instalado. Segundo porque era mais moderno, mais fácil de aprender e com mais suporte de documentação, ferramentas e tudo mais comparado a OpenGL que a essa altura praticamente só a Apple usava. Mesmo assim, se você quisesse fazer um aplicativo ou jogo que funcionasse em tudo, era melhor escolher OpenGL, ou se tivesse grana, implementar e dar suporte pros dois.</p>
<p>Mas aí a Apple quebrou as pernas do povo de OpenGL migrando pra Metal. E o Vulkan quebrou o resto das pernas oferecendo um padrão melhor e com mais suporte. A Microsoft foi o marido traído e correu pra entregar o DirectX 12 como alternativa, se o problema fosse só performance. Com o Vulkan ficando mais estável e completo eles querem criar uma Meta API que vai servir pra escrever tanto pra Vulkan quanto suportar Metal e DirectX por baixo. Ou seja, a API que vai unificar todas as APIs.</p>
<p>Na verdade, a história toda é mais ou menos assim. Lá em 2009 quando o grupo Khronos tava estudando como trazer 3D nativo pra navegadores com a ajuda da própria Apple, Google, Mozilla e Opera, eles tavam chegando no WebGPU que ia usar OpenGL em Macs e Linux e DirectX no Windows. Chamadas de WebGL seriam convertidas pra equivalente em DirectX e transpilers seriam usados pra converter os shaders GLSL em HLSL. Não sei se foi aí que nasceu o projeto Angle do Google que funciona hoje pra Chrome e Firefox pra justamente isso.</p>
<p>O problema é que drivers OpenGL pra Mac e Linux eram muito ruins. Um dos muitos problemas foi o que falei do GLSL, que os drivers já não eram grande coisa, cheio de bugs, e com GLSL precisava ainda ter um compilador embutido. Imagina a complexidade e tanto de bugs pra manter tudo isso com pouca gente. DirectX 10 tava muito na frente tanto em estabilidade quanto facilidade de uso. Por isso todo mundo programava jogos só pra DirectX e raramente você via jogos em OpenGL bons pra Mac.</p>
<p>Aí em 2013 a AMD desenvolveu uma API de mais baixo nível chamada Mantle como alternativa pra DirectX e OpenGL e doaram a implementação pra Khronos que usou de base pra fazer o Vulkan. Depois, com o Metal funcionando melhor que OpenGL em MacOS e iOS e o Vulkan funcionando bem em Linux e Windows, dá pra voltar pra ideia do antigo projeto WebGPU: tirar OpenGL e DirectX dos planos e mirar em suportar Metal e Vulkan.</p>
<p>A ideia é que WebGPU vire uma API única que vai facilitar a vida de pequenos programadores independentes, estúdios de games que queiram fazer aplicativos e jogos pra todas as plataformas com uma API única. Ainda não estamos lá, mas enquanto isso pra WebGL existe o projeto Angle e o MetalAngle, e obviamente as engines de jogos como Unity e Unreal que dão suporte a todas as plataformas.</p>
<p>Aliás, a reunião da Khronos que iniciou os trabalhos pro Vulkan foi nos escritórios da Valve. Ninguém tem mais interesse em aumentar o mercado, fazendo o Steam e todos os jogos saírem das porteiras do Windows, do que a Valve. O projeto Vulkan possibilita fazer uma coisa que a comunidade open source vem tentando faz anos: conseguir rodar DirectX. O problema é que DirectX é gigante, não é fácil de reimplementar via engenharia reversa e muito menos com performance.</p>
<p>Quem é de Linux conhece o projeto Wine, sigla pra Wine is not an Emulator. A ideia em si é simples: vamos pegar um programa de Windows, digamos Notepad. Quando ele pedir pro Windows pra desenhar uma janela, a gente intercepta essa chamada, e traduz no equivalente no Linux. E vai fazendo isso chamada a chamada até o programa acreditar que tá rodando no Windows. Essa ideia começou nos anos 90 e continua até hoje e o objetivo era um dia poder fazer o Linux substituir o Windows como sistema operacional, porque o maior motivo que bloqueia as pessoas de saírem do Windows é que nenhum programa que eles precisam existe lá.</p>
<p>Quando Java saiu o mundo achava que todo mundo ia escrever tudo em Java e isso resolveria o problema. Ficou só na intenção mesmo porque não dá pra escrever tudo numa linguagem só. Java era boa pra algumas coisas, mas péssima pra outras. Ela é basicamente uma máquina virtual, então desperdiça tudo que o sistema operacional já faz e tem muita redundância. Antes que alguém diga que Android é em Java, não é. A sintaxe da linguagem é derivada de Java, mas depois de gerar bytecodes o Dalvik usa um compilador pra gerar binário nativo. Então não roda numa Java Virtual Machine. Ela só se aproveita do ferramental de Java pra desenvolver.</p>
<p>Não tem jeito, pra aplicativos e jogos precisa ser perto do metal. Mas traduzir o Windows inteiro é inviável. Exigiria milhões de horas homem e não ia resolver porque a Microsoft não tá parada  esperando, todo dia sai uma atualização nova pra Windows que muda alguma coisa. É uma corrida infinita de gato e rato.</p>
<p>Em 2018 só tem duas alternativas: rodar o Windows inteiro de verdade numa máquina virtual e passar a GPU da máquina de verdade pra dentro da máquina virtual. Mas isso não resolve também. Como é o Windows de verdade, você precisa pagar licença pra Microsoft. E mesmo em 2018, mesmo Wine tendo avançado bastante e conseguir rodar alguns aplicativos mais de versões mais velhas, jogos é complicado porque DirectX é um dos componentes mais complexos do Windows.</p>
<p>Mas com o Vulkan funcionando bem e agora tendo um framework gráfico decente pra todas as placas, isso começou a dar idéias pra alguns programadores. Assim como na história da 3DFx, o primeiro passo é ter APIs decentes, melhores que a antiga OpenGL. Primeiro surgiu um projeto chamado VK9 com o objetivo de traduzir chamadas de DirectX 9 pra Vulkan.</p>
<p>Inspirado nisso outro programador, Philip Rebohle desenvolveu o DXVK que traduz chamadas de Direct 9 até 11. E quando ele anunciou que o projeto dele já permitia rodar o jogo Nier Automata, a Valve entrou em contato e contratou ele. Isso foi Janeiro de 2018. Construir um DirectX em código aberto do zero era muito difícil, mas fazer só uma casca que é só um adaptador da API do DirectX pra API do Vulkan, era bem mais possível.</p>
<p>Agora a Valve tinha as peças que precisava: Wine quase funcionando pro básico, Vulkan como driver de alta performance pra GPU no Linux e Windows, e o DXVK como camada de tradução que realmente funciona. Com isso eles começaram o projeto Steam Play e o projeto Proton. O Proton é um fork do Wine com diversos patches pra melhorar compatibilidade particularmente com jogos, e vários ajustes de qualidade de vida, modo tela cheia que funciona direito e patches específicos pra ajustar jogo por jogo.</p>
<p>E foi assim, nos últimos 2 anos eles trabalharam bastante. E finalmente temos jogos de Windows novos rodando em Linux quase com a mesma performance e até melhor em alguns casos. E outros desenvolvedores entraram na festa, surgiram forks de Proton e um dos mais famosos é o Proton GE do desenvolvedor Glorious Eggroll que customiza o Proton da Valve pra funcionar ainda melhor, corrige bugs, adiciona patches pra mais jogos e por aí vai.</p>
<p>Mas a novela não acabou. A NVIDIA é notória e reconhecida como não sendo muito legal com a comunidade. O suporte no Windows hoje até que é de boa, dá pau de vez em quando mas menos que antigamente. Mas em Linux ainda é um pé no saco. Em Linux temos o projeto Mesa que é o driver pra placa de video integrada da Intel, a AMD suporta o mesmo projeto pras placas Radeon. Mas óbvio, só a NVIDIA quer ser a diferente e só oferece os drivers em binários fechados. Tem uma tentativa de fazer drivers de código aberto via engenharia reversa chamada Nouveau, mas ela dificilmente vai ser tão performática e compatível quanto os drivers da própria NVIDIA. Mesmo problema do Wine.</p>
<p>Muitas distros e pessoas que são mais xiitas com código aberto e não admitem instalar binários proprietários ficam de fora do mundo NVIDIA porque o driver Nouveau funciona mas pra pouca coisa, em particular jogos não vão funcionar. Pra piorar, se você quer fazer alguma coisa de machine learning, deep learning ou qualquer coisa em placas NVIDIA vai precisar do pacote gigante que é o CUDA, que também é proprietário. Então, se você valoriza software livre, sua única opção é comprar AMD porque os drivers Mesa são todos abertos.</p>
<p>Quem gosta de NVIDIA vai precisar usar os drivers proprietários. Em desktop não tem nenhum problema. Na maioria das distribuições o pacote que se chama só <code>nvidia</code> e <code>cuda</code> devem funcionar. Pra placas mais antigas tem drivers legados com nomes como <code>nvidia-39xx</code>. Um dos problemas é que no mundo Linux estamos querendo mudar do antigo servidor X.org pra Wayland. X é o sistema gráfico do Linux que é usado por gerenciadores de desktop como GNOME ou KDE pra desenhar a interface gráfica.</p>
<p>O X é um dos mais antigos legados do mundo Linux. Grande, complexo, monolítico, que faz muito mais do que deveria. O exemplo clássico é que tem tipo lógica de impressora embutida no servidor gráfico. O Wayland é a versão reescrita, moderna, leve e mais fácil de trabalhar. Se você usa só placa integrada da Intel ou AMD, já pode usar Wayland hoje. Mas por causa dos drivers proprietários da NVIDIA que só suportam X.org, a gente não pode migrar. Dizem que a NVIDIA vai passar a dar suporte a Wayland em breve, mas é um dos problemas do código não ser aberto. O suporte só vai vir se a NVIDIA resolver que quer.</p>
<p>E ainda temos uma segunda complicação. Eu falei lá no começo do video que testei o Steam no meu notebook Thinkpad X1 Extreme com GTX 1050 Max Q como GPU discreta. Meu notebook, como todos os outros modernos com GPU NVIDIA discreta, tem 2 GPUs: a integrada da Intel e a da NVIDIA. O monitor do notebook tá sempre ligado no da Intel, então a GPU da NVIDIA não tem como mostrar no monitor.</p>
<p>Claro, uma GPU que não consegue mostrar no monitor poderia ser meio inútil pra games. Na realidade existe uma ponte entre a GPU da Intel e da NVIDIA que é chamada de Optimus. É uma tecnologia pra permitir usar as duas GPUs. Quando estamos usando a da Intel, a da NVIDIA fica em modo de economia de energia. Mas quando mandamos trocar, a GPU da Intel passa a fazer a ponte com a da NVIDIA, que vai renderizando e copiando os frames pra da Intel mostrar na tela.</p>
<p>O processo de ter um servidor X renderizado por um GPU e poder escolher outra aplicação dentro daquela tela de X pra ser renderizado por outro GPU é o processo de renderização offline batizada de Prime. Óbvio, a ponte chama Optimus e o processo chama Prime. E por isso nasceu outro projeto depois batizado de Bumblebee.</p>
<p>Por padrão tudo roda na GPU da Intel, mas usando um comando no terminal antes do programa como o antigo <code>optirun</code> a gente consegue fazer esse programa em específico sozinho rodar na GPU da NVIDIA. Daí o Bumblebee começou usando VirtualGL e depois migrou pra biblioteca <code>primus</code> pra copiar frames da memória da GPU da NVIDIA pra GPU da Intel, pra daí mostrar na tela.</p>
<p>Se você tem a versão VirtualGL do Bumblebee pode rodar programas na GPU discreta com o comando <code>optirun</code> na frente. Mas na versão nova com <code>primus</code> precisa rodar com <code>primusrun</code> ou chamar o <code>optirun</code> com o parâmetro <code>-b primus</code> pra indicar que é pra usar com primus. Fica a dica porque se você pegar tutoriais antigos vai ver o comando <code>optirun</code> se ver outros tutoriais um pouco menos antigos vai ver <code>primusrun</code>. E ambos podem ser considerados antigos hoje. O que estou explicando neste video só vale pra 2021.</p>
<p>O Bumblebee tinha outros subprojetos como o <code>bbswitch</code> que desliga a GPU da NVIDIA se ninguém estiver usando pra não ficar consumindo bateria à toa, que é o motivo de ter esse esquema todo. E com os drivers mais novos da NVIDIA talvez não seja mais necessário nem instalar o bbswitch. Então teste primeiro pra ver se sua bateria tá indo pro saco muito rápido. Só se estiver pesquise sobre o bbswitch, que é um módulo pra kernel do Linux e por isso sua kernel também precisa suportar DKMS.</p>
<p>Pra complicar o jeito mais novo de usar Optimus parece que chama Prime Offload Render. Pra isso a gente não instala bumblebee e vez disso deve ter um novo pacote chamado <code>nvidia-prime</code> pra instalar na sua distro e outro que provavelmente se chama <code>optimus-manager</code> ou <code>nvidia-optimus-manager</code>. Eu digo “provavelmente” porque o nome desses pacotes pode variar de distro pra distro. E isso só funciona se você tem um driver NVIDIA maior que a versão 435. Se eu não entendi errado, nesse esquema, em vez de <code>optirun</code> ou <code>primusrun</code>, no pacote <code>nvidia-prime</code> vai ter o comando <code>prime-run</code>, se estiver rodando em modo híbrido.</p>
<p>Além do modo híbrido, você tem a opção de usar tudo na GPU discreta, como se não tivesse a integrada da Intel. Pra isso você usa o optimus-manager pra escolher qual quer usar, tem que fazer um logout e login de novo (e se estiver usando GDM como gerenciador de login precisa instalar a versão <code>gdm-prime</code> também), mas enfim, depois de logar vai estar tudo na GPU da NVIDIA que vai renderizar e copiar os frames da memória dele pra memória da placa da Intel, cujo único trabalho vai ser mostrar esses frames no monitor de verdade. Então a placa da Intel vira só um controlador glorificado e por isso disse <code>prime-run</code> só no modo híbrido.</p>
<p>Com o driver novo, sem precisar de Bumblebee e estando em modo híbrido, pra mandar um aplicativo dar offload pra GPU discreta é só setar essa variável de ambiente NV Prime Render Offload pra 1. Pra isso o ambiente tem que estar usando Vulkan. Acho que só de instalar o driver da NVIDIA já instala suporte a Vulkan. Um probleminha que pode passar batido é que essa diretiva de render offline vai carregar o Vulkan que, por sua vez, vai pegar o primeiro GPU que achar e pode ser a da Intel, então precisa de uma segunda variável pra dizer que é pra carregar só na NVIDIA que é VK de Vulkan Layer NV optimus Nvidia Only. Se eu não esquecer vou deixar links na descrição do video abaixo pra vocês pesquisarem em mais detalhes.</p>
<p>(configuração gdm-prime)</p>
<p>Por último, a razão de fazer toda essa zona em notebooks é pra economizar bateria, tentar fazer a GPU discreta ficar quietinha sem consumir energia à toa. O ideal é usar a GPU integrada da Intel que é fraquinha, mas pra renderizar nosso desktop e janelas tá mais que bom. Mesmo pra assistir video como YouTube e Netflix da vida, a placa integrada é mais que suficiente porque ela tem instruções pra decodificar codecs de video como H.264 direto em hardware.</p>
<p>Depois que configurar tudo, basta usar o comando <code>optimus-manager</code> e passar o parâmetro <code>--status</code> pra ver em que mode você tá. A recomendação é testar o modo híbrido primeiro, que significa que você vai ficar usando a da Intel como GPU primária mas vai deixar o driver da NVIDIA pré-carregado e pronto pra renderizar um aplicativo em offline se a gente executar ou com prime-run ou com a variável de NV Render offline.</p>
<p>Problema de deixar o driver carregado é confiar se ele vai ou não gerenciar a GPU pra deixar ela inativa, sem usar energia, quando ninguém estiver usando. Teoricamente era pro driver da NVIDIA fazer isso sozinho. Caso consiga, tem que usar alguma coisa como o módulo de kernel <code>bbswitch</code> que falei antes. Problema desse tipo de coisa é ele forçar desligar a GPU discreta e se alguma ferramenta por acaso tentar acessar ela, pode dar pau.</p>
<p>Se você ver que a bateria continua não durando e o bbswitch não for bom pro seu fluxo de trabalho, a outra utilidade do optimus-manager é mudar pra usar só a placa integrada e só quando precisar, tipo abrir um editor de video ou algo assim, daí você manualmente usa ou a linha de comando ou os aplicativos gráficos como o optimus-manager-qt pra trocar entre a integrada e a discreta. Inconveniente é que precisa dar logout e login pra trocar entre um e outro, mas pelo menos você sabe exatamente se tá ou não desligado, especialmente se bateria for um problema.</p>
<p>Eu espero que o povo de AMD precise configurar menos coisas que isso. Em 2021 a solução da NVIDIA ainda não é amigável o suficiente. Tá melhor que três anos atrás. Mas como depende totalmente da boa vontade deles, ainda vamos ter que esperar mais pra ter um suporte mais estável pra Linux. Pra ser justo, eu fiquei com vontade de documentar isso hoje porque comecei a testar Optimus num Dell XPS lá por 2017 ou algo assim e aí o processo era com Bumblebee e optirun e me confundiu quando fui usar hoje. Quem quiser ver minha configuração daquela época vou deixar os links na descrição abaixo.</p>
<p>Fazendo tudo isso, agora eu tenho um Linux com drivers NVIDIA configurado pra rodar com Prime e Vulkan. Com meu Steam mais Proton e DXVK consigo rodar a maioria dos jogos que eu quero. Aliás, só faltou falar rapidinho que se como eu, você precisar de suporte pro controle sem fio de XBox One, veja o projeto <code>xow</code>. Ele precisa ficar carregado ativo num terminal pra ficar escutando o dongle de USB que é como o controle se conecta. Ou subir como um daemon, que eu não recomendo porque ele é meio bugado e começa a consumir muita CPU do nada e você quer matar ele fácil depois de jogar. Links nas descrições.</p>
<p>Eu falei bastante coisa, mas o objetivo foi mostrar como um simples ato de carregar um jogo no Linux envolveu mais de 20 anos de história com diversas empresas que surgiram e sumiram e diversas tecnologias que foram inventadas. E como um workstation Silicon Graphics de mais de 100 mil dólares no começo dos anos 90 hoje seria muito mais fraco que qualquer smartphone barato Android. Em pouco mais de 20 anos fomos de 100 mil dólares pra menos de 100 dólares.</p>
<p>É assim que mercados funcionam. Ninguém em 1992 poderia comprar um workstation desses, era inacessível. E quem comprava não era pra ostentar, era pra projetos militares, da NASA ou de entretenimento. Projetos de milhões de dólares, onde o custo de 100 mil não é tanto assim. Com bons resultados a demanda aumenta, e aumentando a demanda começam a aparecer concorrentes com alternativas. A Sun, a ATI, a 3DFx, a própria Microsoft. E pouco a pouco cada componente que fazia um Silicon Graphics ser especial foi sendo substituído por versões mais acessíveis.</p>
<p>A SGI cometeu um erro atrás do outro, mas deixou o OpenGL como legado. Na mesma época apareceu uma 3DFx que inovou em muitas áreas, inventou técnicas como soft shadow, reflexão, motion blur, e no final também cometeu vários erros e terminou comprada pela concorrente menor, a NVIDIA, e deixou pra trás o legado da Glide. A ATI, que inovou antes de todo mundo trazendo cor e resolução pros computadores verdes, competiu com NVIDIA, 3DFx e no final seu legado acabou dentro da AMD, que se tornou a maior rival tanto da Intel quanto da NVIDIA hoje, mantendo a dinâmica da concorrência em pé.</p>
<p>A própria Intel, no alto da sua arrogância, rejeitou o iPhone, o que abriu as portas pra Samsung entrar como concorrente mais rápido, e tudo isso levou de volta à ideia original da Silicon Graphics e da Sun: usar chips RISC baseados em ARM. Tudo dá voltas.</p>
<p>Um dos fundadores da Silicon Graphics foi o professor de Stanford, Jim Clark. Stanford que foi onde Steve Jobs e vários outros famosos estudaram. Depois da SGI, Jim Clark se uniu a outros estudantes com ideias inovadoras, como Marc Andressen, e juntos fundaram a Netscape, o primeiro navegador de sucesso comercial. Netscape que seria depois aberto como software livre e renomeado pra Mozilla Firefox. E hoje é o OpenGL que veio da SGI entrando nos navegadores de novo com WebGL e WebGPU.</p>
<p>Mas a maior moral da história é que muita gente que se acha super profissional ou acadêmico gosta de esnobar de gamers, mas hoje vocês aprenderam que quando um cara de data science falar em kernels, CUDA cores, e bla bla, na verdade ele tá falando de shaders de placa de vídeo. Um compute kernel de data science é um pixel shader. Se os elementos mudam de posição no grid é um vertex shader. As mesmas técnicas usadas pra fazer animação e games é a fundação desse movimento atual de data science, machine learning, inteligência artificial.</p>
<p>De perguntas simples do tipo: como simular luzes pintando as cores de alguns pixels pra ser mais claro e outros pra serem mais escuros, e fazer esse modelo 3D de poucos polígonos parecer mais liso, saem as atuais perguntas de deep learning, inteligência artificial e tudo mais. Tudo é conectado. E se esse video não for a maior tangente que alguém já fez, não sei qual é. Eu saí da configuração de jogos no meu notebookzinho e pensei, o que alguém precisa saber pra realmente entender o que significa estar jogando esses jogos? E isso virou o resumo de mais de 30 anos de história. Se ficaram com dúvidas mandem nos comentários abaixo, se curtiram o video deixem um joinha, assinem o canal, cliquem no sininho e não deixem de compartilhar o video pra ajudar o canal. A gente se vê, até mais!</p>
]]></content:encoded><category>linux</category><category>games</category><category>hardware</category><category>akitando</category></item><item><title>[Akitando] #89 - Introdução a Videogames e Emuladores</title><link>https://akitaonrails.github.io/2020/12/22/akitando-89-introducao-a-videogames-e-emuladores/</link><guid isPermaLink="true">https://akitaonrails.github.io/2020/12/22/akitando-89-introducao-a-videogames-e-emuladores/</guid><pubDate>Tue, 22 Dec 2020 10:30:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/vUqLLpUJ47s"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Finalmente vou contar sobre um dos assuntos que eu mais gosto: videogames e emuladores. E aproveitar os episódios que eu vim fazendo sobre Introdução a Computadores pra adicionar mais alguns conhecimentos interessantes pra quem é programador entender como essas coisas funcionam.&lt;/p&gt;
&lt;p&gt;ERRATA: eu falo que PPSSPP emula PS Vita mas na verdade é o PSP.&lt;/p&gt;
&lt;p&gt;Links:&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/vUqLLpUJ47s"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Finalmente vou contar sobre um dos assuntos que eu mais gosto: videogames e emuladores. E aproveitar os episódios que eu vim fazendo sobre Introdução a Computadores pra adicionar mais alguns conhecimentos interessantes pra quem é programador entender como essas coisas funcionam.</p>
<p>ERRATA: eu falo que PPSSPP emula PS Vita mas na verdade é o PSP.</p>
<p>Links:</p>
<ul>
<li>Understanding the ELF File Format (<a href="https://linuxhint.com/understanding_elf_file_format/"target="_blank" rel="noopener">https://linuxhint.com/understanding_elf_file_format/</a>)</li>
<li>Super Nintendo Architecture (<a href="https://www.copetti.org/projects/consoles/super-nintendo/"target="_blank" rel="noopener">https://www.copetti.org/projects/consoles/super-nintendo/</a>)</li>
<li>Mega Drive Architecture (<a href="https://www.copetti.org/projects/consoles/mega-drive-genesis/"target="_blank" rel="noopener">https://www.copetti.org/projects/consoles/mega-drive-genesis/</a>)</li>
<li>CPU comparison: SNES vs. Genesis vs. TG16 (<a href="https://atariage.com/forums/topic/197977-cpu-comparison-snes-vs-genesis-vs-tg16/"target="_blank" rel="noopener">https://atariage.com/forums/topic/197977-cpu-comparison-snes-vs-genesis-vs-tg16/</a>)</li>
<li>Neat story about the 6502 CPU (NES.. sorta SNES..) (<a href="https://forum.nhl94.com/index.php?/topic/12514-neat-story-about-the-6502-cpu-nes-sorta-snes/"target="_blank" rel="noopener">https://forum.nhl94.com/index.php?/topic/12514-neat-story-about-the-6502-cpu-nes-sorta-snes/</a>)</li>
<li>History of Console Emulators (<a href="http://www.emulationnation.com/console-emulation/history-of-console-emulators/"target="_blank" rel="noopener">http://www.emulationnation.com/console-emulation/history-of-console-emulators/</a>)</li>
<li>History of emulation (<a href="https://emulation.fandom.com/wiki/History_of_emulation"target="_blank" rel="noopener">https://emulation.fandom.com/wiki/History_of_emulation</a>)</li>
<li>Emugen: History of emulation (<a href="https://emulation.gametechwiki.com/index.php/History_of_emulation"target="_blank" rel="noopener">https://emulation.gametechwiki.com/index.php/History_of_emulation</a>)</li>
<li>How UltraHLE changed Nintendo 64 emulation forever | MVG (<a href="https://www.youtube.com/watch?v=2NF5sU_n0uk"target="_blank" rel="noopener">https://www.youtube.com/watch?v=2NF5sU_n0uk</a>)</li>
<li>Introduction to N64 Programming (<a href="http://n64.icequake.net/doc/n64intro/kantan/step2/index1.html"target="_blank" rel="noopener">http://n64.icequake.net/doc/n64intro/kantan/step2/index1.html</a>)</li>
<li>After Burner II NEC PC Engine / TurboGrafx-16 (<a href="https://www.youtube.com/watch?v=TORgYPAXk18&amp;t=0s"target="_blank" rel="noopener">https://www.youtube.com/watch?v=TORgYPAXk18&t=0s</a>)</li>
<li>Mac OS on a Sega Genesis? Yes! (Mac OS on a Sega Genesis? Yes! (sega-16.com))</li>
<li>Making a SEGA Mega Drive / Genesis game in 2019 (<a href="https://www.gamasutra.com/blogs/DoctorLudos/20191019/352537/Making_a_SEGA_Mega_Drive__Genesis_game_in_2019.php"target="_blank" rel="noopener">https://www.gamasutra.com/blogs/DoctorLudos/20191019/352537/Making_a_SEGA_Mega_Drive__Genesis_game_in_2019.php</a>)</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Feliz 2021! Muita gente tava esperando o novo ano pra deixar 2020 pra trás, mas infelizmente não sei se esse ano vai ser muito diferente não. Vamos cruzar os dedos.</p>
<p>Depois que fiz o episódio onde falei do chip Apple M1 eu ia fazer este, mas acabei falando de segurança. Mas agora vou voltar ao assunto continuando a falar de emuladores e videogames. Isso porque uma das coisas que mais gosto nessa vida é videogames. Desde que comecei a trabalhar sempre dizia que eu trabalho pra ganhar dinheiro pra sustentar meus videogames, e é quase verdade mesmo.</p>
<p>Outra coisa que vocês já sabem que eu gosto é a história das coisas de tech. No episódio de hoje vou juntar a fome e a vontade de comer e contar um pouco da história dos videogames com uma visão mais de programador, levando em conta o que vimos nos episódios anteriores e focar em assuntos que eu pessoalmente gosto. Claro que o tema é gigantesco e não cabe tudo num video só, mas vamos ver o que eu consigo fazer hoje!</p>
<p>Antes de começar, eu vi nos comentários que muitos ficaram com uma dúvida com a explicação que eu dei sobre máquinas de Turing, ou o que hoje chamamos de programas, serem representados por um numerozão, lembram? Um binário é nada mais que um número gigante. Então como falei de emuladores, muitos perguntaram se o lance era fazer outro programa com o mesmo numerozão.</p>
<p>Mas não é assim que você tem que pensar. Pensar num numerozão como sendo um texto em inglês e a versão emulada sendo o texto em português. Ambos os textos falam, digamos, sobre Harry Potter, mas em línguas diferentes e, portanto, resultam em numerozões diferentes. Quando você sai de Intel e vai pra ARM, por exemplo, necessariamente o mesmo programa recompilado, vai gerar um binário totalmente diferente e, de novo, um numerozão diferente. Espero que tenha esclarecido.</p>
<p>(&hellip;)</p>
<p>Pra começar já vou recomendar logo de cara o canal do Dimitris, mais conhecido como Modern Vintage Gamer. Assisto faz anos e ele sempre trás histórias dos bastidores, coisa que eu gosto. O canal dele tem várias histórias de como conseguiram quebrar a segurança dos mais diversos consoles, coisa que é essencial pra conseguir fazer um emulador. Ao longo dos anos empresas como a Sony, Sega, Nintendo, Microsoft, vem colocando mais e mais mecanismos de criptografia e segurança e, mesmo assim, dado tempo suficiente, a comunidade de emulação encontra maneiras de burlar e é fascinante entender como fazem isso.</p>
<p>Por exemplo, lembro da controvérsia quando a Sony retirou o suporte a Linux no Playstation 3 e o povo ficou pistola demais e isso acelerou alguém conseguir quebrar o PS3. Hoje em dia até a Microsoft já aprendeu e qualquer Xbox One você consegue colocar em modo de desenvolvimento, pra facilitar a vida de quem faz jogo independente, e ao mesmo tempo desincentiva gente que quer hackear pra instalar software homebrew, porque o próprio sistema já permite isso. Todo mundo fica feliz. O Dimitris faz uma série muito boa que conta essas histórias em mais detalhes, é o Mistakes were made, ou em bom português, “Erros foram cometidos”.</p>
<p>Pra quem não sabe, a gente costuma dividir consoles de videogames em gerações. Acabamos de entrar na nona geração com o PS5 e Xbox Series X. Infelizmente eu não reservei na pré-venda então me fodi. Se alguém souber de alguém querendo vender a um bom preço, mandem direct no meu Instagram. Enfim, acabamos de deixar pra trás a oitava geração, com PS4, XBox One, Switch e até o Wii U entra nessa.</p>
<p>A anterior foi do PS3, XBox 360 e o Wii original e foi a maior lavada em favor do Xbox 360 com o Wii original também deixando sua marca com a febre por causa dos controles de movimento. A sexta foi do Dreamcast, PS2, Xbox original e Gamecube, que marcou a virada do milênio em direção ao mundo de alta fidelidade, HD, telas de Plasma e LCD de alta resolução. Mas no fim do século passado, a quinta geração foi o salto de 16 pra 32-bits e a primeira onda de jogos 3D com consoles como Nintendo 64, o Playstation original, o Sega Saturn, Atari Jaguar, Panasonic 3DO e vários outros, foi uma das gerações mais movimentadas que eu já vi, e o salto pra 32-bits foi uma das mais importantes e conturbadas da história recente.</p>
<p>A quarta geração foi dos 16-bits, a virada da década de 80 pra 90, com o Sega Genesis liderando no começo mas com o Super Nintendo lado a lado, a era de tentar ter qualidade gráfica de arcade em casa, e tinha outras opções excelentes como o Turbografx 16 que no Japão era chamado de PC Engine e também tinha o monstruoso Neo Geo. Aliás, Genesis é nos Estados Unidos, aqui no Brasil ou no Japão a gente conheceu como Mega Drive.</p>
<p>A campanha de marketing da Sega nos Estados Unidos foi super agressiva, com o famoso slogan do &ldquo;Sega does what Nintendon&rsquo;t&rdquo; e com o lançamento de jogos como o lendário Sonic, veio o slogan bullshit de &ldquo;Blast processing&rdquo;. Tecnicamente o Genesis era mesmo mais performático, mas fizeram o erro de configurar uma paleta de cores horrível e limitada. O Super Nintendo usava um chip de 16-bits mais fraco, mas eles tinham aceleração de background como o Mode 7 e uma paleta de cores muito mais rica.</p>
<p>Em seguida, a terceira geração foi dos 8-bits que representaram a renascença do videogame com o Nintendinho liderando, mas com outros como o Sega Master System tentando conseguir espaço. Em termos de hardware, essa geração foi o oposto da de 16-bits, o Master System é quem tinha uma paleta de cores mais rica e por isso jogos de Nintendinho tem cores meio bleh e no Master System eram cores bem mais saturadas e diversificadas. Mas obviamente o sistema de licenciamento e exclusividade da Nintendo garantia muito mais jogos pro console deles, deixando a Sega com poucas opções.</p>
<p>A terceira e quarta geração foram marcadas pelo que hoje conhecemos como a “Guerra dos Consoles”, a briga entre a Sega e a Nintendo. E, de novo, mais nos Estados Unidos, porque no Japão a Sega dominava nos arcades mas nos consoles sempre foi a Nintendo na frente. Até eles fazerem uma merda com a Sony. Fizeram parceria pra lançar o Nintendo Playstation com tecnologia de CD da Sony. Mas num grande evento, a CES, a Nintendo anunciou que ia fazer parceria com a Philips e a Sony só descobriu isso com todo mundo nesse evento. Foi uma cagada homérica da Nintendo, procurem essa história. Mas o importante é que isso deixou a diretoria da Sony full pistola e por isso eles aprovaram lançar o próprio console, o Playstation original, daí o resto - como diriam - foi história.</p>
<p>Voltando, a segunda geração foi a que terminou nos Estados Unidos com o crash dos videogames no começo dos anos 80, a geração do nostálgico Atari 2600, Magnavox Odyssey 2, Intellivision, ColecoVision, Vectrex e dezenas de outros. O crash aconteceu justamente pelo excesso de consoles e principalmente excesso de jogos extremamente ruins, o que arruinou a reputação de games, afastou todo o público e inspirou a Nintendo a criar o modelo de licenciamento e controle de qualidade pra lançar jogos pro console deles.</p>
<p>Eu joguei alguma coisa nessa época, e apesar da nostalgia, não acho mais divertido jogos de Atari hoje em dia. Esses jogos não envelheceram nada bem, e quem gosta realmente é pelas memórias da infância. Eu tenho essas memórias, mas viraram só isso mesmo, memórias. Nem Enduro, nem River Raid, nem Space Invaders, ou Pitfall, todos jogos que eu adorava, não consigo mais jogar hoje. A tecnologia nessa época ainda era bem experimental, bem pouco madura, com pouquíssimos recursos, então realmente programar pra esses consoles era um exercício em frustração e era impossível fazer jogos mais sofisticados do que um Pacman.</p>
<p>Agora, segundo a Wikipedia, a primeira geração de consoles tem pelo menos uns 900, não é a toa que na próxima geração ia ter um crash. Começou como uma bolha. Tudo foi derivado da do avô dos videogames, o Pong. E nessa época ainda não havia sido inventado e nem difundido o conceito de cartuchos. A grande maioria desses consoles eram meros clones baratos de Pong e vinham com um único jogo, ou até mais de um, mas eram pré-instalados dentro e você podia trocar de jogo usando um interruptor, mas não podia instalar jogos novos.  Ainda era a geração que entendia que uma máquina só precisava executar uma única tarefa. E nessa geração trocentos fabricantes diferentes faziam seus próprios clones de Pong, Pacman e coisas assim. Imagina a dificuldade pro consumidor.</p>
<p>Já vimos nos episódios anteriores que cartuchos são uma placa com chips de ROM que o console tem acesso direto, sem precisar “carregar” nada pra RAM, é como se fosse um pente de RAM pré-carregado. E se você assistiu a série do Netflix, High Score viu que o primeiro console que introduziu o conceito de cartuchos foi o Fairchild Channel F em 1976 mas quem de fato popularizou a idéia foi o Atari VCS que saiu um ano depois. Vários fabricantes já estavam testando idéias pra baratear custos e facilitar vendas, e eventualmente alguém chegaria no cartucho, era inevitável. Todo mundo tava procurando formas de baratear os custos e tornar coisas como games mais acessíveis, sem usar mecanismos lentos como as fitas cassette, ou caros como disquetes.</p>
<p>Obviamente, a cada nova geração a complexidade dos consoles ia aumentando uma ordem de grandeza. Por exemplo, os consoles de 8-bits não são tão complicados assim e eu dei um pequeno exemplo no episódio do Super Mario com o Nintendinho e canais como o Coding Secrets e Retro Gaming Mechanics Explained tem muitos vídeos explicando técnicas de programação e como os jogos eram estruturados nessas plataformas, incluindo coisas como o lendário Mode 7 do Super Nintendo. Nessa época, cada clock contava e nenhum compilador ainda conseguir cuspir binários otimizados. Todo jogo precisava ser escrito em assembly, na mão mesmo. Recomendo assinar os canais deles.</p>
<p>Emular esses consoles significa encontrar as especificações dos chips e programar as instruções equivalentes em software, garantir que o clock funcione igual, que as instruções executem nos mesmos tempos. Isso não é tão trivial porque pensa que nossas CPUs hoje são absurdamente mais rápidas que antigamente, então a gente precisa propositalmente fazer as instruções rodar mais devagar. No caso de um Nintendinho você tem que criar o emulador pra CPU Ricoh 2A03 que é baseado no MOS 6502. Tem que escrever o emulador pro PPU ou Picture Processing Unit que é o chip responsável por renderizar backgrounds e sprites. Mesma coisa pro APU que é o Audio Processing Unit que tem cinco canais de áudio e é um PSG ou Programmable Sound Generator. Enfim, criar software pra emular cada um dos chips.</p>
<p>Daí precisa emular os 2 kilobytes de RAM que é bem fácil porque temos RAM de sobra hoje. Tem que emular os controles e finalmente os MMU ou memory management controllers que são chips que vinham nos cartuchos e permitiam bancos de ROM. O sistema permite um máximo de 40 kilobytes de ROM mas com os MMUs você podia ter cartuchos com até 2 megabytes ou mais e também memória com bateria pra gravar saves. E sim, é bastante coisa pra emular. Eu expliquei como isso funciona no episódio do Super Mario, dêem uma olhada. Aliás, tudo isso é só pro Nintendinho de 8-bits. Agora repita isso pra todos os consoles, em todas as suas variações ao longo dos anos, de cada uma das oito gerações que eu descrevi. É coisa pra cacete.</p>
<p>Falando só de especificações técnicas, sem olhar os jogos, tecnicamente o Turbografx 16 deveria ser o mais fraco, porque ele usa o processador 65C02 que é o mais rápido CPU 8-bits da família 6502, e tava competindo na geração de 16-bits do Genesis e Super Nintendo. A NEC escolheu usar chips de RAM e ROM dos cartuchos com o clock máximo que o CPU conseguia rodar, e isso foi muito inteligente. Se você pegar jogos de Turbografx como Bonks Adventure ou Dracula X que é o Castlevania, vai provavelmente dizer que é comparável ou até superior ao Super Castlevania IV do Super Nintendo.</p>
<p>O Super Nintendo muita gente pensa que é o mais poderoso por conta do chip gráfico que tem capacidade de rotacionar e escalar o layer de background pra fazer os famosos efeitos pseudo-3D como em Mario Kart ou Pilotwings. Mas a Nintendo foi pelo caminho mais conservador e escolheu usar o processador 65816 que é o sucessor de 16-bits do 65C02 usado no Turbografx 16. Só que o chip de 8-bits do Turbografx ia até 7.6 Mhz e o chip de 16-bits do Super Nintendo foi capado em míseros 3.58 Mhz, metade, em parte porque a RAM não era mais rápida que isso.</p>
<p>Muita gente pensa em performance só como clock da CPU, mas até hoje, você precisa parear a CPU com RAM porque o a CPU precisa ficar constantemente puxando dados e gravando nessa RAM, por isso coisas como clock da RAM e dual channel fazem muita diferença em PC de hoje. E por isso também uma Apple preferiu soldar a RAM direto do lado do seu novo CPU M1 pra garantir a melhor combinação de performance. Smartphones fazem a mesma coisa. Se você comprar um AMD Ryzen mais moderno mas colocar pentes de RAM velhas de menos de 2Ghz e sem colocar em dual channel, você criou um gargalo enorme, e está desperdiçando o CPU.</p>
<p>Sendo o Super Nintendo e o Turbografx derivados da família 6502, eu não posso dizer por experiência própria mas pelo que já li a respeito o assembly dele não era muito amigável pra programar, exigindo muita burocracia, como a constante troca de modes no Super Nintendo entre instruções de 8 bits e 16 bits. Se tentasse escrever em C, o código gerado ficava muito lento pelo overhead do C, faltava registradores pra conseguir otimizar. Enfim, não era uma CPU amigável pra um programador de assembly, e eu já disse que nessa época era obrigatório programar em assembly pra tirar o máximo dos poucos recursos que tinha nesses consoles.</p>
<p>Por outro lado, o Sega Genesis ou Mega Drive de fato tinha o CPU superior, eles escolheram o Motorola 68000 que era híbrido 32 e 16-bits, com clock também de 7.6 Mhz, o dobro do Super Nintendo e ainda vinha com um segundo processador Zilog Z80 de 8-bits que era o mesmo do Master System, usado como processador dedicado de áudio. Além disso, diferente do 65C02 e 65816, você conseguia escrever pelo menos parte do jogo em C, que gerava assembly suficientemente rápido pro 68000. E mesmo não tendo um chip gráfico dedicado pra conseguir os efeitos de rotação e escalonamento de background, ele conseguia alguns desses efeitos via software por causa do CPU mais rápido. Veja jogos como Castlevania Bloodlines por exemplo. Pois é, era possível fazer Mode 7 no Mega Drive, isso não era uma exclusividade do Super Nintendo.</p>
<p>Mas como eu disse antes, uma coisa que o Mega Drive falhou foi na escolha de paletas de cor. Ele tinha conjuntos de cores horríveis e menos cores no total que o Super Nintendo ou Turbografx. Por isso, visualmente, os jogos de Megadrive parecem sempre mais feios em termos de cor se comparar jogos que foram lançados pras outras plataformas. Pegue jogos que saíram ao mesmo tempo em todas como Street Fighter II e no Mega Drive vai ser mais feinho.  Olha aqui do lado. Esse é o do Super Nintendo, esse outro do Turbografx e por último, esse é do Mega Drive.</p>
<p>No final do dia, tudo depende do que os programadores conseguiam extrair dessas máquinas. E em termos de jogos não se pode comparar os que saíram no lançamento dos consoles com os que saíram no final da geração. No começo é quando os programadores ainda não conhecem todo o potencial do hardware. E quando a geração tá acabando, é quando os programadores já descobriram todos os truques possíveis. É interessante ver como jogos como Afterburner II é definitivamente melhor no Turbografx com um processador teoricamente pior de 8-bits contra a versão do Mega Drive de 16-bits.</p>
<p>Mais do que isso, o processador do Mega Drive, o 68000 é super famoso e equipou microcomputadores como os Amiga e Macintosh por exemplo. Existiu até uma tentativa de emular o Mac OS 7 pra rodar em cima de um Mega Drive. Infelizmente, tirando uma thread de fórum de 2006, não achei imagens boas ou vídeos mostrando ele rodando. Se alguém tiver não deixe de compartilhar nos comentários.</p>
<p>Obviamente não seria prático rodar o Mac OS num Mega Drive, é só mais uma evidência do que falei no vídeo anterior sobre máquinas universais de Turing: mesmo lento é possível emular outro sistema. E tecnicamente faz sentido, ele usa o Sega CD como um CD SCSI que o Mac consegue acessar e o video sai pela extensão 32X que foi uma expansão pro Mega Drive conseguir rodar polígonos e outros efeitos especiais, incluindo mais resolução e mais cores também.</p>
<p>De qualquer forma, até a terceira geração, dos 16-bits, muito da programação de jogos se fazia em Assembly, particularmente porque a família de CPUs da MOS não conseguia ter C que gerasse binários eficientes, então só codando assemblão na munheca mesmo. Mas a próxima geração teve um salto enorme. Na quarta geração começamos a usar processadores de 32-bits com arquitetura RISC, semelhante aos processadores ARM de celulares de hoje em dia e ao novo Apple M1.</p>
<p>Era possível ter clocks maiores e acesso a exponencialmente mais endereços de RAM. E daí passou a se utilizar mais C, porque nessa arquitetura os compiladores evoluíram mais e já era possível ter código compilado tão eficiente ou mais do que escrever assembly na mão. E se alguém tinha alguma dúvida, não, em 99.99% dos casos você não vai conseguir escrever mais assembly melhor do que um compilador consegue gerar.</p>
<p>Num resumo bem resumido, pense que a arquitetura x86 ou CISC é feita de instruções complexas, ou seja, que fazem bastante coisa e por isso demoram vários clocks pra executar e arquitetura RISC como nos chips ARM é feita de instruções simples que, que executam poucas tarefas e por isso terminam rápido, tipo num único clock. Só pra ilustrar pra quem não tá acostumado com assembly, num processador x86 talvez eu tivesse uma função chamada “desenhar um botão” que numa instrução só já mostra um botão desenhado na tela. Num ARM hipotético teria só a função “desenhar linha” e eu precisaria chamar quatro vezes pra desenhar o mesmo botão.</p>
<p>Na prática não faria tanta diferença porque desenhar botão digamos que leva 4 clocks pra executar e o desenhar linha leve 1 clock. No fim ambos levariam 4 clocks. Mas pra quem escreve direto em assembly faz diferença porque ele precisaria escrever muitas linhas a mais de código pra fazer a mesma coisa. Hoje em dia não faz diferença, porque do C o compilador que vai ter o trabalho de gerar o assembly, mas antigamente programar em C não era eficiente então fazia diferença essa história de arquiteturas CISC ou RISC porque influenciava diretamente na produtividade dos programadores.</p>
<p>Mas a partir da geração 32-bits passamos a programar quase que exclusivamente em C, deixando o trabalho de gerar assembly pros compiladores, como o compilador do Visual Studio da Microsoft ou o GCC que tem em todo Linux ou o LLVM, mais especificamente o Clang, que tem em todo Mac. Agora, imagine que descobrimos uma forma mais eficiente de fazer a função hipotética de desenhar botão e em vez de levar 4 clocks poderia levar 2.</p>
<p>Num Intel fodeu, não tem como mexer nessa função porque ela é impressa no hardware, no chip da CPU. Num RISC, que tem instruções mais simples, podemos atualizar o compilador e ele vai cuspir um assembly mais otimizado que vai usar menos instruções e executar em 2 clocks. Ou seja, sempre temos possibilidades de, sem mexer no código em C, ganhar performance de graça por avanços nas otimizações dos compiladores. E nesse quesito o ARM tem mais vantagens do que x86 da Intel.</p>
<p>Pra nós, que dificilmente vamos programar assembly na mão, a arquitetura do chip por baixo não importa porque o compilador vai fazer o trabalho bruto de escrever assembly otimizado, mas basta saber que sim, a arquitetura RISC é definitivamente mais flexível do que os x86. A Intel é obrigada a carregar esse legado que vem da época em que era importante um assembly mais simples e, portanto, mais complexo. Hoje isso não é mais importante. Em última instância a arquitetura RISC era mais chata naquela época se você precisasse escrever assembly na mão, mas agora ela tem vantagens. Ela estava à frente do seu tempo.</p>
<p>De qualquer forma, a arquitetura dos dois tipos foi ficando mais complexa com o tempo, porque agora esses CPUs também eram capazes de realizar tarefas concorrentemente com multithreading além de ter chips gráficos capazes de calcular polígonos. Você tinha que ser um sadomasoquista hardcore pra querer fazer multithreading e polígonos em assembly num jogo inteiro. E antes os jogos tinham acesso direto ao hardware, sem um sistema operacional intermediando, mas no Saturn, Playstation ou Nintendo 64, agora eles tinham um firmware que funciona como um sistema operacional super leve. Agora meio que ficou necessário, porque senão ninguém ia conseguir fazer jogos nesses hardwares que eram exponencialmente mais complexos do que a geração anterior. É quando começamos a trocar um pouco de performance por mais qualidade de vida de programação.</p>
<p>Isso aumentou dramaticamente a dificuldade de emular esses sistemas. Porque se você fizer a engenharia reversa de chips de processamento de polígonos e tentar emular só via software, os CPUs de PCs da época simplesmente não conseguiam rodar. Ao mesmo tempo começamos a ter placas gráficas 3D em PC também com os venerados 3DFX. Pra programar em C pra placas 3DFX se usava a biblioteca Glide. Então algumas das primeiras tentativas de emular Playstation ou Nintendo 64 envolvia criar um software Adaptador entre as funções do console e os equivalentes na Glide. Por isso se você instalou emuladores dos anos 90 como o famoso UltraHLE tinha a chatice de achar a DLL certa de Glide por exemplo.</p>
<p>Existem vários vídeos e blogs onde você consegue encontrar a diferença de uma GPU pra uma CPU mas sendo bem simplista pra você ter uma idéia na cabeça. Numa CPU teríamos funções como adição, onde você coloca dois números em dois registradores e ele calcula a soma e grava em outro registrador, e vai fazendo assim uma instrução de cada vez. Se precisássemos processar todos os pixels de uma tela, digamos deixar a cor mais escura, seria um puta trampo pro CPU. Por que? Antigamente a resolução de videogame era tipo trezentos e vinte por duzentos e quarenta pixels, ou seja, setenta e seis mil e oitocentos pixels.</p>
<p>Só pra simplificar a conta digamos que cada adição da CPU custasse um clock, então ia levar mais de setenta e seis mil clocks pra processar todos os pixels. E ele teria que dar um jeito de fazer isso sessenta vezes por segundo. Ou seja, não dava porque num processador da era 16-bits, de 7 megahertz significa 7 mil clocks por segundo. Então ia levar mais de dez segundos pra processar essa imagem do exemplo.</p>
<p>Agora uma GPU é feita pra executar múltiplas adições em paralelo. Desde sempre ela foi organizada no que hoje você conhece como multi-core. Mas em vez de quatro ou oito cores que você tem num Intel i5 da vida, uma GPU tem dezenas, ou centenas de pequenos cores que fazem bem pouca coisa muito rápido. Em vez de passar só um número como parâmetro, passamos um vetor. Pense em um vetor como um array de números.</p>
<p>Então é a adição de um vetor com outro vetor. Digamos que a GPU aguente um vetor de 320 números, então ele precisaria processar a adição só duzentas e quarenta vezes, um por clock, ou melhor ela poderia rodar em duzentas e quarenta dos seus micro-cores e executar tudo em paralelo num clock só. Olha como só nesse exemplo, saltamos do custo de mais de setenta mil clocks pra um único clock.</p>
<p>Uma GPU executa tarefas muito simples em uma quantidade grande de dados de uma só vez, essa é a especialização dela. Porém, ela só é rápida pra esse tipo de cálculo mais massivo e não pra cálculos simples e lineares onde a próxima instrução depende do resultado da anterior. E gráficos é o melhor caso de uso, porque são trinta ou quarenta quadros por segundo com uma quantidade massiva de pixels que precisam ser processados e cujo processamento de uma linha de pixels independe da outra linha de pixels.</p>
<p>E pixels podem ser organizados em vetores e matrizes, que são os elementos que uma GPU adora processar. E em tempos mais recentes inventaram uma forma de mandarmos pequenos programinhas pra GPU, isso é o que você já deve ter ouvido falar como shaders. Enfim, já foi uma longa tangente, por hoje vamos só entender isso. GPU é um troço simples que se tornar complexo porque roda com vetores longos e massivamente em paralelo. CPU é um troço complexo que roda com argumentos simples e linear.</p>
<p>Ah sim, e nessa época a Microsoft tava lançando coisas com Direct3D que era uma tentativa de padronizar a programação 3D pra placas gráficas de diferentes fabricantes. Então talvez você não tivesse a 3DFX Voodoo mas tinha a Nvidia TNT2. Então precisava do nGlide que era uma camada que respondia as APIs da Glide mas mapeava pra chamadas de Direct3D. Sim, se hoje em dia você tem dores de cabeça com drivers da Nvidia ou AMD, com Direct3D ou Vulkan ou OpenGL, imagina a zona no fim dos anos 90. Era a mesma coisa só que pior e mais instável, a gente ainda tava aprendendo como lidar com placas 3D. Um dia vou fazer um episódio falando mais de GPUs, mas pra agora, só estas noções que expliquei pra diferenciar um CPU de uma GPU deve bastar pra maioria dos casos.</p>
<p>Ver coisas como o emulador UltraHLE, rodando Super Mario 64, em um Pentium II ou III, mesmo que parcialmente e meio bugado, em 1999, sendo que o Nintendo 64 tinha sido lançado só 3 anos, antes era absurdamente impressionante. Pra você ter uma idéia, mesmo hoje em dia usando emuladores como o Mugen 64, você não consegue emulação perfeita de Nintendo 64. Temos dificuldade em manter 60 frames por segundo em hardware considerado fraco hoje mas que pra época era um supercomputador, como um Raspberry Pi 3 ou processadores de celular Androids. Isso depois de 20 anos. De qualquer forma o UltraHLE era tão bom que deixou a Nintendo full pistola e você pode conferir essa história no video do canal Modern Vintage Game que vou deixar nas descrições abaixo.</p>
<p>A estratégia de emulação começou a mudar com o UltraHLE. Com consoles de 8 e 16 bits a estratégia era emular os chips como a CPU, PPU e tudo mais. Com o aumento da complexidade nas plataformas de 32-bits isso era um trabalho brutal e bem mais difícil. Porém, como o processo de desenvolvimento dos jogos passou pra C, linkando com as bibliotecas no firmware dos consoles, outra estratégia passou a ser interceptar as chamadas de função em C e traduzir pro equivalente no Windows por exemplo. Se você assistiu meu episódio sobre WSL, o Windows Subsystem for Linux, vai lembrar que a versão 1.0 fazia a mesma coisa com programas pra Linux, interceptava as chamadas de sistema pra kernel do Linux e traduzia em tempo real pra chamadas pra kernel do Windows.</p>
<p>O Playstation, pela popularidade, teve muito mais gente tentando emular e hoje em dia você consegue rodar praticamente todos os jogos, inclusive com hacks pra aumentar a resolução interna e aplicando filtros nas texturas pros jogos ficarem um pouco mais bonitos. Mas em paralelo ao UltraHLE a gente tinha alguns emuladores de Playstation também como o PSEmu ou o Virtual Game Station que era comercial e só rodava em Macintosh. Nenhum dos dois era perfeito na época, mas foram referência pra próxima geração de emuladores.</p>
<p>O primeiro emulador que eu lembro que me deixou realmente impressionado foi o Bleem. Ele era diferente primeiro porque era comercial e fechado e segundo porque em vez de tentar emular tudo do sistema e todos os jogos, eles preferiram focar em otimizar bem só alguns poucos jogos, como Gran Turismo ou Final Fantasy 7. Ou seja, eles deixavam hardcoded no emulador algo como “if gran turismo mude pra fazer X”, até o Gran Turismo rodar liso mesmo que outros jogos falhem. E eles vendiam pacotes de otimizações pra cada jogo. Na época, quando vi os anúncios, eu achava que era enganação, mas de fato a desgraça funcionava.</p>
<p>E eles ainda faziam isso de aumentar a resolução de renderização então jogos de playstation que nativamente só tinham 320 por 240 pixels dobrava pra 640 por 480. Lembrando que a gente usava monitores de 800 por 600 ou 1024 por 768. Então 640 por 480 era nosso HD. O emulador começou a mudar os jogos pra fazer coisas que originalmente eles não foram projetados pra fazer, e isso era fascinante. Pra ver como foi essa história eu recomendo o documentário sobre o Bleem do canal The Gaming Historian, que é outro canal bem produzido, e vou deixar o link nas descrições abaixo.</p>
<p>O Bleem acabou não vingando, tomaram um processo da Sony nas costas e eles tentaram voltar repetindo a estratégia com o Bleemcast na geração seguinte, pra emular Dreamcast. Mas apesar de não terem perdido o processo da Sony, os custos de advogados foram absurdos, e eles fecharam em 2001, no mesmo ano que a Sega decidiu descontinuar o Dreamcast também.</p>
<p>O desenvolvimento de emuladores de Playstation andou bem mais rápido do que Nintendo 64 mas o mais atrasado de todos sempre foi o Sega Saturn. Ele saiu antes do Playstation e esse lançamento foi um dos maiores desastres da história do videogame. Pra quem não sabe, a Sega dos Estados Unidos sempre se ferrava por causa das decisões da Sega do Japão. A falta que fazia mandar e-mails naquela época. Eles desenvolveram o 32X nos Estados Unidos pro Genesis sem saber que no Japão estava sendo desenvolvido o Saturn. Pensa a zona.</p>
<p>O Saturn ainda recebeu uma arquitetura super difícil de trabalhar com dois processadores paralelos. A maioria não sabe programar paralelo hoje, imagina naquela época. Daí acabavam só usando um dos processadores. Foi mais ou menos o mesmo problema que a Sony repetiu com o Playstation 3 e o famigerado CPU Cell com seus co-processadores paralelos, os SPUs. Até hoje o chip é considerado excepcional, mas era notoriamente difícil de programar. Tanto que só no final da sexta geração começaram a sair jogos que tiravam vantagem do processamento paralelo como o lendário The Last of Us original. E foi um dos motivos de porque a Sony perdeu essa geração pro XBox 360 da Microsoft, que era uma arquitetura muito mais simples de programar. Um canal que mostra vários jogos de Saturn é o canal do Sega Lord X, recomendo assistir pra ver se você nunca jogou Saturn.</p>
<p>Em termos de emuladores, o RPCS3 já consegue rodar muitos jogos de PS3 mas é bem pesado. Simular os SPUs sempre foi o desafio. E essas foram algumas das curiosidades que eu mais gosto sobre alguns dos meus videogames favoritos, mas tem toneladas de histórias a mais, tanto que existem canais de YouTube dedicados só nisso, como o The Gaming Historian ou Modern Vintage Games que já mencionei, recomendo que assistam o canal deles pra mais curiosidades assim. Mas o objetivo de hoje era dar uma pequeno overview, uma pincelada geral pra ver se vocês ficam interessados no assunto também. Eu acho que gosto mais de entender os mecanismos de como esses consoles e games funcionam, como eram construídos, que truques usavam, mais do que realmente jogar os jogos propriamente ditos.</p>
<p>Pra finalizar, deixa eu listar os emuladores que mais gosto pra vocês pesquisarem no Google e brincar. A maioria existe pra todas as plataformas e sistemas operacionais, incluindo Windows, Linux e rodam em Raspberry Pi que é fraquinho pros padrões hoje mas suficiente pra maioria dos emuladores. Mas se puder rodar num hardware pra Android melhor, eu recomendo. A maioria dos apps você encontra direto no Google Play Store. E o principal de todos é o RetroArch. Ele em si não é um emulador, mas uma interface pra vários emuladores, que são chamados de Cores. Nem todos funcionam bem ou de primeira, mas pelo RetroArch você consegue instalar os Cores online além de coisas como temas diferentes, artes das capas das caixas dos jogos, códigos de cheats, e diversas outras coisas. É um mundo em si só.</p>
<p>Quem gosta de Sony no próprio RetroArch tem cores de Playstation original. Tem o PCSX2 pra Playstation 2 que roda até que bem mas é pesado. Tem o RPCS3 que ainda não é muito estável e nem muito compatível mas se seu computador for potente deve rodar razoavelmente bem. E tem o PPSPP pro Vita, um dos meus favoritos, que roda muito bem. Jogos como Crisis Core rodam muito bem, mas God of War vai precisar de mais hardware pra rodar direito. E nem tentem rodar em Raspberry Pi, o hardware não é suficiente. Num smartphone mais novo deve rodar razoável, mas acima de PS2, recomendo um PC.</p>
<p>Pra quem gosta de Nintendo, o Nintendinho e Super Nintendo tem vários emuladores como o Mesen que já mencionei ou o Bsnes. E pelo RetroArch você baixa a maioria e é plug-and-play. Mas os mais interessantes são o Dolphin que consegue rodar bem jogos de Gamecube e Wii original, embora seja pesado. Tem o Citra que roda jogos de Nintendo 3DS muito bem. Mesmo no meu PC com Intel i7 alguns dão umas travadas e perde frame, então não é perfeito, mas tá evoluindo rápido. O mesmo vale pro Cemu que consegue rodar jogos de Wii U muito bem mas dá um puta trampo configurar. Se tiver paciência, vai poder jogar Zelda Breath of the Wild em Full HD com vários filtros que deixam o jogo mais bonito do que no Nintendo Switch. E falando em Switch tem o Yuzu que já roda vários jogos de Switch, mas eu mesmo não testei porque tenho um Switch.</p>
<p>Pra Sega, emuladores de mastersystem e genesis tem bastante no RetroArch, mas o mais difícil é o Saturn por causa da arquitetura complicada que expliquei antes. Mesmo assim, o emulador Yaba Sanshiro é bem competente e todo jogo que testei como Panzer Dragoon ou Sega Rally rodaram muito de boa mesmo num Android, então é o que recomendo. E quem gosta de Dreamcast tem o Redream que é pago, mas eu digo que vale a pena pagar porque é de longe o melhor emulador, que roda mais estável e mais compatível.</p>
<p>Finalmente, eu gosto muito de jogos de arcade então NEO GEO é essencial, mas eu mesmo odeio procurar emuladores, bios e configurações que funcionam direito então nem vou recomendar muito que se tente do zero. Eu me enchi tanto que preferi comprar no Mercado Livre o emulador que vem com as ROMS e tudo mais já pré-configurado pra MAME. MAME é de longe o emulador mais chato do mundo de configurar, eu não recomendo. É melhor achar pré-configurado. E a razão de ser tão chato é que arcades eram como um console específico feito só pra um ou um conjunto pequeno de jogos.</p>
<p>A Capcom tinha as famosas placas CPS1, os mais modernos usavam hardware derivado do Dreamcast, o Naomi. E se contar todas as placas criadas desde os anos 80, estamos falando de dezenas. E cada um tem uma configuração diferente. Configurar um a um na mão é um trabalho que não vale a pena. Se alguém tiver boas dicas de como facilmente configurar um bom emulador de Neo Geo pra Android, fiquem à vontade pra colocar nos comentários abaixo.</p>
<p>E sim, vou só listar os emuladores e não pretendo fazer vídeos de como configurar porque isso você vai achar toneladas de tutoriais em video e em blogs, bem detalhados. O próprio Wiki do RetroArch tem bastante documentação. Se você quer jogar jogos pirata, tem que fazer algum esforço ou gastar alguma grana pra comprar já configurado. Minha parte eu já fiz. Espero que tenham gostado dessa curta história dos videogames. Quem tem dúvidas ou histórias pra compartilhar, deixem nos comentários abaixo. Se curtiram o video mandem um joinha e compartilhe com seus amigos, assine o canal e não deixe de clicar no sininho pra não perder os próximos. A gente se vê, até mais!</p>
]]></content:encoded><category>emulacao</category><category>games</category><category>retrocomputacao</category><category>akitando</category></item><item><title>[Akitando] #81 - Aprendendo sobre Computadores com Super Mario (do jeito Hardcore++)</title><link>https://akitaonrails.github.io/2020/06/18/akitando-81-aprendendo-sobre-computadores-com-super-mario-do-jeito-hardcore/</link><guid isPermaLink="true">https://akitaonrails.github.io/2020/06/18/akitando-81-aprendendo-sobre-computadores-com-super-mario-do-jeito-hardcore/</guid><pubDate>Thu, 18 Jun 2020 10:00:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/hYJ3dvHjeOE"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Errata: em 17:12 eu disse certo mas na equação faltou mostrar dividindo tudo por 2. Em 13:00 eu claramente faltei na aula porque 278 x 7 é 1946 😅&lt;/p&gt;
&lt;p&gt;Você não precisa ter assistido o video anterior pra entender este, mas certamente ajuda.&lt;/p&gt;
&lt;p&gt;Hoje vou acelerar na missão de fazer vocês entenderem como computadores em geral funcionam por baixo dos panos usando um Nintendinho e o Super Mario como guias nesta jornada.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/hYJ3dvHjeOE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Errata: em 17:12 eu disse certo mas na equação faltou mostrar dividindo tudo por 2. Em 13:00 eu claramente faltei na aula porque 278 x 7 é 1946 😅</p>
<p>Você não precisa ter assistido o video anterior pra entender este, mas certamente ajuda.</p>
<p>Hoje vou acelerar na missão de fazer vocês entenderem como computadores em geral funcionam por baixo dos panos usando um Nintendinho e o Super Mario como guias nesta jornada.</p>
<p>Não tentem entender tudo na primeira assistida. Eu mesmo não conseguiria. Assista até o fim pra ter a visão completa depois retorne pra partes específicas pra pegar em mais detalhes.</p>
<p>Já aviso que os primeiros Vinte Minutos podem parecer um pouco devagar, porque vou complementar o que comecei no video anterior, mas garanto que depois disso vem o filé mignon do filé mignon. Vamos ver como se constrói um emulador, como cartuchos funcionam, como começar a editar jogos e a entender como se começa a pensar em fazer jogos retrô, e vamos até falar de speedrun e hackear bugs de jogos. Tudo isso num único episódio!</p>
<p>Links:</p>
<ul>
<li>
<p>Super Mario Bros. 3 - Wrong Warp (<a href="https://www.youtube.com/watch?v=fxZuzos7Auk"target="_blank" rel="noopener">https://www.youtube.com/watch?v=fxZuzos7Auk</a>)</p>
</li>
<li>
<p>A Comprehensive Super Mario Bros. Disassembly (<a href="https://gist.github.com/1wErt3r/4048722"target="_blank" rel="noopener">https://gist.github.com/1wErt3r/4048722</a>)</p>
</li>
<li>
<p>Lembra deles? Confira jogos brasileiros do Master System lançados pela Tectoy! (<a href="https://blogtectoy.com.br/lembra-deles-todos-jogos-brasileiros-do-master-system-lancados-pela-tectoy/"target="_blank" rel="noopener">https://blogtectoy.com.br/lembra-deles-todos-jogos-brasileiros-do-master-system-lancados-pela-tectoy/</a>)</p>
</li>
<li>
<p>Free NES assembler (<a href="https://bisqwit.iki.fi/source/nescom.html"target="_blank" rel="noopener">https://bisqwit.iki.fi/source/nescom.html</a>)</p>
</li>
<li>
<p>Micro Mages (<a href="https://morphcatgames.itch.io/micromages"target="_blank" rel="noopener">https://morphcatgames.itch.io/micromages</a>)</p>
</li>
<li>
<p>Nes Dev Wiki (<a href="https://wiki.nesdev.com/w/index.php/Nesdev_Wiki"target="_blank" rel="noopener">https://wiki.nesdev.com/w/index.php/Nesdev_Wiki</a>)</p>
</li>
<li>
<p>Computer Archeology - The Legend of Zelda (<a href="https://www.computerarcheology.com/NES/Zelda/"target="_blank" rel="noopener">https://www.computerarcheology.com/NES/Zelda/</a>)</p>
</li>
<li>
<p>6502 Instruction Set (<a href="https://www.masswerk.at/6502/6502_instruction_set.html"target="_blank" rel="noopener">https://www.masswerk.at/6502/6502_instruction_set.html</a>)</p>
</li>
<li>
<p>An introduction to 6502 math: addiction, subtraction and more (<a href="http://retro64.altervista.org/blog/an-introduction-to-6502-math-addiction-subtraction-and-more/"target="_blank" rel="noopener">http://retro64.altervista.org/blog/an-introduction-to-6502-math-addiction-subtraction-and-more/</a>)</p>
</li>
<li>
<p>Explain Half Adder and Full Adder with Truth Table (<a href="https://www.elprocus.com/half-adder-and-full-adder/"target="_blank" rel="noopener">https://www.elprocus.com/half-adder-and-full-adder/</a>)</p>
</li>
<li>
<p>Build a multiplying machine using NAND logic gates (<a href="https://codegolf.stackexchange.com/questions/12261/build-a-multiplying-machine-using-nand-logic-gates"target="_blank" rel="noopener">https://codegolf.stackexchange.com/questions/12261/build-a-multiplying-machine-using-nand-logic-gates</a>)</p>
</li>
<li>
<p>Tool Assisted Game Movies (<a href="http://tasvideos.org/"target="_blank" rel="noopener">http://tasvideos.org/</a>)</p>
</li>
<li>
<p>RETRO INSECTIVORES: FINDING AND ELIMINATING BUGS IN NES DEVELOPMENT (<a href="https://megacatstudios.com/blogs/press/retro-insectivores-finding-and-eliminating-bugs-in-nes-development"target="_blank" rel="noopener">https://megacatstudios.com/blogs/press/retro-insectivores-finding-and-eliminating-bugs-in-nes-development</a>)</p>
</li>
<li>
<p>FCEUX (<a href="https://sourceforge.net/projects/fceultra/"target="_blank" rel="noopener">https://sourceforge.net/projects/fceultra/</a>)</p>
</li>
<li>
<p>Zelda Screen Transitions are Undefined Behaviour (<a href="https://gridbugs.org/zelda-screen-transitions-are-undefined-behaviour/"target="_blank" rel="noopener">https://gridbugs.org/zelda-screen-transitions-are-undefined-behaviour/</a>)</p>
</li>
<li>
<p>NES Emulator Debugging (<a href="https://gridbugs.org/nes-emulator-debugging/"target="_blank" rel="noopener">https://gridbugs.org/nes-emulator-debugging/</a>)</p>
</li>
<li>
<p>Two&rsquo;s Complement Multiplication (<a href="http://pages.cs.wisc.edu/~david/courses/cs354/beyond354/int.mult.html"target="_blank" rel="noopener">http://pages.cs.wisc.edu/~david/courses/cs354/beyond354/int.mult.html</a>)</p>
</li>
<li>
<p>NES Hello World (<a href="https://www.embed.com/nes/hello-world.html"target="_blank" rel="noopener">https://www.embed.com/nes/hello-world.html</a>)</p>
</li>
<li>
<p>DF Direct: CRT Displays - Was LCD A Big Mistake For Gaming? (<a href="https://www.youtube.com/watch?v=tvRyVZWuvQ4"target="_blank" rel="noopener">https://www.youtube.com/watch?v=tvRyVZWuvQ4</a>)</p>
</li>
<li>
<p>DF Direct! Modern Games Look Amazing On CRT Monitors&hellip; Yes, Better than LCD! (<a href="https://www.youtube.com/watch?v=V8BVTHxc4LM"target="_blank" rel="noopener">https://www.youtube.com/watch?v=V8BVTHxc4LM</a>)</p>
</li>
<li>
<p>Mod pra Wonderboy II Turma da Monica (<a href="https://www.youtube.com/watch?v=zQCm_y31SC0"target="_blank" rel="noopener">https://www.youtube.com/watch?v=zQCm_y31SC0</a>)</p>
</li>
<li>
<p>Meu fork do emulador de NES em Go (<a href="https://github.com/akitaonrails/nes"target="_blank" rel="noopener">https://github.com/akitaonrails/nes</a>)</p>
</li>
<li>
<p>Meu código do decodificador de código de Game Genie (<a href="https://github.com/akitaonrails/gamegenie"target="_blank" rel="noopener">https://github.com/akitaonrails/gamegenie</a>)</p>
</li>
</ul>
<p>Assinem estes canais:</p>
<ul>
<li>Retro Game Mechanics Explained (<a href="https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g"target="_blank" rel="noopener">https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g</a>)</li>
<li>One Lone Coder (<a href="https://www.youtube.com/channel/UC-yuWVUplUJZvieEligKBkA"target="_blank" rel="noopener">https://www.youtube.com/channel/UC-yuWVUplUJZvieEligKBkA</a>)</li>
</ul>
<h3>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Olá pessoal, Fabio Akita</p>
<p>O tema do video da semana passada é um buraco de coelho de Alice no País das maravilhas. Estou demorando pra soltar videos porque cada assunto que eu esbarro vou pesquisar e abro mais uma dúzia de abas. Daqui a pouco vou encher meus 32GB de RAM só de abas. Computação retro é uma área gigantesca. Vocês não imaginam quantas comunidades existem não só colecionando itens antigos mas ainda desenvolvendo em assembly de MOS 6502 e outros processadores antigos como Z80, Intel 8088 e isso só no mundo dos 8-bits. Se entrar em 16-bits vai cair em processadores como o 65C816 do Super NES.</p>
<p>Eu reescrevi o script de hoje várias vezes, numa das versões eu estava gastando páginas e páginas só pra tentar explicar o problema da multiplicação em processadores antigos. Mas ficou muito fora do escopo do canal. Só pra dar um gostinho, no último video comecei a mostrar um pouco do Assembly do 6502 e algumas instruções básicas como LDA ou STA pra dar load no acumulador ou store do acumulador pra algum outro lugar.</p>
<p>Avançando pra operações aritméticas temos instruções como ADC ou SBC pra adição e subtração. Você já começaria coçando a cabeça quando precisasse somar números maiores do que 255, que é o limite que cabe em 1 byte, ou 8-bits. Lembra que o 6502 é uma CPU de 8-bits? Então todas as instruções só conseguem trabalhar com 8-bits de uma só vez. Pra trabalhar com números maiores a gente particiona o número e calcula 1 pedaço de 1 byte de cada vez. Vamos entender um pouco mais disso.</p>
<p>Como todo mundo pelo menos já deve ter ouvido falar, chips como o 6502 são feitos de componentes menores, como um transistor. Um transistor, em sua essência é um componente que funciona como um switch, ou interruptor. Acho que essa é a imagem mais simples de ter na cabeça. Você pode comprar transistors individualmente empacotados como um componente mais fácil de manipular num protoboard como esse aqui (video).</p>
<p>Aliás, no video anterior eu chamei isso de breadboard que é como falam nos Estados Unidos, mas aqui se chama protoboard. Enfim, usando transistores é possível criar alguns dos circuitos mais simples de todos, as portas lógicas, que são peças fundamentais sobre as quais todo o resto é montado. Por exemplo, você pode montar uma porta lógica NOT num protoboard com um transistor, um resistor, um led pra ver a resposta, uma bateria e fios pra conectar. Uma porta NOT quando você manda 0 ele responde 1, ou quando manda 1 ele responde 0. Uma porta NOT pode ser feito com dois transistors, por exemplo.</p>
<p>Além de NOT podemos montar outras portas fundamentais como OR, AND, NAND, XOR que é exclusive OR e assim por diante. E com essas portas podemos montar coisas mais complicadas como uma CPU inteira. Com outras construções como flip flops, podemos montar memória, e por aí vai. À primeira vista é difícil de entender como operações simples como inverter bits pode ser útil. Vamos pensar numa operação um pouco mais complicada que queremos ter numa CPU, por exemplo somar dois números.</p>
<p>Assumindo que todo mundo sabe somar. Pense uma conta besta, somar 28 mais 22. Você começa somando 8 com 2, vai dar 10, coloca zero embaixo e sobe 1. A mecânica interessante aqui é esse &ldquo;sobe um&rdquo;. Agora soma esse 1 que subiu com 2 do 28 e 2 do 22 e vai ter 50. Pra somar em binário é exatamente a mesma coisa. Pra converter um número decimal em binário, você vai dividindo por dois. 28 dividido por 2 é 14, resto 0. 14 por 2 é 7, resto 0, 7 por 2 é 3, resto 1, 3 divido por 2 é 1, resto 1. Então fica 11100. Pra ser 8 bits só completar os 3 zeros à esquerda.</p>
<p>Fazendo mesma coisa com 22 fica 0001 0110. Números pequenos uma hora você lembra de cabeça, mas pra números maiores qualquer calculadora do Windows mesmo converte pra você. Ou em qualquer linguagem de programação tem uma função de formatar strings onde você passa um inteiro e diz que quer formatar com base 2. Num javascript basta chamar o método .toString com argumento 2 num número.</p>
<p>Pra somar esses dois binários, você começa da direita pra esquerda também, zero mais zero é zero. Depois zero e um é um. 1 e 1 é 2 que em binário é 1 0, então coloca zero e sobe 1. 1 mais 1 mais zero, mesma coisa, coloca zero e sobe mais um. 1 + 1 + 1 é 3, coloca 1 e sobe 1. 1 mais zero mais zero é 1. E o resto é zero. Então o resultado final é 0011 0010. Só parece difícil porque você ainda não tá acostumado a enxergar zeros e uns, mas a regra é a mesma e usa a mesma mecânica do &ldquo;sobe um&rdquo;.</p>
<p>A máquina de adição mais simples que soma 2 bits é chamado de half adder ou meio somador. Você liga uma porta AND com uma porta XOR e vai ter a soma e o carry bit. Carry é o bit onde grava o &ldquo;sobe 1&rdquo;. O meio somador vai fazer exatamente o que eu fui descrevendo agora. Se passar 0 e 0 a soma é 0. Se passar 1 e 0 ou 0 e 1 a soma é 1. Se passar 1 e 1 a soma é 2, então baixa 0 e sobe 1 pro Carry bit. A versão completa se chama full adder ou somador completo.</p>
<p>Um dos jeitos de montar um somador completo pode ser ligando duas portas XOR, duas portas AND e uma porta OR. Ou melhor ainda, ligando dois meio somadores. A diferença é que além dos 2 números pra somar ele também recebe o carry bit de entrada e com isso podemos cascatear múltiplos circuitos de somador completo um embaixo do outro, ligando o carry bit de saída de um somador na entrada do outro. Se quisermos somar com números de 4-bits adicionamos 4 somadores completos em cascata. Pra 8-bits precisamos de 8 somadores. E com isso adquirimos um somador completo de 8-bits! (som de zelda)</p>
<p>Um circuito de somador completo pode ser montado de maneiras diferentes e com isso varia o número de transistors, mas pense que na média vai ser alguma coisa na faixa de 10 transistors pra cada somador. Pra somar números de 8 bits vamos precisar de no mínimo uns 80 transistors. Pra hoje em dia isso não parece grande coisa já que um processador A13 Bionic dos iPhone 11 Pro tem 10 bilhões de transistors. Um AMD Ryzen 7 3700X tem quase 6 bilhões de transistors e um AMD Epyc Rome, que é pra servidores, tem mais de 39 bilhões de transistors. Lembrando que são todos chips de 64-bits.</p>
<p>Nosso pobrezinho MOS 6502 de 8-bits tem na faixa de 3500 transistors, lembrem-se que estamos falando do meio dos anos 70. O que viemos fazendo depois, além de aumentar mais e mais a densidade de transistors por centímetro quadrado, foi adicionando novas funcionalidades como SIMD que são instruções de single instruction multiple data pra computação paralela, instruções de virtualização como VT-X ou AMD-V, instruções pra criptografia como AES, sem contar que os chips hoje são multi-core então é como se fossem múltiplas CPUs apertadas no mesmo chip. Mas as instruções fundamentais como somar bytes, carregar acumulador, incrementar contador de programas, atualizar apontador de pilha, e coisas assim que vimos no hello world da semana passada ainda é  similar.</p>
<p>Um primeiro insight é que os chips hoje são na ordem de 10 milhões de vezes mais densos de transistors que os chips dos anos 80 pra trás. Porém isso não se traduz necessariamente em programas 10 milhões de vezes melhor. Pegue o melhor da geração 8-bits que foi Super Mario 3 e compare com New Super Mario Bros rodando no Switch cujo SoC Tegra X1 tem na faixa de 7 bilhões de transistors com 4 cores ARM Cortex A57 ativos.</p>
<p>Vamos descer um pouco mais hardcore pra dar mais contexto com o tipo de CPU que estamos trabalhando. Adição eu disse que fazemos mais ou menos do mesmo jeito que você faria no papel somando digito a digito e subindo 1 quando precisa. Se hoje em dia temos transistors de sobra nas CPUs, nos 3500 que tinha num 6502, cada transistor contava. Então só era implementado o estritamente necessário. Somadores completos numa cadeia de 8 bits está implementado na instrução ADC.</p>
<p>Se recapitularmos sobre o pouco que aprendemos sobre assembly do 6502, pra realizar uma adição de números de 8 bits, faz de conta, o número 1 mais 2 poderíamos fazer assim.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>	LDA #$01
	ADC #$02
	STA $6000</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Começa com LOAD do número 1 no acumulador, ADC que é adição com carry onde passamos 2 e ele vai somar com o número 1 que já tava no acumulador, daí armazena ou Store do resultado que fica no A pra algum endereço na memória, como o endereço $6000 que, no video anterior, ia mandar pro chip de trava e de lá pro LCD. Isso é uma coisa que hoje em dia você não se preocupa porque as linguagens de programação já cuidam disso, mas o 6502 faz cálculos com números de 8-bits. O valor máximo que cabe em 8 bits sem sinal é FF ou 255. O que acontece se eu tentar somar 255 + 255? Precisamos de mais bits.</p>
<p>Só porque uma CPU é de 8-bits não quer dizer que não podemos calcular números maiores, mas pra fazer isso precisamos particionar o número e lidar com pedaços dele. Por exemplo, digamos que tivéssemos uma CPU decimal mas que só faz conta com números de 2 dígitos de cada vez, então de 0 até 99. Se somarmos 99 + 5 teríamos 104. Precisaríamos gravar o 1 separado do zero quatro. No caso da soma, eu disse que todo somador completo lida com 1 bit do número. A instrução ADC é como se fossem 8 somadores completos em cadeia pra 8-bits.</p>
<p>Uma nomenclatura que às vezes você vai esbarrar é high order e low order. Quando lidamos com 16-bits, temos 2 bytes. O primeiro byte à esquerda chamamos de high byte e o último à direita de low byte. Dentro de cada byte tem 8-bits o bit mais à esquerda é o MSB ou Most Significant Bit e o último bit é o LSB ou Least Significant Bit, literalmente bit mais significativo e menos significativo. Lembra quando expliquei sobre little endian no episódio anterior? É pegar os 2 bytes e inverter, assim o low byte é lido antes do high byte.</p>
<p>Voltando pra soma, toda vez que tiver um &ldquo;sobe 1&rdquo; ele vai ser gravado no registrador C. Antes de toda soma o certo é usar a instrução CLC, literalmente Clear C, pra limpar esse registrador. Mas podemos não limpar também. Lembra que falei que registradores funcionam como varíaveis globais? Várias instruções deixam efeitos colaterais pra trás, deixando registradores com a sobra do que foi processado. E podemos usar isso a nosso favor, começar somando a primeira metade do número até 8-bits, e depois somar a segunda metade que vai usar o carry no C e continuar a soma com o resto dos bits. Por exemplo, digamos que temos um número grande, de 24-bits tipo o número 2 milhões. Seriam 3 pedaços de 8 bits cada que podemos chamar de high, medium e low byte.</p>
<p>Declaramos então os 3 pedaços do primeiro número A como A hi, A mid e A lo, depois B hi, B mid e B lo. Começamos limpando o registrador C, fazemos a soma dos bytes low, que é dar load no A low, adicionar com B low e guardar esse resultado parcial em B low; depois mesma coisa com os bytes medium e high. A soma final é a junção dos três pedaços de B.</p>
<p>; ex: 8 milhões = $7A 12 00, A_hi = $7A, A_mid = $12, A_low = $00
A_hi,  A_mid,  A_lo
B_hi,  B_mid,  B_lo</p>
<p>START:  CLC         ; Clear C only to start.
LDA  A_lo
ADC  B_lo
STA  B_lo</p>
<pre><code>    LDA  A_mid  ; Note that here we don't re-clear C, but just
    ADC  B_mid  ; let it do its job of adding the 9th bit that
    STA  B_mid  ; didn't fit in the result of the previous byte's
                ; addition.
    LDA  A_hi
    ADC  B_hi
    STA  B_hi
</code></pre>
<p>Pense na sua linguagem favorita, você nunca se preocupa com isso, simplesmente escreveria <code>A + B</code>. Como você tem processamento e memória de sobra e seus programas nunca são particularmente complicados, mesmo que tenha desperdícios, não chega a ser um problema. Mas quando seus recursos são extremamente limitados, desperdiçar bits é um problema real. Desperdiçar ciclos também, porque cada instrução gasta alguns ciclos de clock. Nada sai de graça. Um processador moderno roda na faixa de 2Ghz a 5Ghz hoje em dia, mas um 6502 roda entre 1 a 3 Mhz.</p>
<p>Portanto em máquinas pequenas como o 6520 queremos tanto economizar a quantidade de memória usada quanto o número de instruções pra não desperdiçar clocks. Literalmente podemos fazer dezenas de milhões de instruções a menos por segundo num 6502 do que num processador moderno de qualquer smartphone hoje. Fazer programas simples num computador excessivamente poderoso é muito fácil, qualquer um faz. Eu sempre digo que você sabe quando um programador é bom quando ele consegue programar num sistema com restrições, porque a arte de programar é conseguir tirar o máximo que o hardware oferece.</p>
<p>Vamos dar outro exemplo besta. Já sabemos como CPUs fazem adição. Subtração e multiplicação é a mesma coisa. Podemos desenhar circuitos como no caso do somador completo e implementar com transistors. Como falei antes, no 6502 temos a instrução ADC pra adição e também temos SBC pra subtração, mas não tem multiplicação.</p>
<p>Digamos que você, que nunca estudou nada de engenharia ou ciências da computação pense numa forma de implementar multiplicação só usando operações básicas que falamos até agora como adição, o que você faria? Eu aposto como a solução mais imediata que a maioria pensaria seria via adições sucessivas. Por exemplo se quisermos multiplicar 278 vezes 7, você iria somando 278 sete vezes até dar 1148. Seriam só 7 adições e não parece tão ruim assim. Aquele famoso caso de &ldquo;testei aqui e no meu computador funciona&rdquo;.</p>
<p>Mas e se quisermos multiplicar 10 mil vezes 10 mil? Agora precisa fazer 10 mil somas pra chegar no resultado. Isso é consideravelmente mais devagar e com números maiores só vai piorando. Vamos usar tempos hipotéticos só pra ilustrar. Pra somar cada bloco de 8 bits digamos que precisariamos gastar uma instrução de LOAD, uma de ADC e outra de STORE, cada um custando uns 5 ciclos de clock. 10 mil é um número que podemos representar em 2 bytes ou 16 bits. Então são pelo menos 2 loads, 2 adc e 2 stores pra cada rodada.</p>
<p>Então temos 6 instruções custando uma média de 5 ciclos de clock, ou seja 30 ciclos. Em 1 Mhz podemos ter no máximo umas 33 mil sequências dessa por segundo. Mas se precisamos executar 10 mil sequências de soma dessas gastaríamos 1/3 de segundo ou pelo menos 300 milissegundos. Lembrando que estou considerando condições ideais de temperatura e pressão, como a gente falava no colégio, mas provavelmente gastaria mais ciclos que isso. Parece pouca coisa mas 300 milissegundos é mais tempo que leva pra você pedir uma página num site, ele processar, retornar o HTML e seu navegador renderizar. Aliás, se sua aplicação web demora 300 milissegundos pra responder, isso é considerado lento quase parando.</p>
<p>Pra variar, não existe uma fórmula universal de multiplicação que tem 100% de melhor performance pra todos os casos. O bom senso é o contrário: fórmulas universais costumam ser lentas. Isso é uma coisa que, como programador, você precisa entender: existem fórmulas que funcionam melhor pra casos diferentes. Por exemplo, no episódio anterior eu já disse como faz multiplicação por 2: basta fazer um shift left, que é o equivalente a adicionar um zero no final do binário e pronto, tá multiplicado numa única instrução.</p>
<p>Você não conhece formas diferentes de multiplicar? Deixa eu contar um diferente. Existe um método ensinado no primário de escolas Russas que ficou famoso porque a gente associa tudo que é russo com excelência em matemática. Na real é um método bom pra números pequenos e não é particularmente bom pra computadores. É chamado de método do camponês russo. Vou explicar de curiosidade.</p>
<p>O método é assim: dobre o primeiro fator, divida o segundo fator pela metade. Se o segundo fator for par ignore e repita. Se o segundo número for ímpar, some o primeiro fator com o anterior. Por exemplo, digamos que eu quero multiplicar 278 por 7 como falamos antes. Primeiro dobramos o primeiro fator. Multiplicar por 2 todo mundo consegue fazer de cabeça e vai dar 556. Daí 7 divido por 2 é 3. 3 é impar então somamos 556 com 278 e temos 834. Agora dobramos 556 de novo e vamos ter 1112. No segundo fator temos 3 dividido por 2 que é 1, que é impar, então somamos com 834 com 1112 e vamos ter 1.946. Como o segundo fator chegou a 1 acabamos e a resposta é 1.946. Pode abrir uma calculadora aí e checar.</p>
<p>Não é difícil implementar isso em Assembly. Existe um site excepcional que é a fonte de referência de qualquer um que quer implementar um emulador de NES que é o Wiki Nesdev e quando fala de multiplicação ele implementa justamente esse algoritmo do camponês russo que fica assim:</p>
<p><a href="https://wiki.nesdev.com/w/index.php/8-bit_Multiply"target="_blank" rel="noopener">https://wiki.nesdev.com/w/index.php/8-bit_Multiply</a></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>;;
; Multiplies two 8-bit factors to produce a 16-bit product
; in about 153 cycles.
; @param A one factor
; @param Y another factor
; @return high 8 bits in A; low 8 bits in $0000
;         Y and $0001 are trashed; X is untouched
.proc mul8
prodlo  = $0000
factor2 = $0001

  ; Factor 1 is stored in the lower bits of prodlo; the low byte of
  ; the product is stored in the upper bits.
  lsr a  ; prime the carry bit for the loop
  sta prodlo
  sty factor2
  lda #0
  ldy #8
loop:
  ; At the start of the loop, one bit of prodlo has already been
  ; shifted out into the carry.
  bcc noadd
  clc
  adc factor2
noadd:
  ror a
  ror prodlo  ; pull another bit out for the next iteration
  dey         ; inc/dec don&#39;t modify carry; only shifts and adds do
  bne loop
  rts
.endproc</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Você dá load do multiplicador no acumulador, load do multiplicando no registrador Y e roda essa rotina e ele vai gravar o low byte do resultado no endereço $0000 e o high byte em A. Lembra que números maiores que 8-bits fica particionado em múltiplos bytes? O resultado de uma multiplicação costuma ser um número com o dobro de bytes dos fatores, então multiplicar 2 números de 8 bits dá um resultado de 16 bits.</p>
<p>Esse algoritmo gasta em torno de 150 ciclos. Se seu programa for ter poucas multiplicações pode ser suficiente. Mas qualquer operação que gasta mais que 100 ciclos num 6502 não é exatamente rápido. Existem maneiras mais rápidas que isso. E aqui vem outro insight que como programador você precisa ter na cabeça. Algoritmos costumam ser um balanço de dois fatores: se você quiser economizar memória vai acabar gastando mais ciclos de processamento. Se quiser velocidade economizando ciclos provavelmente vai gastar mais memória. Por exemplo, vamos pensar um pouco mais: como você faria multiplicações rápido no primário, sem calculadora?</p>
<p>Pra números pequenos você provavelmente teria que ter decorado a tabuada, lembram disso? Tenho certeza que a maioria odiava ter que decorar a tabuada. Mas lembrem de uma coisa, a tabuada é uma tabela pré-calculada. Você procura o multiplicando e o multiplicador e instantaneamente tem a resposta. Imagine uma tabela pré-calculada pra todos os números que cabem em 8-bits. Daí basta achar a posição na matriz com o resultado direto. Você vai gastar ciclos pra pré-calcular a tabela da primeira vez ou pode ler direto a tabela de uma ROM. O problema dessa solução é que fácil fácil ela vai ocupar 16 kilobytes de espaço ou mais. Considerando que um Super Mario Bros inteiro cabe em 40 kilobytes estamos falando em gastar 1 terço disso só numa tabela de números, o que seria um enorme desperdício.</p>
<p>Uma tabela pré-calculada é o que chamamos de lookup table e isso é uma técnica usada em todos os lugares da computação. Você que faz desenvolvimento web provavelmente já usou ou vai usar isso. Por exemplo quando faz cache com um Redis ou Memcache, é um lookup table. Quando cria índices numa tabela de banco de dados, isso é um tipo de lookup table. O problema é que se essa tabela for grande demais, o tempo pra procurar na tabela também pode começar a ser um problema, fora desperdício de espaço caso você não planeje direito.</p>
<p>Mas como seria uma maneira melhor então? E aqui a matemática nos ajuda. Se você estudou Álgebra e trigonometria não vai achar estranho o que vou dizer a seguir. Uma multiplicação de dois fatores a e b pode ser descrita de maneiras diferentes. Por exemplo, ela pode ser a exponencial da soma dos logaritmos de a e b. Se quiser ser mais complicado pode ser a soma do cosseno de x mais y com o cosseno de x menos y, tudo dividido por 2. Sendo que x é o arco cosseno de a que também é chamado do cosseno inverso. Arco cosseno é usado pra determinar o ângulo do cosseno em radianos. Y da mesma forma é o arco cosseno de b.</p>
<p>Continuando, a vezes b pode ser também o quadrado de a mais b, menos o quadrado de a, menos o quadrado de b, tudo dividido por 2 ou, finalmente, pode ser o quadrado de a mais b menos o quadrado de a menos b tudo dividido por 4. E essa opção final é que nos interessa, pois podemos reduzir a fórmula pra ser a subtração de a mais b aplicado numa função F, com a menos b na mesma função F, sendo essa função F o quadrado do número que passarmos dividido por 4.</p>
<p>A parte importante é que decompomos o problema da multiplicação numa adição dos fatores, subtração dos fatores e subtração do resultado da tal função F. E a essa função reduz o tamanho do lookup table pra em vez de ser todos os possíveis resultados da multiplicação de todos os números de 8-bits, pra simplesmente ter uma tabela só com o resultado da multiplicação do quadrado dos números. Ou seja, de 1 vezes 1, de 2 vezes 2, de 3 vezes 3 e assim por diante, que é uma quantidade pré-calculada ordens de grandeza menor, caindo dos 16 kbytes que eu falei pra talvez meio kbyte.</p>
<p>E pra calcular o quadrado de todos os números também vai ser rápido porque existe a propriedade que o quadrado do número é o quadrado do número anterior mais um número impar. Quadrado de 1 é zero mais 1. Quadrado de 2 é o 1 anterior mais o próximo impar que é 3, resultado 4. Quadrado de 3 é 4 mais o próximo impar 5 que dá 9. Quadrado de 4 é 9 mais o impar 7 que dá 16. Quadrado de 5 é 16 mais o próximo impar 9 que dá 25 e assim por diante.</p>
<p>E como eu disse no começo, dá pra ir longe estudando sobre assembly. Outros assuntos que tava pensando em cobrir neste episódio incluíam o conceito de complementar de dois, números inteiros com sinal pra lidar com negativos, algoritmo de Booth pra multiplicação e muito mais. Mas é teoria demais pra um único video, por hoje vou parar por aqui. Mas eu queria gastar pelo menos um pouco de tempo mostrando essa linha de raciocínio pra vocês entenderem que não, hoje em dia você dificilmente vai gastar tempo implementando uma multiplicação na mão. Toda CPU já implementa as melhores fórmulas em hardware e pra quem precisa de casos específicos existem bibliotecas voltadas pro campo científico que otimizam os piores casos.</p>
<p>Mas é importante você entender que tudo que uma linguagem te oferece, cada pequena coisinha insignificamente como aquele mero asterisco de multiplicação teve milhares de horas homens de pesquisa, experimentação, otimizações. Literalmente muito suor e lágrimas até chegar no estado da arte que você usa hoje sem nem pensar. É isso que significa subir nos ombros de gigantes, porque é com o conhecimento testado e acumulado de centenas de anos de matemática que esse asterisco de multiplicação se tornou possível e você consegue multiplicar dois números de praticamente qualquer tamanho em microssegundos.</p>
<p>E também é pra entender que muita coisa hoje ainda não tem uma fórmula perfeita. Eu disse que temos CPUs com dezenas de milhões de vezes mais transistors que um 6502 mas ainda assim não temos programas dezenas de milhões de vezes melhores. Isso porque muitas partes do software que usamos ainda não tá rodando da melhor forma possível. Grande parte do que é o trabalho de um programador é não ignorar os problemas e parar pra tentar encontrar formas mais inteligentes de fazer o computador processar.</p>
<p>Muito bem, vamos voltar ao nosso nintendinho. Assim como no exemplo do protoboard do Ben Eater, o PCB que é sigla pra Printed Circuit Board ou placa de circuito impresso, contém o cérebro que é o 6502 e diversos outros chips como chip de RAM, chip de VRAM que é memória de vídeo, e outros componentes como pra ligar seus controles. Tem a PPU que é o Picture Processing Unit ou unidade de processamento de imagens que é a versão primitiva do que hoje você chamaria de GPU. E tem o APU ou audio processing unit pra gerar som.</p>
<p>O nintendinho já foi tão dissecado nas últimas décadas que temos documentação super completa de cada componente em detalhes suficiente pra ter muita gente fabricando chips e PCB novos. Você consegue literalmente comprar um hardware moderno de nintendinho hoje se quiser, e ele vai ser 100% compatível com qualquer cartucho que você tenha guardado.</p>
<p>Mas pro que me interessa, a documentação é tão boa que é possível criar emuladores em software que se comportam exatamente como o hardware. Eu não sei se vocês conseguem entender a beleza disso. Todo hardware tem a capacidade de simular o comportamento de outro hardware via software. E praticamente toda linguagem de programação consegue representar qualquer hardware.</p>
<p>Tendo documentação tão completa como o Wiki Nesdev que eu mencionei antes, poderíamos escrever nosso próprio emulador. E como alguém faria isso? É um processo mais trabalhoso do que difícil porque você precisa ter o trabalho meticuloso de implementar cada detalhe que tá nas documentações, mas por exemplo, podemos começar criando um projeto vazio, digamos usando a linguagem Go. Aliás, como o nintendinho é bem antigo, qualquer linguagem hoje consegue simular um 6502 e os outros componentes.</p>
<p>Não existe &ldquo;O&rdquo; jeito correto de se escrever um software. Se você pegar diferentes emuladores de nintendinho vai ver que eles são organizados e escritos de maneiras diferentes. Só com experiência e muitos testes você vai chegar no que é o melhor balanço entre legibilidade e eficiência. Mas pra ser simples podemos pensar nos componentes principais que eu listei. O primeiro elemento que queremos emular é o console, então começamos criando um arquivo chamado console.go e dentro definimos o tipo Console como uma estrutura. E não se preocupe se você nunca viu Go, não é relevante entender cada linha do código hoje, só o raciocínio. Estude depois com calma.</p>
<p>Essa estrutura vai declarar ponteiros pra CPU, pro APU, pro PPU, pro cartucho, pros dois controles, pra um troço que vou explicar depois chamado Mapper, e delimitamos a RAM que é só um array. Lembram todos aqueles hexadecimais que eu falei no video anterior? Pense nesses números como posições no array. Memória é isso: uma listona de bytes. Agora precisamos criar arquivos pra cada um desses componentes e definir as estruturas de cada um. O próximo é o arquivo cpu.go.</p>
<p>A estrutura CPU vai ter muitos dos elementos que eu expliquei no vídeo anterior. Começamos definindo uma referência pra uma estrutura de Memory que vou explicar depois. Daí definimos PC que é o contador de programa como um inteiro gigante de 64-bits, e nem precisava ser tão grande porque ele só aponta pro endereço da próxima instrução, então 16-bits bastava. Vamos definir o SP que é o apontador de pilha como um inteiro de 16-bits. Daí os registradores todos de 8 bits, ou seja 1 byte. Temos o acumulador A, o X, o Y, o C, Z, I, D, B, U, V, N. E por fim temos uma última estrutura importante, um array de instruções.</p>
<p>Lembra que cada instrução como LDA tem um hexadecimal associado, que é basicamente o endereço da localização dessa instrução? Pois é, precisamos colocar cada opcode na posição correta nessa lista. Quando quisermos achar a instrução 0xa9 que é o LDA vamos pra posição 0xa9 que é a posição 169 nessa lista. Daí vamos encontrar a referência pra uma função de Go. Agora precisamos implementar cada uma dessas funções.</p>
<p>Por exemplo, o nosso LDA sabemos que vai escrever o valor no registrador A que é o acumulador. Então em Go é simplesmente associar o valor do argumento na variável A da CPU.</p>
<p>Sabemos também que JSR é o Jump pra uma subrotina, o que ele faz é empurrar o endereço no contador de programas pra pilha e sobrescrever o contador de programa com o endereço da subrotina pra onde tem que pular.</p>
<p>E assim vai, tem que escrever uma função pra cada instrução que existe de acordo com a especificação na documentação do 6502. Uma vez feito tudo isso podemos criar o inicializador NewCPU que vai alocar a estrutura que definimos. Esse inicializador recebe uma referência pra estrutura de console que criamos antes pra passar pra essa nova estrutura chamada Memory. Deixa esse Memory de lado que ainda não é hora pra ele. Em seguida criamos e populamos a tal tabela com referências pras instruções que criamos. Finalmente criamos uma rotina de reset.</p>
<p>Reset é o que você pensou mesmo: o equivalente a você apertar o botão reset que todo console e computador tem. A idéia é limpar o contador de programas pra apontar pro endereço 0xFFFC, lembra no episódio anterior que quando o 6502 inicializa a primeira coisa que ele faz é ir no endereço 0xFFFC procurar a primeira instrução do programa? Pois é. E em seguida limpamos o apontador de pilha pra iniciar em 0xFD. Isso é pra relembrar a importância desses dois registradores, porque é com eles que conseguimos executar um programa.</p>
<p>Tem mais coisas que precisam ser feitas pra CPU ficar completa mas por agora vamos pular pra essa tal de Memory criando um arquivo memory.go. A estrutura em si é muito simples. Ela só vai apontar pra uma referência à estrutura de Console que já definimos antes. A parte importante começa com a função de leitura Read. Ele recebe um endereço e vai devolver algum valor que teoricamente está em alguma lugar na tal memória.</p>
<p>Aqui começa a diferença de um nintendinho e outros computadores que usam o processador 6502 como um Atari ou Apple II, o mapa de memória. No episódio anterior eu expliquei que temos endereços de 16-bits então podemos mapear do endereço 0x0000 até 0xFFFF, daí dividimos esse espaço e por exemplo a CPU ia procurar no EEPROM se passássemos endereços acima de 0x8000. Ou seja, arbitrariamente definimos que certos chips respondem a certos endereços.</p>
<p>A grosso modo, do endereço 0x0000 até 0x07FF temos 2 kilobytes de RAM. Nos endereços de 0x2000 a 0x2007, que é bem curto, temos registradores pra PPU. De 0x4000 a 0x4017 acessamos a APU e registradores de I/O como os controles e só de 0x8000 a 0xFFFF temos o equivalente a uns 32 kilobytes reservados pra endereços que mapeiam pra algum lugar do cartucho. Em particular se acessarmos acima do endereço 0x6000 temos esse negócio que colocamos no código chamado Mapper. Agora vocês precisam entender os truques que eram usados em consoles com cartuchos.</p>
<p>Se sua história com games começa só depois do Playstation 1, você tá acostumado a ter os games em CDs, DVDs, Blu-Ray ou instalados no HD do seu computador. É de praxe que toda vez tem que esperar o famoso &ldquo;Loading&rdquo;, que é o tempo do computador começar a carregar os primeiros bytes do jogo na RAM pra só depois conseguir começar a jogar. Daí a cada fase tem que carregar novos bytes pra RAM e jogar fora os bytes da fase anterior que não vai precisar mais. Isso é necessário porque não cabe todo o jogo na memória. Um computador muito bom hoje tem 16 GB, mas qualquer jogo moderno tem 30 GB, 40GB, alguns jogos podem ter absurdos 100GB. Obviamente não cabe tudo na RAM então precisa ir carregando e descarregando de pedaço em pedaço.</p>
<p>Com cartuchos é diferente. O que tem num cartucho são chips de ROM, como expliquei no episódio anterior. Então quando você pluga o cartucho no console, não existe loading, não tem que carregar nada e ele pode iniciar imediatamente porque a CPU acessa os endereços diretamente da ROM, sem precisar carregar o jogo em memória. O cartucho &ldquo;É&rdquo; a memória. Entenderam? Diferente de CD ou HD, a ROM do cartucho já tem velocidade máxima de acesso, igual da RAM. Da mesma forma que a CPU consultaria um endereço na RAM, no caso pedindo endereços de 0x0000 a 0x07FF, quando ele precisa de dados do jogo ele pede nos endereços acima de 0x8000 até 0xFFFF.</p>
<p>Por isso jogos de consoles antigos carregam instantaneamente e não tem loading entre fases e tudo é rápido. Um dos maiores gargalos ainda não resolvidos em games modernos de fato é a lentidão do I/O, não só do HD mas de toda a cadeia que carrega dados, incluindo barramento, controlador e tudo mais. Inclusive é isso que a nova geração de consoles PS5 e Xbox Series X estão tentando combater colocando os SSDs e controladores mais rápidos do mercado pra minimizar ao máximo o tempo de carregar coisas do disco. Mesmo assim o tempo nunca vai ser zero como era nos cartuchos.</p>
<p>Vou repetir o que eu disse antes: programação é sempre um trade off, uma troca. Cartuchos tem tempo quase zero de acesso porque ele é direto um chip de memória. O problema é que chips de ROM são muito mais caros de produzir comparado a discos de HD ou Blu-Rays. É bem mais caro. A comparação mais óbvia foi na transição dos cartuchos pro CD quando saiu o Playstation 1 e o concorrente na época era o Nintendo 64 que preferiu usar cartuchos pelas razões que eu acabei de falar.</p>
<p>Jogos de Playstation podiam ter videos e muito mais conteúdo porque num CD daquela época era possível colocar até 650 megabytes de dados. Em comparação um dos maiores cartuchos de Nintendo 64 era Conker&rsquo;s Bad Fur Day que tinha enormes 60 megabytes, ou seja mais de 10 vezes menos espaço e o cartucho ainda custava mais caro. Os lendários Zelda Ocarina of Time e Majora&rsquo;s Mask eram cartuchos de menos de 30 megabytes. Por isso jogos de Nintendo 64 raramente tinham algum video e também por isso preferiam usar o mínimo de texturas nos modelos em 3D, porque texturas são imagens bitmap que consomem muito espaço.</p>
<p>Voltando pra era dos 8-bits. Um cartucho como do Super Mario original tem 40 kilobytes, portanto male male encaixa no nosso espaço de endereços reservados pra ROM. Mas um Super Mario 3 tem 385 kilobytes, quase 10 vezes mais bytes que o original. Um dos jogos mais pesados do nintendinho é Kirby&rsquo;s Adventure e se você rodar vai ver um dos games mais bem elaborados pro nintendinho, chega perto do que seria um jogo de Super Nintendo. Também pudera, o cartucho dele tem quase 800 kilobytes, perto de 1 megabyte.</p>
<p>Mas como é possível endereçar isso tudo de bytes só com endereços de 16-bits? Agora vem o segundo grande fato sobre cartuchos: eles não tem só chips de ROM. Na realidade um cartucho é uma placa de expansão, um PCB completo. Quando falo em placa, pense mesmo como quando você compra uma placa gráfica como um novo NVIDIA RTX e espeta no slot PCI Express na placa mãe do seu computador. Encaixar um cartucho no console é a mesma coisa.</p>
<p>Num PCB você pode plugar não só ROM como qualquer outro componente. Por exemplo, você pode colocar um chip de SRAM e uma bateria de lítio e boom, você acabou de ganhar a capacidade de salvar o jogo. Só que isso torna o cartucho ainda mais caro, por isso nem todo jogo podia salvar. Um dos chips mais famosos se você jogou Super Nintendo foi o chip Super FX, que literalmente era uma placa primitiva 3D que permitiu jogos como Star Fox. O processo é o mesmo, o chip vem no PCB do cartucho.</p>
<p>Você literalmente poderia enfiar um nintendinho inteiro dentro de um cartucho. Mas só isso não responde a pergunta de como fazia pra um Kirby ter quase 1 mega de dados. Não basta só enfiar mais chips de ROM se não temos endereços suficientes pra passar de 32 kilobytes. Endereços funcionam como o nome diz, é como se tivéssemos uma rua de casas e só tivesse 32 números, da casa 33 em diante ficaria sem números. Se o carteiro precisasse entregar alguma coisa nessas casas como ele encontra?</p>
<p>E se nessa rua colocássemos um síndico? Que separasse a rua em blocos? Daí teria casa de 1 a 32 no bloco A, casas de 1 a 32 no bloco B e assim por diante. Continua só tendo 32 números mas dependendo do bloco sempre encontraríamos uma casa diferente. E é exatamente isso que o nintendinho faz. No cartucho, além de vir mais ROM ele vem com um síndico, um controlador que chamamos de Mapper.</p>
<p>Como o nome diz, Mapper é um mapeador. Em vez de blocos na rua do nosso exemplo a memória ROM é dividida em Banks ou bancos. E a técnica pra enxergar mais memória se chama Bank switching. A CPU continua só conseguindo enxergar dos endereços 0x8000 a 0xFFFF mas ele pode pedir pro Mapper trocar os banks, assim como no exemplo dos blocos da rua. Os banks costumam ter 16 kilobytes de tamanho e podemos ter vários banks, então se montarmos o cartucho com ROM suficiente pra 50 banks de 16 kilobytes, vamos ter os quase 800 kilobytes do jogo Kirby.</p>
<p>Agora vem a parte cabeluda pra fazer emulador de NES: não basta só escrever código que representa o console, precisa também emular os chips que vem nos cartuchos, em particular esses mappers. Você poderia imaginar que deve ter alguns poucos modelos de mappers. Mas que nada, se olhar a biblioteca toda de games de nintendinho existem 407 mappers que foram encontrados e documentados. Por sorte, se você cobrir os mappers da própria nintendo e alguns de marcas famosas como Konami, já cobre a maior parte dos jogos. Muitos mappers só existem em jogos muito obscuros, feitos na China ou lugares assim.</p>
<p>Se você olhar de novo no wiki da nesdev vai encontrar o código que vem no cartucho que identifica qual mapper ele tem. No arquivo de Memory ele vai selecionar um Mapper baseado nesse código identificador que ler da ROM. Daí precisamos de cada um dos Mappers, que precisam responder às mesmas funções. Por isso no nosso arquivo de mapper vamos definir uma interface que todos os mappers vão ter que implementar. Basicamente definimos o que um Mapper precisa obrigatoriamente fazer, que é ler da ROM, gravar na RAM e coisas assim.</p>
<p>No inicializador pegamos o cartucho associado no console. Depois que carregarmos uma ROM ele vai preencher esse campo Mapper com seu código identificador, e com isso podemos checar qual mapper vamos ter que carregar. Neste pequeno emulador em Go vai ter só alguns dos principais. De curiosidade esse último mapper código 225 é que permite aqueles cartuchos de 52 jogos em 1 que você já deve ter visto por aí. Um cartucho desses tinha 6 chips de ROM com meio megabyte cada.</p>
<p>Não vou entrar no detalhe de cada um, senão a gente fica aqui até o ano que vem, mas só pra mostrar um, podemos criar um arquivo pro mapper 2. Lembrando que no nosso caso, usando máquinas modernas, não temos esses limites pequenos de 16-bits. Podemos carregar a ROM de um cartucho como um arrayzão contínuo de bytes, seja lá quantos bytes tiver porque temos espaço pra mapear tudo. Então recebemos o endereço que o CPU manda e mapeamos com esse arrayzão.</p>
<p>No caso, o que nos interessa é que quando carregamos a ROM os bytes são identificados como regiões distintas, sendo as duas principais o PRG e CHR. PRG são bytes de programa. CHR são os bytes de caracteres, que é a área onde normalmente estão os tiles. Eu sempre chamo de tiles mas se for traduzir é como se fossem azulejos. Tiles, azulejos, caracteres, são termos que significam a mesma coisa.</p>
<p>O princípio de tiles é simples. Um CPU como o 6502 não fica dando instruções pra escrever pixel a pixel na tela. Ele pede pra escrever tiles. Pense num nintendinho como um editor de textos. Um editor não escreve pixel a pixel na tela, ele escolhe uma letra de alguma família de fontes, digamos Arial, e passa o código que representa ela. E o Windows ou MacOS da vida que vai se encarregar de realmente desenhar os pixels.</p>
<p>No nintendinho quem se encarrega de desenhar os pixels é o chip chamado de PPU que eu falei que é a unidade de processamento de pixels. O CPU não entende pixels, ele entende tiles. Significa que o PPU tem que trabalhar bastante pra desenhar pixel a pixel. Inclusive o clock do PPU é maior que do CPU. Mas a CPU só precisa mandar um byte pra identificar blocos de 8 por 8 pixels de uma vez só, em vez de mandar 64 comandos independentes pra cada um desses pixels.</p>
<p>Se você é de web front-end já lidou com algo assim, é como os sprites de CSS. Aliás a técnica de sprites de CSS não é novidade, isso é uma técnica antiga. Outra técnica antiga são fontes com imagens, como a Font Awesome que todo site hoje usa pra desenhar icones. A memória CHR da ROM que eu falei é como se fosse uma Font Awesome, literalmente caracteres. Cada caracter, ou fonte, é um tile. Acho que assim vocês conseguem visualizar na cabeça. Consoles antigos assim sequer tem fontes ou tabela de letras. Cada jogo define suas fontes e o código das letras, não tem um padrão como ASCII ou Unicode.</p>
<p>A PPU enxerga a resolução máxima de 256 por 240 pixels, e a CPU só enxerga uma grade de 16 por 15 espaços onde cabem os tiles. É parecido com um computador DOS antigo que tem resolução de 640 x 480 mas em modo DOS só enxerga 80 colunas por 25 linhas de texto. O PPU também só consegue enxergar 8 kilobytes de tiles de cada vez, então toda vez que precisamos de tiles diferentes, o CPU pede pro Mapper trocar o banco por outro. Existem dois excelentes emuladores pra quem quer aprender a programar jogos de verdade de nintendinho. Um deles é o FCEUX que acho que é o mais conhecido e o outro é o Mesen que eu acho que tem ferramentas mais modernas.</p>
<p>Vocês entenderam o que fizemos até agora? Eu fui estruturando o nintendinho como código de Go. Cada aspecto dele são estruturas de dados normais como arrays e bytes. Bytes na memória que sabemos exatamente onde estão e com isso podemos consultar a qualquer momento. Seja o emulador feito em Go, em C ou C++ vai ser a mesma coisa. O emulador Mesen implementa de forma parecida mas além de só emular ele expõe essas estruturas de forma visual em tempo real. Por exemplo, podemos abrir um visualizador da memória da PPU e organizar pra vermos os bitmaps.</p>
<p>E olha só o que tem na memória da PPU, esses são os tiles. Cada tile é um quadrado de 8 por 8 pixels. Se eu não estou enganado, podemos associar até 4 cores pra cada um, dentre 12 cores de uma paleta, num total de 4 paletas que posso escolher. Em outra aba podemos ver as 12 cores da paleta de background e outras 12 cores da paleta pros sprites. Se você já brincou de front-end, HTML e CSS certamente já viu código de cores em hexadecimal, é a mesma coisa.</p>
<p>Como a localização dessa área CHR na ROM é conhecida, podemos editar o que tem lá. Os tiles são bitmaps não comprimidos. Hoje em dia você tá acostumado a lidar com imagens comprimidas como JPEG que usa um algoritmo lossy, ou seja, que perde detalhes da imagem pra reduzir o tamanho. Um bitmap é exatamente o que o nome diz, um mapa de bits, nas posições exatas pra formar a imagem e sem  compressão.</p>
<p>Só pra mostrar como podemos afetar o jogo, com o Mesen rodando podemos editar as cores da paleta de background e trocar a cor do céu de azul pra outra cor. Ou podemos mexer na paleta de sprites e trocar a cor do Mario. Você pode mudar completamente a aparência do jogo só de ajustar as cores dessa forma.</p>
<p>Repetindo, pense na tabela de tiles como se fosse uma tabela de fontes de letras. Aliás, o nintendinho sequer tem fontes. Ele não tem um sistema operacional, o jogo começa rodando direto no hardware, sem nenhuma camada intermediária pra ajudar. Então se um jogo quer escrever textos na tela, ele próprio precisa embutir tiles de fontes. E de fato você vai ver que normalmente começando no endereço zero dessa área CHR costuma ter letras, números e símbolos. Aqui o número zero é a posição zero mesmo, o número um é posição um e assim por diante. E começando do zero até a letra F fica bonitinho de 0 a F em hexadecimal.</p>
<p>Lembra quando usamos no Linux a ferramenta hexdump ou xxd e na terceira coluna ele tenta interpretar bytes que mapeiam pra tabela ASCII como letras e às vezes aparecem textos mesmo? Numa ROM de videogame isso não funciona porque os códigos das letras não seguem a tabela ASCII. Mesmo entre jogos diferentes a posição das letras na ROM não é a mesma. Por isso em emuladores com debug como o Mesen e FCEUX podemos carregar nossa própria tabela que mapeia código das posições dos tiles pra letras, como essa na tela que é um arquivo texto com extensão TBL. Assim podemos tentar reconhecer algum texto no meio do binário.</p>
<p>Vejam no espaço PRG da ROM que não dá pra identificar nada. Mas carregando a tabela começamos a reconhecer quais bytes são textos. E com isso posso editar o texto, por exemplo trocando de MARIO pra FABIO. Resetamos o jogo e olha só como aparece meu nome. Podemos trocar todos os textos num cartucho e salvar o binário por cima, contanto que o texto novo caiba no mesmo espaço usado pelo texto antigo. Esse é o hacking mais simples de todos e que todo mundo que já brincou com binários já fez na vida. É assim que muita gente traduziu cartuchos japoneses pra inglês, por exemplo. Se tiver filhos pequenos imagino que eles vão gostar de ver os nomes deles nos jogos.</p>
<p>E podemos editar o binário não só do texto como dos tiles. Por exemplo, existem programas como o Tile Layer Pro. Se abrirmos a ROM do Super Mario, no começo vamos ver um monte de sujeira que são bytes de programa, mas se descermos vamos encontrar os tiles do jogo. Pra enxergar melhor podemos mudar a paleta e rapidamente vamos começar a reconhecer alguns, como os tiles que formam o personagem. Pra ver melhor, podemos arrastar os tiles pra esta outra janela e montar como um quebra cabeça. O Mario grande é formado por seis tiles. Na ROM tem a sequência pra cada posição da animação, seja correndo ou pulando.</p>
<p>Podemos fazer mais, podemos editar cada tile e mudar o jogo completamente. É um puta trampo editar tile a tile mas se tiver paciência fazendo isso eu poderia pegar os bits de tiles de um Zelda ou Megaman e mudar o Mario pra ser o Link, ou qualquer outro personagem que caiba em seis tiles ou menos. E só com as técnicas eu mostrei aqui você poderia fazer um novo jogo usando um que já existe como base.</p>
<p>Sabe quem já fez isso? A Tectoy aqui no Brasil. Por causa deles nós somos o único país no mundo que ainda produz Master System novo até hoje. O Master System foi o concorrente do nintendinho nos anos 80. Também é um console de 8 bits mas no papel ele era tecnicamente superior. Em vez do MOS 6502 de 1.8 Mhz o Master System vinha com o Zilog Z80 que ia até 3.5 Mhz, quase o dobro de clock. Em vez de 2k de RAM e 2k de VRAM ele vinha com 8k de RAM e 16k de VRAM. Em vez de ser limitado a ter só 16 cores na tela, ele podia ter 32 cores, por isso jogos de Master System sempre parecem mais coloridos e vivos</p>
<p>Essa discussão de especificações e jogos sempre foi uma constante nas rodas de gamers. Um Xbox One X é tecnicamente mais poderoso que um PS4 Pro, mas o Playstation continua tendo alguns dos melhores jogos exclusivos como God of War ou Spiderman. Nos anos 80 não era diferente. O Master System era mais poderoso mas as marcas que chamavam mais atenção estavam no Nintendinho.</p>
<p>De qualquer forma o Master System conseguiu um público cativo aqui no Brasil e a Tectoy começou não só a licenciar e distribuir jogos estrangeiros como começou a lançar jogos brasileiros. Um grande exemplo que eu lembro que me impressionou na época foi o jogo da Turma da Mônica.</p>
<p>Esse jogo na realidade é o Wonder Boy II com textos e sprites editados pra encaixar numa história da Turma da Mônica. Se nunca viram olhem lado a lado.</p>
<p>A Tectoy produziu vários jogos usando essas técnicas como Geraldinho, Sapo Xulé, TV Colosso. Mas fazendo isso eles foram aprendendo como de fato programar no Master System e começaram a produzir jogos mais elaborados. Por exemplo, um dos melhores jogos de Master System sem dúvida é Castle of Illusion. Daí a Tectoy pegou emprestado elementos desse jogo e fez um terceiro jogo na sequência do também excelente Land of Illusion, com fases novas e inimigos novos e chamou de Legend of Illusion. É bem claro onde são sprites dos jogos anteriores e quais são sprites desenhados do zero. A parte artística ainda tava bem primitiva, mas já é uma evolução.</p>
<p>Mas quando você treina e vai aprimorando as coisas melhoram. Por exemplo, eles começaram a experimentar com a idéia de pegar jogos de Mega Drive, que é um console bem mais poderoso que o Master System, pegar os sprites e elementos visuais e diminuir detalhes, diminuir cores, diminuir frames de animação pra tentar fazer caber no Master System. E fazendo isso eles de fato conseguiram alguns jogos interessantes. Mesmo a jogabilidade não sendo nada boa, eu acho interessante pela tentativa. Só no Brasil existem jogos como Street Fighter, Mortal Kombat, Ecco the Dolphin e A Pequena Sereia pra Master System.</p>
<p>Tem vários videos no YouTube contando a história da Tectoy. Tem até vários canais gringos descobrindo a Tectoy só agora e ficando impressionado de ver o Master System e Mega Drive sendo fabricados por aqui até hoje, recomendo darem uma olhada, é uma parte da história da nossa indústria brasileira que infelizmente ficou parado nos anos 90 e não conseguiu evoluir. Aliás, recentemente lançaram um remake HD do Wonderboy II que ficou bem bacana e tá em lojas como Steam. E claro, alguém fez um mod pra ele relembrando o jogo da Turma da Mônica. Então você tem uma versão HD disso também! Vale conferir só pela nostalgia se você jogou o original no começo dos anos 90.</p>
<p>Bom, vamos voltar pro nintendinho. O que eu mostrei do código do emulador é só o começo do esqueleto. Na verdade eu não escrevi um emulador não, esse foi um projeto que achei aleatoriamente no Github. Vocês podem baixar a versão completa no link que vou deixar nas descrições abaixo. E pra mostrar que ele funciona vamos compilar e executar.</p>
<p>(nes)</p>
<p>Um último insight que eu queria aproveitar pra falar é sobre o PPU. Como expliquei ele era o equivalente aos nossos GPUs de hoje só que muito mais primitivo. Se havia um chip que trabalha incessantemente no nintendinho era o PPU, desenhando 60 quadros por segundo sem parar. Na verdade são dois insights. Vamos lá. Pra começar eu disse que o MOS 6502 roda a meros 1.8 Mhz que é milhares de vezes mais lento que qualquer CPU de hoje.</p>
<p>Antigamente jogos tentavam usar o máximo que a CPU podia oferecer e o timing de tudo era atrelado ao clock do sistema. Hoje em dia não fazemos isso, em vez de atrelar ao clock atrelamos a outras coisas como framerate que é a taxa de quadros por segundo ou vsync que sincroniza com a frequência de atualização do monitor. Ou seja, se temos como alvo rodar o jogo a 60 quadros por segundo, vamos calcular tudo pra caber na faixa de 60 quadros por segundo. Mesmo se o clock aumentar ou diminuir, a referência vai ser os quadros por segundo. Se a CPU for lenta demais vamos ser obrigados a cortar quadros. Se a CPU for rápida demais vamos dar pausas pra esperar. Estou simplificando, claro.</p>
<p>Mas jogos antigos não tinham o luxo de esperar, cada clock contava. Por isso se programava em assembly pra ter controle absoluto do hardware. Daí quando os CPUs evoluiram na geração seguinte e pularam de 1Mhz pra digamos 40Mhz os jogos ficaram rápidos demais. Até por isso nos 386 de antigamente tinha um botão Turbo. A idéia desse botão era diminuir o clock do sistema pros programas não rodarem rápidos demais. Se você tentar rodar um jogo dos anos 80 num PC moderno vai ver que ele roda rápido demais ao ponto de ser injogável.</p>
<p>Um dos desafios mais difíceis nos emuladores de consoles antigos é literalmente adicionar pausas em cada passo pro jogo rodar exatamente como seria antigamente, se não tiver esse controle de pausas o jogo rodaria rápido demais. E nosso emulador precisa levar isso em conta. Por isso temos que editar o arquivo do CPU e adicionar outra informação importante: uma lista dizendo quantos ciclos cada instrução consome. Lembra que falei que um Load, Adição e Store consomem em média uns 5 ciclos? Não pode ser aproximado assim, tem que ser a quantidade exata de ciclos. Então vamos adicionar a lista, onde cada posição é o endereço da instrução como declaramos na estrutura table.</p>
<p>O segundo insight que falei tem a ver com timing de velocidade. O PPU é ocupado demais, ele não pode parar de desenhar na tela. Ele roda com clock 3 vezes mais rápido que a CPU e precisa de uma rotina pra sincronizar. A coordenação entre CPU e PPU é um assunto fascinante em si só mas a parte importante é que a CPU não pode interromper a PPU a qualquer momento. Ela vai estar escrevendo pixels na tela numa frequência precisa e se você interromper, vai quebrar toda a renderização.</p>
<p>Significa que do lado da CPU digamos que você detecte que um botão foi pressionado no controle. Digamos que foi um botão de salto. Você iria querer imediatamente mostrar isso na tela acionando a animação de salto do Mario por exemplo. Então você processa esse estado e envia o comando pro PPU atualizar o sprite do Mario. Mas isso vai quebrar a renderização, então como faz?</p>
<p>A característica importante do PPU é que ele escreve na tela uma linha horizontal de cada vez. Isso se chama ScanLine e é derivado de como monitores de tubo funcionam. Se você nunca viu ele não escreve pixels em qualquer coordenada. No fundo do tubo existe um canhão, que vai atirando eléctrons na tela de fósforo na frente dele uma linha horizontal de cada vez e fazendo um zigue zague pra próxima linha. Diferente de LCDs modernos que tem uma quantidade fixa de linhas, monitores de tubo podem ter quantas linhas quiser, basta o canhão distanciar ou aproximar essas linhas. Por isso bons monitores de tubo tendem a ter imagens melhores do que LCDs. Recomendo ver esse video da Digital Foundry que explica sobre a qualidade esquecida dos CRTs e como eles ainda superam os LCDs.</p>
<p>De qualquer forma, o PPU do nintendinho vai desenhar 240 linhas visíveis e depois vai entrar num período entre as linhas 240 a 260 em que ele não desenha nenhuma linha visível. Isso se chama Vertical Blank ou Vblank. Isso acontece 60 vezes por segundo, uma vez depois de desenhar cada frame. É nessa pequena janela de 20 ScanLines que o PPU tem a oportunidade de ser interrompido e receber ordens da CPU, por exemplo, dizendo o que tem que desenhar no frame seguinte.</p>
<p>De novo, se você é de front-end, uma das boas práticas que deve ter aprendido, principalmente se usa frameworks como um React é nunca escrever direto no navegador. Você acumula todas as modificações e escreve tudo de uma vez depois. E como você faz isso? Em vez de mandar ordens de desenhar direto na árvore de elementos HTML do navegador, o famoso DOM, você manda escrever numa cópia desse DOM que só existe em memória, o famoso Virtual DOM. Então se você modificou 50 elementos nesse VDOM, você não precisou interromper o navegador 50 vezes. Você guarda essas modificações em memória e só interrompe o navegador uma vez pra desenhar só o que mudou, uma vez só.</p>
<p>E é quase isso que se faz no nintendinho também. A idéia de separar lógica da  apresentação não é novidade. É assim que se programa desde pelo menos os anos 80. Então do lado da lógica do jogo na CPU ele faz as modificações em RAM e durante o Vblank o PPU puxa essas modificações e avança pro próximo frame, e com isso temos uma separação de responsabilidades.</p>
<p>Como cada jogo monta estruturas diferentes pra representar o que precisa mandar pra PPU. Mas um jogo que é visualmente fácil de acompanhar é o Super Mario Bros 3 porque ele mantém a estrutura completa da tela com cada elemento aberto na RAM. Se você procurar por memory map e o nome do jogo no Google facilmente vai achar a documentação que várias pessoas gastaram horas garimpando e com isso sabemos que a partir do endereço 0x6000 na RAM vai ter os dados de montagem de cada tela da fase.</p>
<p>Vamos abrir no Mesen e vou colocar lado a lado pra vocês verem. Se procurarmos na RAM depois do endereço 0x6000 rapidamente vamos encontrar padrões que se assemelham à tela que estamos, e na sequência vai tendo todas as outras telas dessa fase. Olhem os códigos internos de cada bloco dessa tela e veja como o código muda quando eu modifico um objeto, por exemplo batendo nele.</p>
<p>E se você é adepto de Mario Maker, esse é o Mario Maker raíz. Vamos olhar algumas telas pra frente. Por tentativa e erro sabemos que essas &ldquo;arrobas&rdquo; representam moedas. Vamos criar um monte &hellip;. e agora vamos até essa tela. &hellip; Olha que bonito. E de novo vejam como cada vez que vou pegando as moedas o código se modifica na RAM.</p>
<p>De novo usando a analogia com front-end, isso é o equivalente a você dar um inspect no navegador e sair editando os elementos. E aproveitando que estamos no Mesen, vamos abrir primeiro o Super Mario de novo. E esses são todos os tiles que tem no cartucho, somente um único bank de 16 kbytes. Pense que o jogo inteiro, que não é curto, é desenhado somente com esses tiles. É impressionante se considerar que antes dele você só tinha jogos nível pacman bem simples e eles conseguiram esticar pra múltiplas fases que parecem diferente mas que são basicamente os mesmos tiles com paletas diferentes de cores.</p>
<p>Mas se abrirmos o Super Mario 3 de novo, que vem com o Mapper conhecido como MMC5, ele vai ter bem mais banks como eu expliquei. E olha só no visualizador de novo. Podemos ir explorando os diferentes banks que são os conjuntos de tiles. E por isso o Super Mario 3 tem visuais bem mais elaborados e diferenciados de mundo pra mundo. Não é só uma mudança de paleta de cores mas de diversidade de tiles. E no último olha como só a tela de entrada com título grande ocupa um bank quase inteiro. Por isso quando tem imagens bitmap grande que ocupam a tela inteira a gente sabe que é um jogo caro porque literalmente ele tá usando uma parte considerável do chip só pra guardar essa uma imagem que só aparece uma vez.</p>
<p>Recentemente teve uma ressurgência de games independentes publicando nos Steam da vida que tentam emular o visual pixel art pra ter aquela vibe de jogo retro. Um bom exemplo disso é o excelente jogo Celeste, considerado um dos melhores jogos de plataforma pra speedrun pela nuance nos controles e como ela recompensa quem consegue combinar timing com movimentos avançados do jogo pra percorrer as fases. Outros exemplos são os já classicos Meat Boy ou Shovel Knight também. Mas o que esses jogos tem em comum é que eles são modernos mas só escolheram um estilo artístico de pixel art pela estética e não porque foram obrigados a isso.</p>
<p>Entendam, jogos antigos não são pixel art porque o povo gostava do estilo mas sim porque a resolução da tela era de meros 256 pixels na horizontal por 240 pixels na vertical. Isso é um quarto da resolução de um monitor full HD que tem 1080 pixels na vertical. Cabe literalmente 16 telas de nintendinho numa tela full HD. Mas agora você entende também que não é só a resolução, todo o design do jogo, das fases, inimigos e outros elementos dependem muito do espaço na ROM. Quanto mais ROM se adicionava no cartucho mais caro ele ficava. Por isso a maioria dos jogos se mantinha nos limites de 40 kilobytes que o Super Mario original usava. Em comparação, a instalação do jogo Celeste tem mais de 700 megabytes.</p>
<p>Existem vários programadores hoje explorando programar no hardware limitado do nintendinho. Um grande exemplo é o jogo Micro Mages da Morphcat Games. Dois anos atrás eles soltaram um mini documentário mostrando como as limitações do console e do cartucho influenciaram as decisões de design do jogo. Eles se colocaram no desafio de fazer um jogo de verdade, bem feito, escrevendo em Assembly de 6502 e ainda suportando 4 jogadores simultâneos.</p>
<p>O jogo é excepcional, eu paguei pra ter a ROM e recomendo que comprem também, são 10 dólares bem gastos. A mecânica é muito simples, lembra um pouco a idéia do Celeste. É um jogo vertical onde a tela vai subindo lentamente e você precisa alcançar o fim da fase antes que a tela te alcance. E falando em fases, vale um parêntese pra explicar mais uma estrutura de dados que o nintendinho usava, os nametables. Em resumo hiper resumido, é um espaço na memória do PPU que organiza o equivalente a 4 telas, duas em cada linha.</p>
<p>Se você está num Mario que é plataforma horizontal, ele vai mantendo a próxima tela no espaço à direita. Olha como a memória vai atualizando conforme vamos avançando pelas telas.</p>
<p>Se for plataforma vertical como Kid Icarus ele mantém a próxima tela no espaço pra cima e você pode trabalhar os modos desse namespace se precisar de algo mais complexo como num Mario 3 que é horizontal mas quando você pega a folha pode voar vertical.</p>
<p>No caso do Micro Mages ele vai usar um modo semelhante ao do Kid Icarus. Jogando um pouco, veja lado a lado como o próximo nivel vai se montando nesse espaço de memória de nametables.</p>
<p>No video da Morphcat ele começa explicando o que eu já falei, que gráficos são divididos em duas tabelas CHR. Ele chama tiles de sprites mas é a mesma coisa, eu chamo sprites os tiles que estão na tela neste momento. Ele continua repetindo que cada tile é um quadrado de 8 por 8 pixels e que pode escolher até 3 cores da paleta. E que juntamos tiles pra formar o que ele chama de meta-sprites que é o objeto completo. Continuando, ele explica que só dá pra ter até 4 paletas de cores e que as cores são reusadas pra outros objetos como inimigos porque não dá pra ter cores diferentes pra cada coisa, é tudo as mesmas paletas.</p>
<p>Outra limitação do PPU que eu não mencionei ainda é que ele só consegue desenhar 8 sprites por scanline. Como cada personagem é formado por duas linhas de dois tiles cada, nesse exemplo vai ter 10 tiles por linha em vez do máximo de 8. Se tiver mais que 8 os sprites seguintes simplesmente não são desenhados. Por isso um truque muito usado é escolher 8 tiles dos 10 e desenhar num frame, daí no próximo frame você esconde 2 que foram desenhados no anterior e troca por 2 que ainda não tinham sido desenhados, e vai permutando de frame a frame. Por isso muitos jogos de nintendinho parece que os personagens ficam piscando na tela. Isso acontece quando eles se movimentam e na mesma linha acaba ficando mais de 8 sprites.</p>
<p>Por causa dessas limitações, a primeira decisão da Morphcat foi criar personagens que precisam só de um tile pra formar o sprite em vez de 4 ou mais. Além de economizar em espaço, isso também evita o flicker, aquelas piscadas, porque vai ser mais difícil ter mais de 8 sprites por scanline. Falando só em espaço, de volta à tabela de tiles CHR na ROM, esse é o espaço ocupado por todos os tiles que formam as animações do Mario, que nós já vimos antes. E agora o espaço ocupado por todas as animações dos magos nesse novo jogo. Veja como economiza espaço escolhendo fazer personagens menores que cabem num único tile. E não só isso, também conseguimos adicionar mais quadros na animação, tornando a movimentação mais fluida.</p>
<p>Outro desafio são os chefões, que costumam ser sprites grandões. Por exemplo, esses são todos os frames de animação de um dos chefões. O problema é que se você tentar encaixar todas essas imagens no que restou do espaço CHR, simplesmente não vai caber. E isso é só um chefão. Agora vem a parte onde a programação e o design precisam andar juntos, porque o designer tem que fazer um chefão cujos quadros podem ser divididos em partes, no caso três, que podem ser animados independentemente.</p>
<p>Olhando só os quadros que fazem a animação da cabeça, dividimos em tiles, e vemos se tem repetições. E de cara você pode ver que a primeira metade em todos os três quadros é igual, então só precisa armazenar uma versão, que pode ser reusada em todos.</p>
<p>Não só isso, se um tile é o espelho de outro tile, você guarda só uma versão e pede pro nintendinho inverter horizontalmente, e assim pode economizar mais um pouco. E fazendo isso, só na cabeça otimizamos de 16 tiles pra 4 que realmente precisam existir na ROM.</p>
<p>Pra parte do meio, fazemos a mesma coisa: procuramos todos os tiles repetidos, todos que podem ser invertidos e diminuímos mais ainda.</p>
<p>E a última parte tem 5 animações mas de cara as duas últimas são inversões das duas primeiras. E fazendo todas as mesmas reduções, removendo tudo que é repetido, compare os tiles que sobraram com os que originalmente eram necessários sem otimizar.</p>
<p>O video deles continua mostrando como aplicaram outras técnicas pra reduzir ainda mais a quantidade de memória necessária pra montar as fases. Mas eu vou pular pra não ficar extenso demais, por isso recomendo que assistam e também comprem o jogo.</p>
<p>Falando em programar seus próprios jogos, como você faz isso? Simples, se pesquisar no Wiki da Nesdev vai encontrar sobre ferramentas, tem vários fóruns ainda ativos onde o povo troca dicas e informações sobre as melhores técnicas e ferramentas, mas o mais básico é o cc65 que vem com o montador ca65 e o disassembler da65. E se procurar num Github vai encontrar vários exemplos, de hello world a joguinhos completos feitos do zero como o Micro Mages. Se você já pensou em programar games e não quer ser só mais um mero clonador de Flappy Bird, programar em hardware restrito como um nintendinho é um excelente exercício pra aprender todos os fundamentos de um bom design de games.</p>
<p>Por exemplo, baixei este projetinho que faz todo o setup do ambiente, carrega o mínimo de tiles e tudo mais pra ter fontes e com isso consigo fazer um hello world da vida rapidamente em C. E sim, é possível programar em C e compilar com o cc65 pra binário de 6502 específico de nintendo. A desvantagem de programar em C é que ele vai gerar um binário menos otimizado do que um bom programador faria na unha direto em assembly. Por outro lado, como estamos em ambiente emulado você sempre pode mexer no emulador pra ter uma CPU mais rápido do que o nintendinho original e quantos banks de ROM quiser.</p>
<p>Aliás, sobre o hello world, considere o seguinte: o nintendinho não tem um sistema operacional, sequer vem com fontes numa ROM, o jogo tem que fazer tudo, então pra fazer um hello world, você precisa primeiro armazenar suas próprias fontes no espaço CHR da ROM. Só depois pode escrever alguma coisa.</p>
<p>Falando nisso vale a pena mostrar como subir um pouquinho o nível da linguagem pra não ficar tão tedioso fazer só assembly puro. Não é um compilador ainda, tá longe disso, mas muitos assemblers tem capacidade pra macros. Pra quem não sabe, macro é como um template. Um procesador de Markdown é tipo um macro de HTML. Quando eu digito asterisco o processador vai pegar o texto seguinte e colocar entre as tags de bold por exemplo. Macro é uma forma de reduzir copy e paste de trechos de código.</p>
<p>O ca65 que é o assembler mais recomendado pra programar pro nintendinho já vem com vários macros que adicionam algumas construções mais modernas como ifs, whiles e outras coisas, assim você consegue ter mais dicas visuais do que cada trecho faz em vez de ver só um linguição de instruções. Some isso a subrotinas com JSR que mostrei no video anterior e é possível programar sem ficar completamente doido no processo. Mas pense assim: é assim que se programava games de verdade. O grande lance de programar em consoles é tirar o máximo que o hardware consegue oferecer.</p>
<p>Outra coisa interessante. Hoje em dia não existe mais o código fonte da maioria esmagadora dos games. Muitas empresas da época até faliram e muito material se perdeu. Mas isso não tem problema. Você sempre consegue reabrir o código a partir do binário. Pra isso serve a ferramenta da65 que vem no mesmo pacote. Você pode fazer o desassembly e voltar aos mnemônicos. Obviamente não vai ter o nome correto das subrotinas, labels, constantes e variáveis. Mas se você tiver experiência com o hardware vai saber por exemplo que se tiver alguma coisa mexendo com o endereço a partir de 0x8000 está acessando a ROM, se mexer com o endereço 0x4016 ou 0x4017 está falando com os controles.</p>
<p>Daí você pode fazer a engenharia reversa que é adicionando as etiquetas e nomes das coisas mais óbvias primeiro e fazer o caminho inverso. Ah, se esse trecho mexe com o endereço 0x4016 deve ser o trecho que decide o que fazer quando aperta um botão. Além disso você pode fazer tracing, visualizar o que acontece em cada registrador e na memória a cada instrução pra determinar do que se trata cada subrotina. É super trabalhoso mas fazendo isso você consegue encontrar praticamente tudo. Diversos jogos já foram mapeados assim.</p>
<p>E de fato, se procurar no Github você vai achar um disassembly do Super Mario praticamente completo com todos os nomes de subrotinas, etiquetas e constantes. É o mais próximo que se chegou do código fonte original. E em cima disso você pode modificar o jogo como quiser no nível do código em vez de se limitar a só modificar os bytes no nível da ROM como fizemos com textos e tiles. Podemos adicionar tiles novos ou fazer textos mais longos e reprogramar a lógica porque o assembler vai conseguir recalcular todos os endereços corretamente e gerar um novo binário que funciona.</p>
<p>Finalmente, vou completar a maior tangente que fiz até hoje. Vocês vão se lembrar que o episódio anterior começou só porque eu vi um video falando sobre o Game Genie. Como expliquei antes, Game Genie é um hardware que fica entre o cartucho e o console. E agora sabemos que o cartucho responde a uma faixa de endereços bem específico entre $8000 e $FFFF. Também sabemos que endereços que a CPU pede não correspondem à localização exata nos cartuchos por causa do sistema de mappers e bank switching.</p>
<p>Existem duas formas de adicionar cheats, ou trapaças nos jogos. Uma delas é alterando o valor carregado na memória RAM e a outra é alterando direto o binário na ROM. Com bastante paciência você consegue visualizar o conteúdo da RAM usando emuladores como o FCEUX e o Mesen, gravar dumps da memória entre uma parte do jogo e outro e comparar os bits pra ver o que mudou. Por exemplo, gravar a RAM antes de morrer e depois de morrer pra ver qual byte diminuiu e ele é um candidato pra ser o local na memória que representa quantas vidas você tem, daí você pode testar esse valor.</p>
<p>Com tantas décadas de gente escovando bits, existem bancos de dados inteiros com diversos cheats pra cada jogo. Você facilmente consegue encontrar código pra tudo. Num emulador como o RetroArch tem até funcionalidades pra sincronizar com esses bancos de dados daí você nem precisa digitar os códigos manualmente. Só escolher o jogo, selecionar em cheats, carregar e já era.</p>
<p>Resumindo o video do canal Retro Game Mechanics Explained o que o hardware do Game Genie faz é receber um endereço de 16-bits e um ou dois valores de 8 bits cada. Isso forma códigos de 6 ou de 8 letras. Quando o código tem 6 letras é fácil porque os primeiros 4 dígitos representam o endereço na RAM e os dois últimos digitos representam o valor que o Game Genie vai devolver e pronto. Quando estamos falando de jogos usando o Mapper mais simples, como num Super Mario original que só suporta ROMs com 40 kilobytes, isso é tudo que precisamos.</p>
<p>Agora que você entende bank switching, sabe que no mesmo endereço da RAM pode estar apontando dados em banks diferentes da ROM. Depende de qual bank tá apontando no momento. Então o Game Genie não pode responder com um valor fixo  toda hora, só quando um determinado bank tá selecionado. Pra isso serve o código de 8 digitos. De novo, os primeiros 4 formam o endereço na RAM. Agora os dois dígitos seguintes representam qual é o valor que esperamos encontrar na RAM, ou seja, o valor que ele carregou do bank. Se for diferente do que passamos é porque o console tá olhando um bank diferente do que queremos. Mas quando o valor voltar igual, é porque ele mudou pro bank que queremos, e aí devolvemos o valor fixo que tá no ultimos dois dígitos do código.</p>
<p>A forma como o Game Genie monta os códigos é só um embaralhamento arbitrário que ele faz sei lá porque, talvez só pra deixar o código um pouco mais legível. É só uma obfuscação simples. Pra isso primeiro você pega os bits do endereço e dos dois valores, daí embaralha os bits pra outras posições, e no fim substitui cada bloco de 4 bits por uma letra de acordo com uma tabela arbitrária. Pra cada console tem uma regra de embaralhamento e tabela de mapeamento de letras diferentes.</p>
<p>Eu fiz um programinha bem besta na linguagem Crystal que pega o código do Game Genie, traduz de volta em bits, desembaralha os bits e devolve o endereço e os valores. Eu fiz em Crystal só porque eu quis, nenhuma razão especial, podia ser em qualquer linguagem. Vou deixar o link pra esse código nas descrições abaixo. Talvez eu termine de fazer o desembaralhamento das versões de game genie pros outros videogames mas eu queria um executável simples pro meu teste.</p>
<p>Eu fiz algumas coisas do jeito menos otimizado, estilo &ldquo;o que funciona primeiro&rdquo;, então não xinguem. Pelo menos tem testes unitários direitinho. Veja esse por exemplo, eu garanto que eu passo um código de Game Genie e ele vai gerar o binário que eu quero. Daí no outro spec eu garanto que dado esse linguição de bits vai gerar a representação em hexadecimal direitinho também.</p>
<p>O código em si é muito simples. Ele começa pegando o código de 6 ou 8 letras do game genie, processa letra a letra e troca pela representação binária. Eu não estou lidando com o número binário e sim com a representação em texto mesmo pra ficar mais fácil. Depois de montar esse binário, o próximo passo é desembaralhar, e isso é arbitrário do game genie, só trocar bits de posição. Finalmente, com os bits rearranjados, faço um outro loop besta pegando de 4 em 4 bits e transformando em hexadecimal.</p>
<p>Vocês vão notar que eu fiz de um jeito meio tosquinho aqui criando um array pra mapear cada conjunto de bits no hexadecimal em vez de converter a string num número e depois usar um formatador pra hexa, mas foi mais porque eu não achei fácil o jeito de fazer isso em Crystal ainda. Quando descobrir eu mudo. Mas pros meus propósitos esse código tá suficiente. Com isso eu posso compilar um binário e &hellip; pronto, posso chamar o binário, passar o código de game genie e ele devolve o hexadecimal certo.</p>
<p>O próximo passo foi mexer no emulador feito em Go. A grande maioria dos emuladores mais maduros e populares tem suporte a códigos de game genie. Mas esse emulador mais simples não tinha, por isso achei que seria um exercício interessante. Pra começar eu resolvi modificar o arquivo do console adicionando uma estrutura chamada Cheat que vai ter só dois elementos, o valor de condição pra comparar com o que tá no bank da ROM selecionado nesse instante, e o valor trapaceado que eu quero devolver. Daí eu adiciono na estrutura do console uma nova estrutura, um Map de Cheats. Map é o que algumas linguagens chamam de dicionário ou de hash. É uma lista que vai mapear um número inteiro, que no caso, é o endereço com uma instância da estrutura de Cheat.</p>
<p>Agora precisamos ler os cheats de algum lugar. No caso escolhi ler de um arquivo. Eu não estou mostrando, mas estou seguindo o padrão que esse emulador já fazia pra fazer saves dos jogos, criando um hash md5 do binário. O nome do arquivo que eu vou buscar é o hash md5 do Super Mario numa pasta .nes/cheats. Essa função readCheats recebe o caminho pra esse arquivo e só vai lendo linha a linha e gravando numa lista. Assim podemos ter múltiplos arquivos pra com códigos específicos de cada jogo que queremos.</p>
<p>A função seguinte vai interpretar essa lista. A função LoadCheats vai usar a readCheats acima passando o caminho do arquivo e recebendo a lista que ele ler. Daí eu passo um caminho fixo mesmo por enquanto, pro executável daquele programinha que eu fiz em Crystal. Ele vai passar os códigos pra esse programinha pra decodificar o endereço e valores.</p>
<p>Com o que ele devolver, checo se é um código de 6 ou 8 digitos, e isso serve pra preencher ou não aquele campo de condição na estrutura de Cheat. Feito isso associamos o endereço devolvido com a estrutura de Cheat e jogamos no dicionário na estrutura do Console. Com isso o console tá ciente dos códigos.</p>
<p>Pra de fato aplicar o cheat o lugar mais óbvio pra procurar é a estrutura de Memory, lembram dele? É nesse arquivo que tem a lógica pra escolher qual mapper o cartucho carregado precisa. Mas ele abstrai os mappers e a gente não precisa se preocupar. Os Mappers vão se encarregar de ler da ROM nos banks corretos. Então o que vamos fazer é, em vez de devolver o valor lido, vamos gravar temporariamente numa variável e passar pra uma nova função chamada replaceWithCheat.</p>
<p>Essa função recebe o endereço consultado e o valor devolvido. Agora acessamos o dicionário de Cheats que tá na instância do Console e procuramos por esse endereço. Se não achar nada, devolve o valor real original. Caso encontre ele checa se precisa comparar com a condição do Cheat.</p>
<p>Se não tiver condição ou se a condição bate com o valor real, então ele devolve o valor falsificado. E pronto, é só isso que precisa pra implementar um game genie num emulador. Com isso o console vai receber o valor falsificado em vez do valor real e nosso Super Mario vai começar com mais vida. Podemos testar isso.</p>
<p>Veja o arquivo de cheats com o código. Agora executamos o emulador passando a ROM do jogo, esperamos carregar e olha só, 9 vidas!!</p>
<p>Mas digamos que a gente é ruim em Super Mario e o tempo sempre acaba, quero que comece com 900 segundos em vez de só 400 e se procurar no Google descubro que o código pra isso é VGYOKK, então vamos editar o arquivo de trapaças e adicionar o código. Reiniciamos o emulador e &hellip; veja só que bacana, 9 vidas e 900 segundos pra terminar a fase.</p>
<p>Mas digamos que a gente é tão ruim, mas tão ruim que morre toda hora. Malditos Goombas! Mas não se preocupem, existe um código pra isso. Vamos editar de novo o arquivo e adicionar SSASSA. Agora vamos reiniciar o emulador e corremos de cara pra um Goomba. E olha só, invencibilidade!!</p>
<p>Vocês vão notar no terminal que toda vez que eu encosto num inimigo o programa busca o endereço 0xD88D pra checar se é pra perder vida ou não, daí se devolver 0xD5 ele sabe que é invencível. E é assim que trapaceamos pra chegar até o final fácil! E com isso finalmente consegui fechar o assunto que comecei no video anterior, fazer meu próprio Game Genie de Nintendinho. Com tudo que expliquei desde o vídeo anterior agora vocês entendem exatamente como tudo funciona.</p>
<p>E pra finalizar o episódio de hoje quero mostrar como vocês vão ter uma noção melhor pra entender videos de outros canais também. No próprio canal do Retro Game Mechanics Explained, alguns dos videos mais divertidos é a explicação de diversos bugs que esses jogos tem, e como podemos tirar vantagem disso. Uma das categorias de gamers mais escovadores de bits são os speedrunners. São jogadores que competem pra bater o recorde de quem acaba o jogo no menor  tempo. Tem várias sub-categorias. Uma das mais divertidas é quando eles encontram bugs que permitem, por exemplo, saltar todas as fases e ir direto pro final.</p>
<p>Antes de falar desse bug preciso falar de uma última ferramenta que emuladores mais avançados como o FCEUX tem, se chama TAS ou Tool Assisted Speedrun. Lembram no nosso código em Go que eu associo controles na estrutura de console? Obviamente nós conseguimos ler o que vem do controle pra poder codificar o que cada botão apertado vai fazer no jogo. E naturalmente eu posso fazer o que quiser com esses dados, inclusive salvar num arquivo. Mais do que isso, como eu controlo a PPU também consigo saber exatamente em que frame cada botão foi apertado.</p>
<p>Então eu também consigo ler esse tal arquivo que diz em que frame foi apertado qual botão e com isso podemos dar replay no jogo inteiro repetindo exatamente tudo que que foi apertado com precisão de 1 frame. E é exatamente assim que esses jogos são arquivados em sites como o tasvideos.org, que mantém registros de todos os recordes. E você pode baixar o arquivo formato .fm2 ou .fm3 que contém exatamente essa sequência, rodar no seu emulador e assistir o speedrun exatamente como a outra pessoa jogou.</p>
<p>Então eu vou abrir o FCEUX, carregar a ROM do Super Mario 3, abrir o TAS Editor e carregar o arquivo .fm2 que baixei do site tasvideos.</p>
<p>Pronto, agora é só despausar e assistir. Vou pular as primeiras fases porque ele usa outros truques conhecidos pra ir pulando de warp zone em warp zone até chegar no mundo 7. Nesse ponto a maioria dos speedrunners ia pro Dark World normalmente, mas nessa corrida eles vão pelo Pipe World porque é de lá que dá pra acionar o bug. Assistam primeiro.</p>
<p>(glitch run)</p>
<p>Foda né, vocês não entenderam nada eu imagino, mas deu pra ver que eles fazem uma sequência bem absurda de coisas no Pipe World, daí começa tudo a descer pra um monte de sujeira de tiles e de repente ele chega na princesa direto. Agora que vocês tem uma idéia de como as coisas funcionam, dá pra entender que o bug aciona alguma coisa que faz a tela descer por um pedaço de RAM com bytes aleatórios que ele manda pro PPU que mapeia os tiles correspondentes, montando uma fase toda bagunçada e com comportamento incerto. E em algum momento dá um JUMP. O truque é simples, vamos usar a posição dos sprites na RAM pra montar um assembly em tempo real e dar um jeito de executar.</p>
<p>O código em si que precisa ser escrito é JSR 0x8FE3. Se conseguir fazer o jump esse é o endereço pra subrotina que inicia a sequência final da princesa. Então precisamos de 3 bytes consecutivos num lugar especial na RAM, os bytes sao 0x20 que é o JSR, e depois 0xE3 e 0x8F que é o endereço com os bytes invertidos por causa de little endian, que vocês já sabem como funciona.</p>
<p>A posição X dos inimigos, especialmente dos koopa troopers ficam sempre no mesmo lugar e não apagam mesmo quando o sprite some da tela. Por isso esses bytes são bons candidatos pra usar. Mas não adianta sair matando qualquer koopa. Precisamos que eles estejam na posição correta nessa lista e também que estejam numa posição X específica. Pra isso precisamos tentar fazer com que eles apareçam numa determinada ordem primeiro. A lógica é que novos sprites sempre vão aparecer primeiro na posição mais alta livre da lista primeiro. Então usamos essa informação pra fazer eles aparecerem numa ordem em particular.</p>
<p>Ao matar essa tartaruga e ir pro cano enquanto ela ainda está na tela, podemos forçar as plantas piranha pra aparecer nos slots 2 até 4 e o próximo koopa no slot 5.</p>
<p>Matamos as plantas pra elas não reaparecerem mais tarde quando voltarmos pra essa parte.</p>
<p>Agora o koopa entre os blocos de interrogação vai estar no slot 4 e o parakoopa no slot 3. Pegamos a casca dessa tartaruga e matamos jogando ele no bloco. Isso fixa o byte na posição fixa 0xE3 que precisamos.</p>
<p>Daí ficamos exatamente nessa posição em cima do cano e damos uma rabada no parakoopa quando ele estiver exatamente alinhado com o topo do outro cano pra garantir que a casca aterrisse na posição X hexadecimal 0x20, e com isso temos o byte que representa o jump. Agora vamos pra baixo, agarramos a casca desse koopa e voltamos ao comeco do nível.</p>
<p>Nesse ponto precisamos realizar o bug do cano apertando pra baixo no controle ao mesmo tempo que faz um clip na parede no canto desse cano. Às vezes o Mario consegue fazer um clip numa parede, tipo passar por ela, se estiver rápido o suficiente e bater bem na beira do grid de 16 pixels, é um movimento bem preciso e às vezes precisa fazer várias vezes pra acertar. Nessa sequência não tem tanto problema se de vez em quando pisar na casca pra tartaruga não acordar.</p>
<p>Uma vez entrando no cano inicia uma sequência de bugs porque não tava programado pra ter como ele entrar no cano nesse ponto, dai vai descendo por todo esse lixo aleatório que tá na memória. O PPU vai simplesmente mapeando o lixo que vai recebendo com os tiles na tabela CHR e mostrando na tela. Por isso fica essa bagunça visual.</p>
<p>No final tem que pular com muito cuidado com a casca e alinhar com o fundo bem nessa posição. Tem um detalhezinho que se notar que esse bloco de música estiver parcialmente cortado, talvez precise mover o Mario um pixel pra direita pra compensar a posição da camera. Deixamos o koopa reaparecer nas nossas mãos e desaparecer no fundo da tela, e essa posição onde ele desaparece nos dá o último byte que precisávamos, valor 0x8F. Finalmente caímos aqui e pulamos pra ativar a instrução. E se tudo foi configurado exatamente como mostrado aqui, vamos pular direto pra princesa e terminar o jogo.</p>
<p>Pra entender o que aconteceu vamos usar tudo que aprendemos até agora. Essa fase vertical é mapeada entre os endereços 0x6000 e 0x6EFF, que é suficiente pra 16 telas. Mas aquele cano que entramos depois de clipar pela parede manda o Mario pra tela 19 que obviamente não existe. Então acontece um transbordamento, um overflow da memória e começamos a acessar áreas da RAM que não era pra acessar.</p>
<p>E pra piorar, além de visualmente aparecer essa zona, a rotina de desenho falha e o que estamos vendo pode não estar de fato lá, por isso o Mario consegue subir numa plataforma invisível. A coincidência é que o final desse cano deixa o Mario do lado de um bloco de nota invisível e é batendo nesse bloco que ativa os bytes de Jump que configuramos.</p>
<p>Quando batemos num bloco de musica o tile é temporariamente removido e outra versão do sprite aparece pra fazer a animação. E claro, o índice nos dados da tabela de fase tá todo zoado quando procura por esse tile e ele pega o endereço 0x9C70 pra atualizar, que não é nem de longe perto da tabela de dados. Pior esse endereço simplesmente não existe na RAM.</p>
<p>Recapitulando o que já vimos sobre os endereços que nintendinho entende, temos a RAM entre 0x0000 e 0x1FFF e temos Work RAM entre os endereços 0x6000 e 0x7FFF e já sabemos que de 0x8000 até 0xFFFF é a região reservada pra ROM, ou seja, pro cartucho. Então aquele índice errado do bloco de musica tenta escrever na ROM. Mais do que isso, esse endereço na verdade fala com o Mapper do cartucho. E você sabe o que é um Mapper.</p>
<p>Por acaso quando tentamos escrever nesse endereço 0x9C70, é o mesmo que dizer pro Mapper fazer uma troca de banco, pra apontar pra outros bancos da ROM. Recapitulando, já sabemos que entre os endereços 0x8000 e 0xFFFF só cabe 32 kilobytes de dados, mas a ROM de programa do Super Mario 3 tem 256 kilobytes. Obviamente não cabe e por isso durante o jogo ele vai pedindo pro Mapper ir trocando os bancos pra apontar pra outras regiões da ROM.</p>
<p>Então esse trecho tá fazendo seu trabalho feliz e contente, achando que tá atualizando um tile na tela pro bloco de musica, mas em vez disso quando executa a instrução no endereço 0xDD1A, a ROM de 0xA000 a 0xDFFF é trocado pelo mapper do nada. Ele literalmente atira no próprio pé e as próximas instruções foram trocadas pelo que tá no novo banco que o Mapper trocou.</p>
<p>O apontador de pilha nesse momento da execução é 0xFD, que sabemos que quer dizer que a pilha tá quase vazia, lembra do video passado e do código de Reset da CPU que fizemos antes? Lembra que a instrução RTS vai retornar pro último endereço que estiver na pilha? E por acaso na pilha tem só um endereço nesse momento. E de fato essas instruções novas que vieram na troca do bank pelo Mapper, ele continua executando e uma hora bate num RTS fazendo ele pular pro endereço 0x8F4D.</p>
<p>Agora caímos no meio de uma nova rotina com uma pilha vazia, coisa que ele não esperava. Daí ele continua executando e uma hora vai bater num RTS, vai olhar pra pilha pra saber pra onde retornar. Mas a pilha tá vazia então quando isso acontece o ponteiro faz um wrap, ele circula como se a pilha estivesse totalmente cheia, lembra de quando falei de stack overflow no video anterior?</p>
<p>Lembrando que a pilha fica entre os endereços 0x0100 e 0x01FF, mas praticamente nunca a pilha enche totalmente então alguns programas acabam usando o topo da pilha pra outra coisa e no caso o jogo mantém informação da fase em 0x0100. Lá vai ter o valor 0xC0 se forem fases horizontais e 0x80 em fases verticais. E como o ponteiro circulou pro topo da pilha ele pega o valor que tá lá, subtrai 1 e retorna o endereço 0x0081.</p>
<p>Beleza, então o RTS vai pular pra 0x0081 e isso é endereço da RAM que tem um monte de dados voláteis sobre as propriedades da fase. Por exemplo em 0x007E a 0x0086 tem propriedades sobre os sprites carregados nesse momento, tipo o timer de quando as plantas piranha tem que aparecer dos canos, ou como os parakoopas voam. Dos endereços 0x0087 a 0x008F tem o high byte da posição Y de cada sprite, que é o número da tela onde eles estão.</p>
<p>Agora chegamos onde queríamos porque dos endereços 0x0090 a 0x0098 estão os low bytes da posição X de cada sprite na tela, que são as posições que viemos manipulando no começo e configuramos o JUMP. Os bytes antes disse são dados, mas o processador não sabe disso e tenta executar como se fossem instruções. Por coincidência nenhuma das tentativas de executar esses dados termina num crash e ele consegue chegar até nosso jump. Como esses dados anteriores podem ser qualquer coisa que representa os tais elementos na tela que falei, poderiam ser bytes que representam instruções que crasheiam, então essa sequência toda que fizemos não é garantido que funciona sempre, mas funciona vezes o suficiente.</p>
<p>Chegando no nosso JSR 0x8FE3 ele pula pra um programa que fica num bank que nunca é trocado pelo mapper então garantidamente sempre vai estar lá e é a rotina pra carregar o quarto da princesa.</p>
<p>Pra fechar, a sequência pra montar a instrução de jump pode ser feita de várias formas contanto que a posição X dos inimigos certos entre na sequência correta nos slots da memória. Esse é o recorde mundial usando esse bug do MitchFlowerPower onde ele termina o jogo em 3 minutos e 9 segundos. Ele mesmo jogou manualmente e gravou seus comandos.</p>
<p>E com tudo isso dito, finalmente chegamos ao final do episódio! Tudo que eu queria era explicar como o Game Genie funciona, mas pra realmente entender era necessário entender cada componente de como um computador funciona. Com isso eu espero que se você é iniciante tenha conseguido ter uma visão um pouco mais abrangente do que significa fazer um hardware funcionar.</p>
<p>Pra mim isso é programação. Programação nunca foi sobre seguir receitas e procedimentos prontos e sim encontrar um cenário de restrição e com conhecimento de verdade usar as ferramentas disponíveis pra conseguir soluções criativas. Nenhum livro, nenhum curso, nenhum tutorial jamais vai ensinar essas coisas. Só quando você encara problemas difíceis é que conhecimento de verdade começa a aparecer. Eu tenho certeza que vocês nunca imaginaram que tinha tanta coisa que podia ser dito sobre um videogame obsoleto dos anos 80.</p>
<p>Se você ficou empolgado pra escrever seu próprio emulador recomendo que acompanhem outro canal, o do One Lone Coder que está desenvolvendo um emulador de NES em C++ e explicando passo a passo no seu canal. Vou deixar o link nas descrições abaixo. O próprio canal do Retro Game Mechanics Explained na realidade tem videos detalhados explicando o funcionamento do Super Nintendo. Como funcionam os gráficos e cores, como funciona a memória, como funciona o lendário Mode 7. Tem bastante coisa pra aprender.</p>
<p>Se vocês pensam que eu acabei todos os assuntos, tão enganados. Descer nesse buraco de coelho me levou a rever um monte de coisas do passado em relação a emuladores e estou pensando em fazer um episódio mais leve do que esses pra explicar o ecossistema atual de emuladores. Pra variar eu vou descer mais no detalhe em alguns deles então aguardem pelo próximo. Como vários assuntos eu tive que resumir ou mesmo pular pra não ficar confuso demais, se você também é entusiata desses assuntos, não deixem de complementar nos comentários abaixo. Se curtiram o video mandem um joinha, assinem o canal e cliquem no sininho. E principalmente ajudem o canal compartilhando os videos com seus amigos. A gente se vê na próxima, até mais!</p>
<p>Links:</p>
<ul>
<li>
<p>Super Mario Bros. 3 - Wrong Warp (<a href="https://www.youtube.com/watch?v=fxZuzos7Auk"target="_blank" rel="noopener">https://www.youtube.com/watch?v=fxZuzos7Auk</a>)</p>
</li>
<li>
<p>A Comprehensive Super Mario Bros. Disassembly (<a href="https://gist.github.com/1wErt3r/4048722"target="_blank" rel="noopener">https://gist.github.com/1wErt3r/4048722</a>)</p>
</li>
<li>
<p>Lembra deles? Confira jogos brasileiros do Master System lançados pela Tectoy! (<a href="https://blogtectoy.com.br/lembra-deles-todos-jogos-brasileiros-do-master-system-lancados-pela-tectoy/"target="_blank" rel="noopener">https://blogtectoy.com.br/lembra-deles-todos-jogos-brasileiros-do-master-system-lancados-pela-tectoy/</a>)</p>
</li>
<li>
<p>Free NES assembler (<a href="https://bisqwit.iki.fi/source/nescom.html"target="_blank" rel="noopener">https://bisqwit.iki.fi/source/nescom.html</a>)</p>
</li>
<li>
<p>Micro Mages (<a href="https://morphcatgames.itch.io/micromages"target="_blank" rel="noopener">https://morphcatgames.itch.io/micromages</a>)</p>
</li>
<li>
<p>Nes Dev Wiki (<a href="https://wiki.nesdev.com/w/index.php/Nesdev_Wiki"target="_blank" rel="noopener">https://wiki.nesdev.com/w/index.php/Nesdev_Wiki</a>)</p>
</li>
<li>
<p>Computer Archeology - The Legend of Zelda (<a href="https://www.computerarcheology.com/NES/Zelda/"target="_blank" rel="noopener">https://www.computerarcheology.com/NES/Zelda/</a>)</p>
</li>
<li>
<p>6502 Instruction Set (<a href="https://www.masswerk.at/6502/6502_instruction_set.html"target="_blank" rel="noopener">https://www.masswerk.at/6502/6502_instruction_set.html</a>)</p>
</li>
<li>
<p>An introduction to 6502 math: addiction, subtraction and more (<a href="http://retro64.altervista.org/blog/an-introduction-to-6502-math-addiction-subtraction-and-more/"target="_blank" rel="noopener">http://retro64.altervista.org/blog/an-introduction-to-6502-math-addiction-subtraction-and-more/</a>)</p>
</li>
<li>
<p>Explain Half Adder and Full Adder with Truth Table (<a href="https://www.elprocus.com/half-adder-and-full-adder/"target="_blank" rel="noopener">https://www.elprocus.com/half-adder-and-full-adder/</a>)</p>
</li>
<li>
<p>Build a multiplying machine using NAND logic gates (<a href="https://codegolf.stackexchange.com/questions/12261/build-a-multiplying-machine-using-nand-logic-gates"target="_blank" rel="noopener">https://codegolf.stackexchange.com/questions/12261/build-a-multiplying-machine-using-nand-logic-gates</a>)</p>
</li>
<li>
<p>Tool Assisted Game Movies (<a href="http://tasvideos.org/"target="_blank" rel="noopener">http://tasvideos.org/</a>)</p>
</li>
<li>
<p>RETRO INSECTIVORES: FINDING AND ELIMINATING BUGS IN NES DEVELOPMENT (<a href="https://megacatstudios.com/blogs/press/retro-insectivores-finding-and-eliminating-bugs-in-nes-development"target="_blank" rel="noopener">https://megacatstudios.com/blogs/press/retro-insectivores-finding-and-eliminating-bugs-in-nes-development</a>)</p>
</li>
<li>
<p>FCEUX (<a href="https://sourceforge.net/projects/fceultra/"target="_blank" rel="noopener">https://sourceforge.net/projects/fceultra/</a>)</p>
</li>
<li>
<p>Zelda Screen Transitions are Undefined Behaviour (<a href="https://gridbugs.org/zelda-screen-transitions-are-undefined-behaviour/"target="_blank" rel="noopener">https://gridbugs.org/zelda-screen-transitions-are-undefined-behaviour/</a>)</p>
</li>
<li>
<p>NES Emulator Debugging (<a href="https://gridbugs.org/nes-emulator-debugging/"target="_blank" rel="noopener">https://gridbugs.org/nes-emulator-debugging/</a>)</p>
</li>
<li>
<p>Two&rsquo;s Complement Multiplication (<a href="http://pages.cs.wisc.edu/~david/courses/cs354/beyond354/int.mult.html"target="_blank" rel="noopener">http://pages.cs.wisc.edu/~david/courses/cs354/beyond354/int.mult.html</a>)</p>
</li>
<li>
<p>NES Hello World (<a href="https://www.embed.com/nes/hello-world.html"target="_blank" rel="noopener">https://www.embed.com/nes/hello-world.html</a>)</p>
</li>
<li>
<p>DF Direct: CRT Displays - Was LCD A Big Mistake For Gaming? (<a href="https://www.youtube.com/watch?v=tvRyVZWuvQ4"target="_blank" rel="noopener">https://www.youtube.com/watch?v=tvRyVZWuvQ4</a>)</p>
</li>
<li>
<p>DF Direct! Modern Games Look Amazing On CRT Monitors&hellip; Yes, Better than LCD! (<a href="https://www.youtube.com/watch?v=V8BVTHxc4LM"target="_blank" rel="noopener">https://www.youtube.com/watch?v=V8BVTHxc4LM</a>)</p>
</li>
<li>
<p>Meu fork do emulador de NES em Go (<a href="https://github.com/akitaonrails/nes"target="_blank" rel="noopener">https://github.com/akitaonrails/nes</a>)</p>
</li>
<li>
<p>Meu código do decodificador de código de Game Genie (<a href="https://github.com/akitaonrails/gamegenie"target="_blank" rel="noopener">https://github.com/akitaonrails/gamegenie</a>)</p>
</li>
</ul>
<p>Assinem estes canais:</p>
<ul>
<li>Retro Game Mechanics Explained (<a href="https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g"target="_blank" rel="noopener">https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g</a>)</li>
<li>One Lone Coder (<a href="https://www.youtube.com/channel/UC-yuWVUplUJZvieEligKBkA"target="_blank" rel="noopener">https://www.youtube.com/channel/UC-yuWVUplUJZvieEligKBkA</a>)</li>
</ul>
]]></content:encoded><category>retrocomputacao</category><category>games</category><category>emulacao</category><category>akitando</category></item><item><title>[Akitando] #3 - Por que a Coréia do Sul é tão grande em Criptomoedas?</title><link>https://akitaonrails.github.io/2018/08/21/akitando-3-por-que-a-coreia-do-sul-e-tao-grande-em-criptomoedas/</link><guid isPermaLink="true">https://akitaonrails.github.io/2018/08/21/akitando-3-por-que-a-coreia-do-sul-e-tao-grande-em-criptomoedas/</guid><pubDate>Tue, 21 Aug 2018 17:00:00 -0300</pubDate><description>&lt;p&gt;Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal &lt;a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener"&gt;Akitando&lt;/a&gt;. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/BEaVdiTiiH4"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;Descrição no YouTube&lt;span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Neste episódio finalmente vamos ver alguns dos assuntos que assisti na conferência Beyond Blocks Summit em Seoul. E no meio da pesquisa esbarrei com uma história muito curiosa que quero contar em mais detalhes aqui:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal <a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener">Akitando</a>. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/BEaVdiTiiH4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Descrição no YouTube<span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"></span>
    <a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Neste episódio finalmente vamos ver alguns dos assuntos que assisti na conferência Beyond Blocks Summit em Seoul. E no meio da pesquisa esbarrei com uma história muito curiosa que quero contar em mais detalhes aqui:</p>
<p>O que um culto xamanista e um cachorro de estimação podem ter a ver com o impeachment da presidente da Coréia do Sul e como isso pode estar relacionado com o boom das criptomoedas lá?</p>
<p>Este episódio ficou com a narração um pouco mais devagar do que eu gosto, mas nos próximos eu acelero um pouco mais, aguardem ;-)</p>
<h2>Script<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A gente acha que o Brasil não é para novatos.
É verdade. Mas não subestimem outros países. Querem ver?
Como um CULTO XAMANISTA e um cachorro de estimação levam ao impeachment da presidenta da Coréia do Sul e o que isso pode ter a ver com o boom de criptomoedas lá?</p>
<p>Rola a intro!</p>
<p>Olá Pessoal, Fabio Akita!</p>
<p>Mano … esse episódio vai dar trabalho. Apertem os cintos e vamos lá!
Com o turismo pra trás, HOJE vamos falar sobre o que vocês estavam esperando. Por que a Coréia é o que é no mundo de criptomoedas HOJE?</p>
<p>Claro, podemos criar muitas teorias e a maioria delas provavelmente vai estar errada, MAS uma delas veio logo no primeiro dia do evento Beyond Blocks. A primeira palestra foi do CEO e co-fundador da Hashed, Simon Kim.</p>
<p>A Hashed é um dos grupos mais influentes no mundo de criptomoedas na Coréia. Basicamente é uma aceleradora fundada no meio de 2017. Eles tem dezenas de startups no portfólio e estão envolvidos em projetos que vocês já devem ter ouvido falar como Kyber Network, OmniseGo, EOS, WAS, Storm. No portfolio deles, segundo a Crunchbase, você vê empreendimentos como Origin Protocol que já levantou mais de USD 28 milhões em investimento, Watcha que levantou 12 milhões, Bluzelle que levantou quase 20 milhões e assim por diante.</p>
<p>O próprio Simon foi um investidor no começo do Ethereum e, claro, se deu muito bem quando o Ether começou a crescer exponencialmente. Muitos fundadores de crypto funds eram inicialmente investidores e tiveram a sorte de pegar os primeiros bull runs como o de 2013 e do ano passado.</p>
<p>A teoria de Simon e da Hashed até faz muito sentido pra mim por isso apresento ela aqui. E tem a ver com TRES pilares: cultura, demografia e timing político.</p>
<p>Para dar perspectiva, pense que a Coréia do Sul é um país BEM pequeno. Ele não está nem entre os top 100 países em tamanho. É quase o fim da lista dos top 30 de população. Mas mesmo assim figura quase entre os top 10 de PIB, estando em 12o lugar!</p>
<p>A coréia é globalmente mais conhecida hoje pelo que eu chamo dos TRES Ks: Kimchi, K-pop claro e Kryptomoedas.</p>
<p>Que outros fatos são interessantes? Eles tem uma das internets mais rápidas do mundo, liderando acima da China, acima do Japão.</p>
<p>Eu falei como todo coreano carrega um celular Samsung e eles tem a maior densidade de smartphones difundido na população. E não estamos falando de feature phones, tipos os Nokia baratos que ainda se usa em muitos lugares da China ou Índia por exemplo. Estamos falando de smartphones Android. E a penetração é nada menos que 94% da população!</p>
<p>Some isso ao fato que quase metade dessa população, 40%, vive em Seoul ou em cidades ao redor da região de Seoul e você tem uma das populações mais hiperconectadas do mundo. O Brasil por exemplo é prejudicado pela sua geografia, que isola as cidades e impede conexões maiores. Veja este vídeo para saber mais.</p>
<p><a href="https://www.youtube.com/watch?v=FQ2jmrz_xgU"target="_blank" rel="noopener">https://www.youtube.com/watch?v=FQ2jmrz_xgU</a></p>
<p>Por causa disso a Coréia tem a 4a maior receita de app store do mundo. Só em 2017 os sul coreanos gastaram nada menos que 3 BILHÕES de dólares no Google App Store comprando itens puramente digitais. Avatars, presentes digitais, upgrade de apps. Num jogo chamado Lineage que é um MMORPG tipo World of Warcraft, jogadores gastam até 1000 DÓLARES em espadas digitais de quantidade limitada.</p>
<p>Games, todo mundo sabe que a Coréia tem uma longa tradição em games, MMORPG, e-sports. Todo mundo neste ponto já conhece a Bluehole que é a criadora sul coreana do explosivo massive multiplayer battle royale PUBG. Mas essa tradição vem lá de trás.</p>
<p>Sabe qual é o MMORPG mais antigo ainda em funcionamento até hoje? Que tal NEXUS: The Kingdom of the Winds que foi lançado em 1996 (!!) e até hoje está funcionando?</p>
<p>Em 1999 você já tinha o primeiro serviço pago de avatars chamado SayClub!</p>
<p>Também em 1999 você tinha um tipo de rede social com microblogging onde você podia comprar mercadorias virtuais para mobiliar um quarto virtual chamado CyWorld, algo como um Orkut mas já envolvendo comércio.</p>
<p>E 1999 não pára porque daí você tinha um grande portal onde você podia jogar usando uma moeda virtual, o Hancoin, na plataforma Hangame.</p>
<p>E o próximo passo depois de comprar coisas virtuais é trocá-las e aí você tem a plataforma ItemBay em 2001, um e-Bay para coisas virtuais.</p>
<p>E a Coréia também embarcou na onda Napster de música p2p com seu próprio Soribada.</p>
<p>E isso sem contar o início do e-Sports com o Starcraft League em 2000, a primeira liga de e-sports a atrair popularidade nacional.</p>
<p>Um aspecto que eu mesmo não tinha me dado conta, e faz todo sentido, é que asiático é viciado em jogatina. E jogatina organizada tipo cassino é proibido em muitas dos países asiáticos como na China, Japão ou Coréia do Sul. Só estrangeiros podem frequentar os cassinos. Um exemplo, Macau tem metade dos casinos de Las Vegas mas tem o DOBRO da receita. E nem começamos a falar das apostas em corridas de cavalos.</p>
<p>Com tudo isso, estabelecemos que a sociedade coreana é altamente cosmopolita, com quase metade da população na grande região ao redor de Seoul, todo mundo altamente conectado onde as notícias se espalham muito rápido entre uma população altamente acostumada a jogatina online.</p>
<p>Mas em 2012 quando o Bitcoin começou seu primeiro grande crescimento parabólico (antes do crash por causa do Mt Gox e Silk Road) os coreanos ainda não tinha muito acesso a comprar Bitcoins e perderam essa corrida. Então quando o Ethereum apareceu e passou do USD 1 de valor já haviam várias exchanges operacionais e as pessoas viram como uma oportunidade de investir no “próximo Bitcoin”.</p>
<p>Quando o valor do Ethereum passou de USD 1 para USD 40 em 4 meses em 2016, a notícia de ganhos de 4000% se espalharam hiper rápido e todo mundo começou a comprar Ether como se não houvesse amanhã! E as notícias de ganhos extraordinários em altcoins como Ripple, Litecoin, Monero e outros continuaram a se espalhar extremamente rápido nas mídias sociais durante 2017.</p>
<p>Só uma coisa poderia parar isso: a intervenção do governo. Qualquer governo do mundo, principalmente em 2015 a 2016, depois do crash da Mt Gox de 2014, estaria atento vendo pessoas comprando coisas como Ether desgovernadamente e o preço subindo de USD 1 para USD 10 do nada.</p>
<p>Em 2013 a Coréia do Sul tava elegendo seu 18o presidente, a primeira presidente mulher da história não só da Coréia do Sul, mas do Leste Asiático -  박근혜 - Park Geun Hyeo .
Ela tinha longa carreira política e exerceu quatro termos consecutivos no parlamento desde 1998. Segundo nossa amiga Wikipedia, depois que foi eleita ela foi listada como décima-primeira das mulheres mais influentes da lista da Forbes e quadragésima-sexta (46) pessoa mais influente da lista da Forbes, em termos de coreanos ela tava só atrás do presidente e vice-presidente do poderoso grupo Samsung. Lembram? 15% do PIB??</p>
<p>Ela também era conhecida pela más línguas como a “filha do ditador”, Park Chung Hee 박정희 que liderou um golpe de estado em 1961. Pelo bem ou pelo mal, numa Coréia do Sul pós-liberação (lembra? Contra os fantoches do norte em 1950), tendo terminado a segunda república que não tinha apoio por acusações de terem fraudado as eleições de 1960, dizem que a ditadura de Park criou as fundações pro rápido período de industrialização do país. As ditaduras militares iam ainda continuar até 1993.</p>
<p>Em 1974 uma tentativa de assassinato deu errado e o tiro perdido matou a primeira mulher de Park - Yuk Young-soo 육영수.</p>
<p>Park Chung Hee e sua filha Park Geun Hye obviamente sofreram muito com a morte de Yuk Young Soo e eis que uma figura bizarra aparece: Choi Tae-min originalmente um monge budista que se converteu para a igreja católica romana e criou um culto xamanista chamado Yongsae-gyo (영세교), ou “Igreja do Espírito do Mundo”, se auto-declarando Maitreya, ou “Futuro Buda”! Ele apareceu na vida dos Park logo depois do assassinato de Yuk Young Soo dizendo que ela apareceu para ele e pediu para que ajudasse sua filha!</p>
<p>Park escapou de outras tentativas de assassinato, sendo 2 pelo menos ligados a simpatizantes da Coréia do Norte. Mas em 79 ele foi traído pelo seu amigo e diretor da agencia central de inteligencia - a fucking CIA da Coréia- Kim Jae-gyu 김재규 que depois foi capturado junto com seus comparsas, torturado, julgado, condenado e executado. Então, em 2 anos, a jovem Geun Hyeo perdeu sua mãe e seu pai.</p>
<p>E foi assim que o sinistro Choi se tornou mentor de Park Geun Hyeo e também foi assim que sua 5a filha Choi Soon Sil se tornou amiga de Park Geun Hyeo desde pelo menos 1977.</p>
<p>Com uma carreira em ascensão que culminou em ser eleita democraticamente presidente em 2013 começaram a aparecer os escândalos. Parece que Park se tornou mero fantoche dos Choi, sendo manipulada a vida inteira.</p>
<p>Mas como isso veio à tona? A Coréia do Sul não é para amadores. A coisa estourou por causa do Puppygate! Isso mesmo!</p>
<p>Em resumo, a tal Choi conheceu um ex-esgrimista e atleta olímpico, o Ko Young Tae, que estava com uma marca luxuosa de bolsas e roupas chamada Villomillo. Choi gostou dos itens e passou a dá-los para a presidente Park. E, claro, o Ko se beneficiou muito tendo sua cara marca de itens associada não-oficialmente a Park via Choi.</p>
<p>A coisa azedou uma vez que a Choi pediu para ele cuidar do cachorro da sua filha. Ko deixou o cachorro no seu apartamento e foi jogar golfe. Quando voltou tomou uma comida de rabo homérica por ele ter deixado o cachorro abandonado. Daí ela passou a tratar ele mal, xingando ele, tratando como escravo. E o que fez o sr. Ko? Resolveu devolver os maus tratos: foi pra imprensa e contou da relação da Choi com Park. Aí a casa caiu.</p>
<p>Foi revelado como Choi Soon Sil que Não tem afiliação política nem nenhum tipo de cargo oficial tinha acesso a documentos confidenciais do governo, chegando a editar os discursos de Park. Também por causa dessa relação apareceu que Park fazia as grandes empresas como Samsung doar mais de dezenas de milhões de dólares para ONGs controladas por Choi.</p>
<p>Em resumo, como vocês sabem, o boca a boca corre MUITO rápido na população hiperconectada de Seoul. E em outubro de 2015 o povo já tava de saco cheio e foi pras ruas pedindo a renúncia de Park. Ela se recusou a renunciar mesmo tendo chegado ao pior índice de aceitação da história da Coréia do Sul, indo para 1% entre as pessoas abaixo de 60 anos de idade.</p>
<p>Choi foi até chamada por muitos de a Rasputin Coreana. Depois de muitas investigações e muita merda jogada no ventilador que espirrou em gigantes como os grupos Samsung e Lotte, terminou com a condenação de 20 anos de prisão de Choi.
E tentando relutar e negar até o fim, boicotando os julgamentos, ela terminou condenada por 16 das 18 acusações e terminou com uma sentença de 24 anos de prisão.  Agora ela está cumprindo sua pena no Centro de Detenção de Seoul.
Muitos ainda apoiam a ex-presidente e dizem que foi Golpe. ..</p>
<p>Sério, essa história é surreal. Quando você acha que já viu de tudo .. mas eu sei que ficou longo mas a história é tão legal que eu me empolguei aqui.</p>
<p>E o que tudo isso tem a ver com criptomoedas você se pergunta. Imagine o rebuliço que ficaram todas as instâncias de todas as instituições do país enquanto as investigações e o escrutínio da mídia e do público pegavam fogo.</p>
<p>Vocês acham que alguém do governo tava prestando atenção em Ethereum, que estava tendo uma valorização meteórica de preço de USD 1 para USD 40 e a mesma coisa estava começando a acontecer com outras alt-coins. Num período normal o governo teria brecado isso.</p>
<p>E eis a receita de como a Coréia do Sul saltou para o país com o maior volume de transações em criptomoedas em 2017. Imagina, uma população viciada por jogatina, ouvindo falar de novos milionários aparecendo do dia para a noite por causa de uma novidade chamada criptomoedas. O boca a boca digital de uma população quase inteira hiperconectada.</p>
<p>Nos Estados Unidos parece que nem 1% da população tem criptomoedas. De acordo com algumas pesquisas da Hashed, parece que nada menos que 30% dos trabalhadores assalariados da coréia do sul já tem criptomoedas em alguma forma, e isso é um número conservador. Alguns acreditam que o número real seja mais próximo dos 50% ou mais.</p>
<p>Além disso nos Estados Unidos, a maioria dos investidores está concentrado em grupos mais jovens, de millennials. Na Coréia até sua avó está investindo em criptomoedas. Não é incomum encontrar grupos de velhinhas discutindo altcoins nos cafés de Seoul.</p>
<p>Como disse no começo, é muito difícil dizer que essa exata sequência de eventos foram realmente os determinantes, mas que é uma puta boa história, isso é. E no mínimo serve para tornar a imagem que temos dos coreanos mais colorida.</p>
<p>E no próximo episódio vou ser mais leve e vamos tratar dos outros assuntos e startups que vi nos eventos. Em particular, vamos começar a tocar no assunto de ICOs!</p>
<p>Nos vemos em breve! Câmbio e desligo!</p>
]]></content:encoded><category>bitcoin-e-criptomoedas</category><category>politica</category><category>games</category><category>akitando</category></item><item><title>Partidas, Rankings, A Rede Social, League of Legends e Ruby?</title><link>https://akitaonrails.github.io/2016/11/01/partidas-rankings-rede-social-league-of-legends-ruby/</link><guid isPermaLink="true">https://akitaonrails.github.io/2016/11/01/partidas-rankings-rede-social-league-of-legends-ruby/</guid><pubDate>Tue, 01 Nov 2016 10:20:00 -0200</pubDate><description>&lt;p&gt;Tem um trecho de uma série de palestras que venho apresentando no Brasil há uns 3 anos sobre o qual nunca escrevi no blog. Ontem acabei de &lt;a href="http://www.akitaonrails.com/2016/10/31/implementacao-ruby-on-rails-sistema-ranking-popularidade-correto"target="_blank" rel="noopener"&gt;postar sobre a forma correta de ranquear conteúdo por &amp;ldquo;popularidade&amp;rdquo;&lt;/a&gt; então achei que valia revisitar o tema.&lt;/p&gt;
&lt;p&gt;Pra começar, acredito que a essa altura quase todo mundo já assistiu ao filme &amp;ldquo;A Rede Social&amp;rdquo;. É curioso que ouvi várias pessoas dizerem como esse filme as influenciou a começar suas próprias startups. Aí eu fiquei pensando, &amp;ldquo;o que esse filme realmente ensina?&amp;rdquo;&lt;/p&gt;</description><content:encoded><![CDATA[<p>Tem um trecho de uma série de palestras que venho apresentando no Brasil há uns 3 anos sobre o qual nunca escrevi no blog. Ontem acabei de <a href="http://www.akitaonrails.com/2016/10/31/implementacao-ruby-on-rails-sistema-ranking-popularidade-correto"target="_blank" rel="noopener">postar sobre a forma correta de ranquear conteúdo por &ldquo;popularidade&rdquo;</a> então achei que valia revisitar o tema.</p>
<p>Pra começar, acredito que a essa altura quase todo mundo já assistiu ao filme &ldquo;A Rede Social&rdquo;. É curioso que ouvi várias pessoas dizerem como esse filme as influenciou a começar suas próprias startups. Aí eu fiquei pensando, &ldquo;o que esse filme realmente ensina?&rdquo;</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/567/pasted-image-765.jpg" alt="The Social Network Casting"  loading="lazy" /></p>
<p>Bom, do filme aprendemos que David Fincher é um diretor fantástico, que Aaron Sorkin escreve diálogos afiadíssimos e envolventes, que Justin Timberlake faz um Sean Parker melhor que o real, que Andrew Garfield faz um Eduardo Saverin razoável, e que Jesse Eisenberg vai ser para sempre o Mark Zuckerberg.</p>
<p>E é só isso, não dá pra aprender mais nada do filme.</p>
<p>Ou dá?</p>
<h3>Facemesh<span class="hx:absolute hx:-mt-20" id="facemesh"></span>
    <a href="#facemesh" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Uma das minhas cenas favoritas do filme é quando Zuckerberg/Eisenberg fica puto com o término com a Erica Albright e começa a raspar fotos de mulheres dos sites de Harvard, organizando elas num site trollesco chamado &ldquo;Facemesh&rdquo;, onde coloca as fotos pra competir entre si. As pessoas votam em qual foto preferem e o site as ordena num ranking de popularidade.</p>
<p>Quando Eduardo Saverin/Andrew Garfield aparece, Zuckerberg pergunta:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/BzZRr4KV59I"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<blockquote>
  <p>&ldquo;Wardo, preciso de você (&hellip;) preciso do algoritmo usado para ranquear jogadores de xadrez&rdquo;</p>

</blockquote>
<p>E ele vai lá e escreve o seguinte na janela do dormitório:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/569/pasted-image-759.jpg" alt="Through the Looking Glass"  loading="lazy" /></p>
<p>Aqui a maioria das pessoas pensaria:</p>
<blockquote>
  <p>&ldquo;pff, mais uma fórmula sem sentido só pra mostrar que eles são gênios mirins, mas com certeza essa fórmula nem existe&rdquo;</p>

</blockquote>
<p>Só que ela existe. E essa é a única cena do filme que ficou martelando na minha cabeça porque eu já tinha visto isso antes. Pra ajudar, vamos inverter a imagem espelhada:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/568/pasted-image-761.jpg" alt="The Algorithm"  loading="lazy" /></p>
<p>E esse é o &ldquo;algoritmo&rdquo;.</p>
<p>Como falei no artigo anterior, a maioria dos desenvolvedores criaria um site tipo Facemesh adicionando campos inteiros na tabela de competidores com a contagem de upvotes, downvotes e fariam alguma bobagem do tipo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">score</span> <span class="o">=</span> <span class="n">upvotes</span> <span class="o">-</span> <span class="n">downvotes</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ou algo ainda mais bobo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">score</span> <span class="o">=</span> <span class="n">upvotes</span> <span class="o">/</span> <span class="p">(</span><span class="n">upvotes</span> <span class="o">+</span> <span class="n">downvotes</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E não funciona desse jeito, você vai obter rankings completamente errados.</p>
<h3>A Demonstração<span class="hx:absolute hx:-mt-20" id="a-demonstração"></span>
    <a href="#a-demonstra%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Pra mostrar o quão errado, criei um projeto simples de demonstração chamado <a href="https://github.com/akitaonrails/elo_demo"target="_blank" rel="noopener">elo_demo</a> que você pode clonar e rodar.</p>
<p>Ele cria 2.000 partidas aleatórias entre 10 jogadores. Esse vai ser o resultado ordenado se usarmos o método errado de subtrair derrotas das vitórias e ordenar por esse resultado:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>   Name        Games  Wins  Losses Points (wins - losses)
 1 Kong          217   117    100     17
 2 Samus         211   110    101      9
 3 Wario         197   102     95      7
 4 Luigi         186    95     91      4
 5 Zelda         160    81     79      2
 6 Pikachu       209   105    104      1
 7 Yoshi         223   112    111      1
 8 Mario         203   101    102     -1
 9 Fox           208    95    113    -18
10 Bowser        186    82    104    -22</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora, vamos fazer com que a Samus (2º lugar) vença 10 vezes seguidas o Wario (3º lugar). Esse é o novo ranking:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>   Name        Games  Wins  Losses Points
 1 Samus         221   120    101     19
 2 Kong          217   117    100     17
 3 Luigi         186    95     91      4
 4 Zelda         160    81     79      2
 5 Pikachu       209   105    104      1
 6 Yoshi         223   112    111      1
 7 Mario         203   101    102     -1
 8 Wario         207   102    105     -3
 9 Fox           208    95    113    -18
10 Bowser        186    82    104    -22</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Parece justo, Samus pula pro 1º lugar e Wario desce pro 8º.</p>
<p>Agora, e se fizermos o fraquinho Bowser (10º lugar) vencer 10 vezes contra o atual 2º lugar, Kong?</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>   Name        Games  Wins  Losses Points
 1 Samus         221   120    101     19
 2 Kong          227   117    110      7
 3 Luigi         186    95     91      4
 4 Zelda         160    81     79      2
 5 Pikachu       209   105    104      1
 6 Yoshi         223   112    111      1
 7 Mario         203   101    102     -1
 8 Wario         207   102    105     -3
 9 Bowser        196    92    104    -12
10 Fox           208    95    113    -18</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>É aqui que dá pra ver o quão <strong>errado</strong> esse método é. Mesmo perdendo 10 vezes contra o jogador mais fraco, Kong continua reinando absoluto no 2º lugar. E o pobre Bowser, apesar de todo seu esforço e dedicação, sobe apenas 1 mísera posição, do 10º pro 9º.</p>
<p>Isso é muito frustrante e parece injusto porque é injusto mesmo. Esse tipo de cálculo é <strong>errado</strong>.</p>
<h3>Do Xadrez ao League of Legends<span class="hx:absolute hx:-mt-20" id="do-xadrez-ao-league-of-legends"></span>
    <a href="#do-xadrez-ao-league-of-legends" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Se você já jogou League of Legends, provavelmente está familiarizado com algo chamado &ldquo;ELO Boost&rdquo;.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/570/Screen_Shot_2016-11-01_at_10.19.42.png" alt="Elo Boost"  loading="lazy" /></p>
<p>É uma forma de subir de nível sua conta pagando dinheiro. Recomendo fortemente evitar isso se você pretende competir profissionalmente porque é contra as regras da Riot.</p>
<p>De qualquer forma, você já se perguntou por que se chama &ldquo;ELO&rdquo;?</p>
<p>É uma homenagem ao professor austro-húngaro <strong>Arpad Emmerich Elo</strong>. Ele é mais conhecido pelo seu sistema de rating de jogadores de xadrez. Citando a Wikipedia:</p>
<blockquote>
  <p>O sistema original de rating de xadrez foi desenvolvido em 1950 por Kenneth Harkness (&hellip;). Em 1960, usando os dados desenvolvidos pelo Sistema de Rating de Harkness, Elo desenvolveu sua própria fórmula que tinha uma <strong>base estatística sólida</strong> e constituía uma melhoria sobre o Sistema Harkness. O novo sistema de rating foi aprovado em uma reunião da Federação de Xadrez dos Estados Unidos em St. Louis em 1960.</p>

</blockquote>
<blockquote>
  <p>Em 1970, a FIDE, a Federação Mundial de Xadrez, concordou em adotar o Sistema de Rating Elo. Daquele momento até meados dos anos 80, o próprio Elo fazia os cálculos de rating. Naquela época, a tarefa computacional era relativamente fácil porque menos de 2000 jogadores eram ranqueados pela FIDE.</p>

</blockquote>
<p>O sistema dele foi refinado e evoluiu pra tornar os leaderboards de torneios realmente justos e competitivos. Uma dessas evoluções é o <a href="https://www.microsoft.com/en-us/research/project/trueskill-ranking-system/"target="_blank" rel="noopener">TrueSkill Ranking System</a> da Microsoft, usado em todos os jogos do Xbox Live.</p>
<p>Aquele &ldquo;algoritmo&rdquo; que Eduardo Saverin escreve na janela do dormitório de Harvard? É o <strong>Sistema de Rating ELO</strong>!!</p>
<p>Não sei se Zuckerberg de fato implementou as equações do sistema ELO. Se implementou, foi a escolha <strong>correta</strong>. Mas a história toda do Eduardo escrevendo as equações na janela provavelmente não aconteceu desse jeito porque seria muito mais fácil dar um Google :-)</p>
<h3>Demonstração do Sistema de Rating ELO<span class="hx:absolute hx:-mt-20" id="demonstração-do-sistema-de-rating-elo"></span>
    <a href="#demonstra%c3%a7%c3%a3o-do-sistema-de-rating-elo" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Meu projetinho de demonstração também calcula esse exato score ELO. Os cálculos são feitos pela rubygem <a href="https://github.com/iain/elo"target="_blank" rel="noopener">elo</a>.</p>
<p>A ideia é calcular a probabilidade que um jogador tem de vencer o outro. Então, se um jogador forte joga contra um fraco, espera-se que ele vença, e se esse for o resultado, ele vai pontuar pouco e o perdedor também não vai cair muito. Mas se acontecer o inesperado e o forte perder, espera-se que ele caia bastante e que o jogador &ldquo;mais fraco&rdquo; suba bastante.</p>
<p>Isso torna os torneios mais competitivos, motiva os novos jogadores a enfrentar os mais fortes, e força os mais fortes a jogar pesado pra manter suas posições.</p>
<p>Pela documentação da gem elo, é assim que se usa:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">kong</span>  <span class="o">=</span> <span class="no">Elo</span><span class="o">::</span><span class="no">Player</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl"><span class="n">bowser</span> <span class="o">=</span> <span class="no">Elo</span><span class="o">::</span><span class="no">Player</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:rating</span> <span class="o">=&gt;</span> <span class="mi">1500</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">game1</span> <span class="o">=</span> <span class="n">kong</span><span class="o">.</span><span class="n">wins_from</span><span class="p">(</span><span class="n">bowser</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">game2</span> <span class="o">=</span> <span class="n">kong</span><span class="o">.</span><span class="n">loses_from</span><span class="p">(</span><span class="n">bowser</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">game3</span> <span class="o">=</span> <span class="n">kong</span><span class="o">.</span><span class="n">plays_draw</span><span class="p">(</span><span class="n">bowser</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">game4</span> <span class="o">=</span> <span class="n">kong</span><span class="o">.</span><span class="n">versus</span><span class="p">(</span><span class="n">bowser</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">game4</span><span class="o">.</span><span class="n">winner</span> <span class="o">=</span> <span class="n">bowser</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">game5</span> <span class="o">=</span> <span class="n">kong</span><span class="o">.</span><span class="n">versus</span><span class="p">(</span><span class="n">bowser</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">game5</span><span class="o">.</span><span class="n">loser</span> <span class="o">=</span> <span class="n">bowser</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">game6</span> <span class="o">=</span> <span class="n">kong</span><span class="o">.</span><span class="n">versus</span><span class="p">(</span><span class="n">bowser</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">game6</span><span class="o">.</span><span class="n">draw</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">game7</span> <span class="o">=</span> <span class="n">kong</span><span class="o">.</span><span class="n">versus</span><span class="p">(</span><span class="n">bowser</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">game7</span><span class="o">.</span><span class="n">result</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># resultado é na perspectiva do kong, então kong vence</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">game8</span> <span class="o">=</span> <span class="n">kong</span><span class="o">.</span><span class="n">versus</span><span class="p">(</span><span class="n">bowser</span><span class="p">,</span> <span class="ss">:result</span> <span class="o">=&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="c1"># bowser vence</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E é assim que se acessa os resultados:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">kong</span><span class="o">.</span><span class="n">rating</span>       <span class="c1"># =&gt; 1080</span>
</span></span><span class="line"><span class="cl"><span class="n">kong</span><span class="o">.</span><span class="n">pro?</span>         <span class="c1"># =&gt; false</span>
</span></span><span class="line"><span class="cl"><span class="n">kong</span><span class="o">.</span><span class="n">starter?</span>     <span class="c1"># =&gt; true</span>
</span></span><span class="line"><span class="cl"><span class="n">kong</span><span class="o">.</span><span class="n">games_played</span> <span class="c1"># =&gt; 8</span>
</span></span><span class="line"><span class="cl"><span class="n">kong</span><span class="o">.</span><span class="n">games</span>        <span class="c1"># =&gt; [ game1, game2, ... game8 ]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A gem tem mais ajustes além do algoritmo original, como o K-factor pra recompensar novos jogadores. Esses tipos de ajustes são o que torna as partidas mais competitivas hoje e como você evolui pra níveis de TrueSkill, mas isso foge do escopo deste artigo.</p>
<p>Vamos ver o ranking errado de novo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>   Name        Games  Wins  Losses Points (wins - losses)
 1 Kong          217   117    100     17
 2 Samus         211   110    101      9
 3 Wario         197   102     95      7
 4 Luigi         186    95     91      4
 5 Zelda         160    81     79      2
 6 Pikachu       209   105    104      1
 7 Yoshi         223   112    111      1
 8 Mario         203   101    102     -1
 9 Fox           208    95    113    -18
10 Bowser        186    82    104    -22</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora vamos ver como fica o ranking <strong>correto</strong> calculando o score Elo usando exatamente as mesmas 2.000 partidas:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>   Name        Games  Wins  Losses Points  Elo Rating
 1 Pikachu       209   105    104      1         851
 2 Zelda         160    81     79      2         847
 3 Samus         211   110    101      9         842
 4 Luigi         186    95     91      4         841
 5 Wario         197   102     95      7         824
 6 Mario         203   101    102     -1         820
 7 Yoshi         223   112    111      1         803
 8 Kong          217   117    100     17         802
 9 Bowser        186    82    104    -22         785
10 Fox           208    95    113    -18         754</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Viu como é diferente? No ranking errado, Kong é considerado o mais forte, mas no ranking Elo ele está apenas em 8º lugar. E a razão é que mesmo sendo quem venceu mais partidas (217), também perdeu pra caramba (117). Alguém com menos vitórias, como a Zelda em 2º lugar (160 vitórias), perdeu muito menos (81), e é por isso que ela está mais alta no ranking.</p>
<p>Agora, se fizermos ela vencer 10 partidas seguidas contra a Samus (3º lugar), esse é o novo ranking:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>   Name        Games  Wins  Loses  Points  Elo Rating
 1 Zelda         170    91     79     12         904
 2 Pikachu       209   105    104      1         851
 3 Luigi         186    95     91      4         841
 4 Wario         197   102     95      7         824
 5 Mario         203   101    102     -1         820
 6 Yoshi         223   112    111      1         803
 7 Kong          217   117    100     17         802
 8 Bowser        186    82    104    -22         785
 9 Samus         221   110    111     -1         775
10 Fox           208    95    113    -18         754</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>De novo, Zelda pula do 2º pro 1º lugar e Samus cai do 3º pro 9º. Até aqui, tudo certo. Mas e o cenário onde fazemos o forte Pikachu (2º lugar) jogar contra o muito mais fraco Fox McCloud (10º lugar)?</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>   Name        Games  Wins  Loses  Points  Elo Rating
 1 Zelda         170    91     79     12         904
 2 Luigi         186    95     91      4         841
 3 Fox           218   105    113     -8         829
 4 Wario         197   102     95      7         824
 5 Mario         203   101    102     -1         820
 6 Yoshi         223   112    111      1         803
 7 Kong          217   117    100     17         802
 8 Bowser        186    82    104    -22         785
 9 Samus         221   110    111     -1         775
10 Pikachu       219   105    114     -9         766</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora sim, isso é justiça: Pikachu deveria ter vencido, mas perder 10 vezes seguidas contra alguém considerado muito mais fraco faz ele cair do 2º lugar lá pro último. E o novato Fox, tendo vencido 10 vezes contra um oponente muito mais forte, merece pular lá pro 3º lugar.</p>
<p>Esse é o tipo de dinâmica que torna partidas e jogos competitivos, e é exatamente por isso que todo leaderboard online e torneio profissional usa esse tipo de algoritmo.</p>
<p>E tudo começou no xadrez, usando matemática conhecida desde o final dos anos 40!!</p>
<blockquote>
  <p>Esse é o ponto deste post e do anterior: <strong>a matemática não é nova</strong>.</p>

</blockquote>
<p>Desenvolvedores perdem uma quantidade enorme de tempo em discussões idiotas sobre qual linguagem ou ferramenta é &ldquo;mais brilhante&rdquo;, mas ignoram a matemática adequada e entregam resultados errados. E essa matemática existe há décadas, em alguns casos há mais de um século já!</p>
<p>Deveríamos lutar pra merecer o título de <em>Cientistas</em> da Computação. Falta muita <strong>ciência</strong> na computação hoje em dia. Discussões inflamadas não tornam ninguém um bom programador.</p>
]]></content:encoded><category>algoritmos-e-estruturas-de-dados</category><category>games</category></item><item><title>Off Topic: Por que programadores devem jogar Go</title><link>https://akitaonrails.github.io/2008/07/15/off-topic-por-que-programadores-devem-jogar-go/</link><guid isPermaLink="true">https://akitaonrails.github.io/2008/07/15/off-topic-por-que-programadores-devem-jogar-go/</guid><pubDate>Tue, 15 Jul 2008 01:07:00 -0300</pubDate><description>&lt;p&gt;Faz tempo que não faço traduções, mas este artigo foi bastante nostálgico para mim, então fiz questão de divulgá-lo. É pelo &lt;a href="http://web.archive.org/web/20080720152831/http://railspikes.com/2008/7/14/why-programmers-should-play-go"target="_blank" rel="noopener"&gt;Jon Dahl&lt;/a&gt; do blog &lt;strong&gt;RailSpikes&lt;/strong&gt;. Leiam minhas &lt;a href="#notas-do-akita"&gt;notas&lt;/a&gt; no final. Aqui vai:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://flickr.com/photos/andres-colmen/2539473895/"target="_blank" rel="noopener"&gt;&lt;img src="http://s3.amazonaws.com/akitaonrails/assets/2008/7/15/2539473895_47418f2049.jpg" alt="" loading="lazy" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Go_%28board_game%29"target="_blank" rel="noopener"&gt;Go&lt;/a&gt; é um antigo jogo de estratégia com regras simples e um profundo grau de complexidade.&lt;/p&gt;
&lt;p&gt;Desenvolvimento de software é a arte de gerenciar complexidade usando um número limitado de regras, estruturas e padrões.&lt;/p&gt;
&lt;p&gt;Programadores deveriam jogar Go.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Faz tempo que não faço traduções, mas este artigo foi bastante nostálgico para mim, então fiz questão de divulgá-lo. É pelo <a href="http://web.archive.org/web/20080720152831/http://railspikes.com/2008/7/14/why-programmers-should-play-go"target="_blank" rel="noopener">Jon Dahl</a> do blog <strong>RailSpikes</strong>. Leiam minhas <a href="#notas-do-akita">notas</a> no final. Aqui vai:</p>
<p><a href="http://flickr.com/photos/andres-colmen/2539473895/"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/7/15/2539473895_47418f2049.jpg" alt=""  loading="lazy" /></a></p>
<p><a href="http://en.wikipedia.org/wiki/Go_%28board_game%29"target="_blank" rel="noopener">Go</a> é um antigo jogo de estratégia com regras simples e um profundo grau de complexidade.</p>
<p>Desenvolvimento de software é a arte de gerenciar complexidade usando um número limitado de regras, estruturas e padrões.</p>
<p>Programadores deveriam jogar Go.</p>
<h3>Go em 2<sup>8</sup> palavras ou menos<span class="hx:absolute hx:-mt-20" id="go-em-28-palavras-ou-menos"></span>
    <a href="#go-em-28-palavras-ou-menos" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A beleza do Go é sua combinação de simplicidade e complexidade. Por um lado, Go tem somente poucas regras. Coloque as pedras, não fique completamente cercado, controle o território. Como xadrez, a mecânica pode ser aprendida em alguns minutos, embora Go tenha somente um único tipo de “movimento”, e somente um caso extremo (a regra <a href="http://en.wikipedia.org/wiki/Rules_of_Go#Ko_.28no_repetition_of_the_same_shape.29"target="_blank" rel="noopener">Ko</a>). E como xadrez, uma pessoa pode gastar a vida toda descobrindo as camadas estratégicas e táticas do jogo.</p>
<p>Enquanto xadrez é bem complexo e rico, tal que levou um supercomputador de 30 nós para derrotar o campeão de xadrez, nenhum computador chega próximo de derrotar mesmo um amador habilidoso de Go. Existem 361 posições no tabuleiro de Go e, com dois jogadores, existem 2,08168199382×10<sup>170</sup> posições válidas. Isso é bem maior do que um <a href="http://en.wikipedia.org/wiki/Googol"target="_blank" rel="noopener">googol</a> (sim, é assim que se escreve). Realisticamente, existe algo na ordem de 10<sup>400</sup> jeitos diferentes que um típico jogo pode ser jogado. E o número de movimentos possíveis mais ou menos segue 361! (361 fatorial), o que significa que com somente uns 20 movimentos, existem muitos googols de maneiras possíveis que um jogo pode continuar. (Como curiosidade, experimente calcular 361! em uma <a href="http://web.archive.org/web/20240416232143/https://www.cs.uml.edu/~ytran/factorial.html"target="_blank" rel="noopener">calculadora fatorial</a> online).</p>
<h3>Gerenciando Complexidade<span class="hx:absolute hx:-mt-20" id="gerenciando-complexidade"></span>
    <a href="#gerenciando-complexidade" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Então, como uma pessoa pode jogar Go, dada a complexidade quase infinita? Em um nível tático, um jogador encara Go como xadrez, pensando vários movimentos à frente. Mas isso somente funciona em pequenos espaços, como uma batalha apertada em um pequeno setor do tabuleiro. Mais do que isso, existem possibilidades demais. Então, de maneira estratégica, um jogador precisa pensar em padrões de <a href="http://en.wikipedia.org/wiki/Shape_%28Go%29"target="_blank" rel="noopener">formas</a>. Essas formas dão atalhos para o gerenciamento de complexidade do Go. Como um não-mestre, posso não ter nenhuma idéia de como as coisas vão acontecer em um setor do tabuleiro, mas posso ser capaz de reconhecer padrões fortes e fracos de pedras, formas vulneráveis e formações efetivas.</p>
<p>Mas há mais: Go tem diversas formas de padrões. Mais do que formas, existem <a href="http://senseis.xmp.net/?GoProverbs"target="_blank" rel="noopener">provérbios de Go</a>. Eles podem ser generalistas: <em>“O bom movimento de seu oponente é seu bom movimento”</em>; específicos: <em>“Não tente cortar o salto de um ponto”</em>; engraçados: <em>“Até um idiota conecta contra um peep”</em>; e meta: <em>“Não siga provérbios cegamente.”</em> Esses provérbios são princípios que ajudam um jogador a tomar boas decisões. Eles são menos específicos do que formas, e portanto fornecem guias para quaisquer situações que possam surgir no tabuleiro de Go. Provérbios podem entrar em conflito, e um jogador deve determinar quando e como aplicá-los.</p>
<p>Finalmente, existe <a href="http://en.wikipedia.org/wiki/Joseki"target="_blank" rel="noopener">Joseki</a>. Joseki são padrões de jogo que são considerados iguais para ambos os lados. Eles tipicamente acontecem em cantos do tabuleiro, e tipicamente no começo do jogo. De forma interessante, existe um provérbio no Go que diz <em>“Aprender joseki custa 2 pedras”</em> o que pode significar que memorizar esses padrões não é interessante. Em vez disso, um jogador deve aprender <em>a partir</em> dos joseki entendendo o que está acontecendo a cada movimento.</p>
<h3>Padrões em Go, padrões em design de software<span class="hx:absolute hx:-mt-20" id="padrões-em-go-padrões-em-design-de-software"></span>
    <a href="#padr%c3%b5es-em-go-padr%c3%b5es-em-design-de-software" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Cada um desses padrões de Go tem, mais ou menos, um análogo em programação.</p>
<p>Formas em Go se parecem com <a href="http://c2.com/cgi/wiki?DesignPatterns"target="_blank" rel="noopener">design patterns</a> em software. Enquanto não há nada que o previna de colocar lógica em suas views, essa forma é <a href="http://www.vimeo.com/1050804"target="_blank" rel="noopener">reconhecida</a> como uma forma fraca. Pense em design patterns do Gang-of-Four: os padrões MVC, Adapter e Factory são reconhecidos como úteis em algumas circunstâncias (e não apropriadas em outras). Em um nível mais baixo, iteração e recursão têm formas comumente reconhecidas, assim como normalização de bancos de dados vs. denormalização. Mesmo que você não possa ter um programa inteiro ou algoritmo de cabeça de uma vez, reconhecer formas padrão ajuda a entender o que está acontecendo.</p>
<p>Provérbios de Go são como outras formas de padrões em software: CapitalizedPrinciples (por falta de um termo melhor) que se tornaram populares graças a Extreme Programming. Pense em DontRepeatYourself, YouArentGonnaNeedIt, CollectiveCodeOwnership, DailyBuild, TestFirst. Eles não são “formas” de código, como uma classe singleton – são princípios gerais que guiam a prática de programação.</p>
<p>Como joseki é sobre troca entre pares competidores, seu paralelo de programação é um pouco menos claro. A comparação mais próxima, na minha cabeça, são exercícios de programação. <a href="http://binstock.blogspot.com/2008/04/perfecting-oos-small-classes-and-short.html"target="_blank" rel="noopener">Este artigo</a>, por exemplo, sugere 9 exercícios para ajudá-lo a se tornar um melhor programador OO, como:</p>
<ul>
<li>use apenas um ponto por linha</li>
<li>use apenas um nível de indentação por método</li>
<li>não use setters, getters ou propriedades</li>
</ul>
<p>Em um programa real, você não seguirá esses princípios 100% do tempo. Mas se forçar a escrever dessa maneira pode ser uma experiência de abrir os olhos e pode torná-lo um desenvolvedor melhor.</p>
<h3>Então o que Go pode realmente fazer por você?<span class="hx:absolute hx:-mt-20" id="então-o-que-go-pode-realmente-fazer-por-você"></span>
    <a href="#ent%c3%a3o-o-que-go-pode-realmente-fazer-por-voc%c3%aa" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Obviamente, esses paralelos são estruturais. Provérbios específicos de Go podem não ter relevância direta com desenvolvimento de software. Então, pode Go realmente torná-lo um melhor desenvolvedor?</p>
<p>Eu acho que pode, e vou mais fundo. Acho que Go pode torná-lo mais esperto. Existem muitas evidências anedóticas sobre esse efeito <a href="http://web.archive.org/web/20170616121831/http://www.godiscussions.com/forum/archive/index.php/t-6061.html"target="_blank" rel="noopener"><sup class="footnote" id="fnr1"><a href="#fn1">1</a></sup></a>, <a href="http://news.ycombinator.com/item?id=133178"target="_blank" rel="noopener"><sup class="footnote" id="fnr2"><a href="#fn2">2</a></sup></a>, <a href="http://news.ycombinator.com/item?id=228356"target="_blank" rel="noopener"><sup class="footnote" id="fnr3"><a href="#fn3">3</a></sup></a>, por exemplo, <a href="http://www.china.org.cn/english/features/Archaeology/131298.htm"target="_blank" rel="noopener"><sup class="footnote" id="fnr4"><a href="#fn4">4</a></sup></a> :</p>
<blockquote>
  <p>De fato, todas as nossas mentes podem se beneficiar com o aprendizado do Go, que oficialmente tem a capacidade de torná-lo mais esperto. Pesquisas demonstram que crianças que jogam Go têm o potencial de grande inteligência, já que motiva os dois lados do cérebro.</p>

</blockquote>
<p>A pesquisa mencionada não cita referências, infelizmente, portanto não leve esse tipo de afirmação ao pé-da-letra.</p>
<p>Mas faz muito sentido: como xadrez, Go requer reconhecimento de padrões, uma mistura de estratégia e pensamento tático, e compreensão de estruturas complexas, embora em Go os padrões sejam maiores e muito mais complexos. Uma mente treinada a pensar dessa maneira terá mais facilidade em atacar problemas similares em outras esferas.</p>
<p>Como desenvolvimento de software.</p>
<h3>Notas do Akita<span class="hx:absolute hx:-mt-20" id="notas-do-akita"></span>
    <a href="#notas-do-akita" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Há muito tempo eu gosto de Go. Como descendente de japonês é claro que eu já vi Go, Shogi e outros jogos orientais. Mas, como todo bom japonês ocidental, eu dei muita pouca atenção a isso. Por causa disso, hoje não sei mais do que as regras e filosofias básicas por trás do Go.</p>
<p>Particularmente o interesse se renovou quando li a série <a href="http://en.wikipedia.org/wiki/Hikaru_no_Go"target="_blank" rel="noopener">Hikaru no Go</a>, que é uma história inteira sobre Go, aliás uma das minhas séries favoritas. Cheguei a comprar um tabuleiro de Go, alguns livros de Joseki, mas não fui muito longe. Hoje em dia apenas dou umas espiadas nos jogos online nos servidores da <a href="https://pandanet-igs.com/"target="_blank" rel="noopener">IGS</a>.</p>
<p><a href="http://web.archive.org/web/20080725154909/http://www.onemanga.com/Hikaru_no_Go/"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/7/15/1hikaru800.jpg" alt=""  loading="lazy" /></a></p>
<p>Não lembro onde li isso, mas alguém chegou a mencionar uma coisa interessante: xadrez é um jogo primordialmente de destruição. Go é um jogo essencialmente de conquista e expansão. Não é literalmente verdade, mas há nuances em Go que me remetem a isso.</p>
<p>E no paralelo a desenvolvimento de software, design patterns não são apenas estruturas que você copia e cola onde “acha” que são necessários. Um punhado de design patterns não faz um bom software.</p>
<p>O que o Jon quis dizer faz muito sentido. Assim como um jogador de Go, um desenvolvedor de software precisa ser um artista. Jogar é uma atividade criativa. Estratégia é uma atividade criativa. Dada uma série de limitações, qual o melhor caminho a seguir?</p>
<p>Mais do que isso: a única maneira de aprender Go é jogando, centenas de milhares de vezes durante muitos e muitos anos. Profissionais de Go se formam lá entre os 10 anos de idade e sobem dali até a velhice. A única forma de aprender é errando, errando e errando. O que volta ao que o Ryan falou sobre <a href="/2008/06/14/machucando-c-digo-por-divers-o-e-lucro/">Machucar Código</a>.</p>
<p>Refatoramento é algo parecido com isso: conquista e expansão. Somente um bom desenvolvedor entende os reais motivos de refatoramento. Ninguém refatora porque alguém mandou refatorar, da mesma forma que um artista não faz um certo traço porque alguém mandou fazer.</p>
<p>Um bom desenvolvedor dá valor à forma e à filosofia do que se constrói. Siglas, marcas e nomes da moda não dizem nada para ele.</p>
<p>Falta algo de filosofia oriental nos programadores de hoje. Ser um codificador no estilo empilhador-de-tijolos é muito fácil: qualquer peão pode fazer. Agora, chegar ao <a href="http://en.wikipedia.org/wiki/Go_ranks_and_ratings"target="_blank" rel="noopener">10<sup>o</sup> dan</a> de programação, é somente para os que se esforçaram muito na arte.</p>
]]></content:encoded><category>aprendizado</category><category>programacao</category><category>games</category><category>off-topic</category></item></channel></rss>