Projetei meu próprio dispositivo portátil de jogo baseado em um microcontrolador AVR e em um pequeno monitor OLED.
Comecei com uma tela monocromática de 128x64 pixels e posso desenhar confortavelmente mais de 60 quadros por segundo.
Recentemente, reformulei-o para usar um RGB OLED de 128x128 pixels sem realmente pensar muito apenas para descobrir que só conseguia atingir cerca de 4 FPS. Após algumas reflexões e cuidadosas refatorações, posso chegar a ~ 12fps se não me importo muito em fazer outra coisa!
Minha pergunta é: como um dispositivo como o GBA (Game Boy Advance) atingiu uma taxa de quadros de quase 60fps? Pensei em ter um 'processador gráfico' separado, mas percebi que ainda estaria com um gargalo ao transferir os dados da tela para isso.
Também me perguntei sobre o uso da interface paralela vestigial de 8 bits que a maioria dessas telas costuma ter, o que pode gerar uma velocidade de 8x, exceto que os MCUs modernos não tendem a ter interfaces paralelas de hardware, como fazem para serial e bit- bater provavelmente consumirá muito do ganho de velocidade.
Que outras opções existem?
Atualmente, estou usando um ATmega1284P conectado a um controlador OLED SSD1306 via USART-SPI. Essa é a versão monocromática.
A tela colorida era um SSD1351, não originalmente conectado ao hardware SPI. Eu não estava convencido de que isso faria diferença suficiente , é muito lento no geral
Sei que posso obter MCUs mais rápidos, mas quero saber que outras opções posso explorar - o processador GBA é muito mais lento que o meu 1284!
fonte
Respostas:
Outras respostas cobrem sua pergunta muito bem em um nível abstrato (hardware), mas, tendo uma experiência real com o GBA em particular, achei que uma explicação mais detalhada pode valer a pena.
O GBA tinha muitos modos e configurações de desenho que podiam ser usados para controlar como o processador gráfico interpretava a RAM de vídeo, mas uma coisa era inevitável: a taxa de quadros. O processador gráfico estava desenhando na tela em um loop constante quase (mais sobre isso abaixo). (Este é provavelmente o bit mais relevante para sua pergunta.)
Ele traçaria uma linha de cada vez, fazendo um intervalo muito curto entre cada uma. Depois de desenhar a última linha do quadro, uma pausa seria aproximadamente igual ao tempo necessário para desenhar 30 linhas. Então comece de novo. O tempo de cada linha e o tempo de cada quadro foram todos pré-determinados e gravados em pedra. De várias maneiras, o processador gráfico era realmente o mestre desse sistema e você precisava escrever seus jogos em torno do comportamento dele, porque continuaria fazendo o que fazia, estando você pronto ou não.
Aproximadamente 75-80% das vezes estava ativamente pressionando a tela. Quais taxas de quadros você poderia obter se estivesse fazendo o mesmo?
Também em 80% do tempo a CPU tinha que processar a entrada do usuário, calcular o estado do jogo e carregar sprites / tiles em áreas da VRAM que estavam fora da tela (ou pelo menos não incluídas na linha atual que está sendo desenhada).
Os 20% entre os quadros, era tudo o que a CPU precisava ajustar as configurações de vídeo ou RAM que impactariam todo o próximo quadro.
No final de cada linha, o processador gráfico envia uma interrupção de sincronização de linha para a CPU. Essa interrupção pode ser usada para ajustar as configurações em alguns sprites ou em algumas camadas de fundo (é assim que você pode obter um efeito como um refletor cônico, alterando o tamanho e a localização de uma das máscaras retangulares entre cada linha desenhada. No que diz respeito ao hardware, todas essas regiões são retangulares.). Você precisa ter cuidado para manter essas atualizações pequenas e concluir antes que o processador gráfico comece a desenhar a próxima linha ou obtenha resultados feios. Qualquer tempo gasto no processamento dessas interrupções também reduz os 80% do tempo de processamento da CPU ...
Para jogos que tiraram o máximo proveito deste sistema, nem a CPU nem o processador gráfico deram uma pausa real; cada um estava perseguindo o outro em volta do loop, atualizando o que o outro não estava vendo no momento.
fonte
O principal recurso de todos os consoles de jogos que os distinguiam dos PCs antigos e praticamente de todos os computadores domésticos (1) eram sprites de hardware .
O guia de programação GBA vinculado mostra como eles funcionam do ponto de vista do processador principal. Os bitmaps que representam jogador, plano de fundo, inimigos etc. são carregados em uma área da memória. Outra área de memória especifica a localização dos sprites. Portanto, em vez de ter que reescrever toda a RAM de vídeo em todos os quadros, o que requer muitas instruções, o processador precisa apenas atualizar a localização dos sprites.
O processador de vídeo pode trabalhar pixel por pixel para determinar qual sprite desenhar nesse ponto.
No entanto, isso requer RAM de porta dupla compartilhada entre os dois, e acho que no GBA o processador de vídeo está no mesmo chip que o ARM principal e o processador Z80 secundário.
(1) Exceção notável: Amiga
fonte
"Minha pergunta é: como um dispositivo como o GBA atingiu uma taxa de quadros de quase 60fps?"
Para responder apenas à pergunta, eles fizeram isso com um processador gráfico. Tenho certeza de que o Game Boy usou gráficos de sprite. Em um nível superior, isso significa que o processador gráfico carrega coisas como a imagem de um plano de fundo, uma imagem de Mario e uma imagem de Princess Peach, etc. Em seguida, o processador principal emite comandos como "mostrar o deslocamento de fundo dessa muito em x e y, sobreponha a imagem 3 do Mario nesta posição x, y "etc. etc. Portanto, o processador principal não se preocupa absolutamente positivamente com o desenho de cada pixel, e o processador gráfico não se preocupa positivamente em calcular o estado do jogos. Cada um é otimizado para o que precisa fazer, e o resultado é um bom jogo de vídeo sem usar muito poder de computação.
fonte
O GBA tinha um processador bastante lento. O ARM7 é muito bom; eles apenas correram devagar e deram quase nenhum recurso.
Há uma razão pela qual muitos jogos da Nintendo naquele momento e antes eram side-scrollers. HARDWARE. Tudo é feito em hardware. Você tinha várias camadas de blocos, mais um ou mais sprites, e o hardware fez todo o trabalho para extrair pixels dessas tabelas e direcionar a exibição.
Você constrói o bloco configurado na frente e, em seguida, tinha uma memória pequena que era um mapa de bloco. Deseja que o ladrilho inferior esquerdo seja o ladrilho 7? Você coloca um 7 nesse local da memória. Deseja que o próximo bloco seja o bloco 19? No conjunto de blocos, você coloca 19 lá e assim por diante para cada camada que você ativou. Para o sprite, basta definir o endereço x / y. Você também pode fazer a escala e a rotação definindo alguns registros e o hardware cuida do resto.
O modo 7, se bem me lembro, era um modo de pixel, mas era como uma placa de vídeo tradicional em que você coloca bytes que cobrem a cor de um pixel e o hardware cuida da atualização do vídeo. Eu acho que você pode jogar pingue-pongue ou, pelo menos, quando tiver um novo quadro, pode jogá-lo, mas não me lembro direito. Novamente, o processador estava com um clock insuficiente para aquele dia e idade e não tinha muitos recursos rápidos. Então, enquanto alguns jogos eram no modo 7, muitos eram side-scrollers baseados em blocos ...
Se você deseja uma solução com alta taxa de quadros, é necessário projetá-la. Você não pode simplesmente pegar qualquer tela antiga que encontrar e conversar com ela via SPI ou I²C ou algo assim. Coloque pelo menos um buffer de quadro na frente dele, idealmente dois, e tenha controle de linha e coluna, se possível, sobre essa exibição.
Alguns monitores que eu suspeito que você está comprando têm um controlador com o qual você está realmente conversando. Se você quiser um desempenho do tipo GBA / console, crie / implemente o controlador. Ou você compra / constrói com um chip de GPU / vídeo / blob lógico e usa HDMI ou outra interface comum em um monitor de estoque.
Só porque uma bicicleta tem pneus, uma corrente e engrenagens não significa que ela pode ir tão rápido quanto uma motocicleta. Você precisa projetar o sistema para atender às suas necessidades de desempenho, de ponta a ponta. Você pode colocar a roda da bicicleta naquela motocicleta, mas ela não funcionará como desejado; todos os componentes precisam fazer parte do design geral.
Asteróides também funcionavam dessa maneira; precisava apenas de um 6502. Os gráficos vetoriais foram feitos com lógica separada; o 6502 enviou uma minúscula seqüência de dados ao controlador de gráficos vetoriais, que usava uma ROM e esses dados para fazer a plotagem xy do feixe ez, ligar / desligar ... o processador que computa o jogo. Hoje, é claro, o vídeo é tratado por centenas, senão milhares, de processadores separados do processador principal ...
fonte
Hardware.
Possui memória gráfica, que pode ou não compartilhar o mesmo barramento que a memória de programa / dados ... mas o mais importante é que ele possui um processador gráfico que lê a memória 60 vezes por segundo e envia os dados para o LCD usando um interface otimizada, projetada para fazer isso com eficiência.
Você pode fazer o mesmo com qualquer microcontrolador moderno equipado com um periférico de "interface LCD", por exemplo, o LPC4330, embora isso possa ser um exagero. Claro que você precisará de um painel LCD compatível.
Com os modernos microcontroladores rápidos (por exemplo, ARM e AVR) e uma tela tão pequena, você provavelmente não precisará de sprites ou de um piscar de olhos para acelerar as operações gráficas. Com um AVR de 8 bits, pode ser lento.
Mas não importa o processador, bater com força na interface do monitor será uma droga.
Acredito que o Atari 2600 tenha usado o processador de bits para enviar a imagem para a TV. Isso é um pouco obsoleto.
fonte