
Senior Developer
Interesses: Ciência cognitiva, teoria da computação, desenvolvimento de linguagens, desenvolvimento de jogos, programação bare-metal, IA local e deploy
Co-fundador da Common Lisp Brasil
lisp.com.br
luksamuk https://luksamuk.codes/ luksamuk
Figura: Ken Kutaragi e o Sony PlayStation
Consoles de 32-bits, CD-ROM como mídia, polígonos na tela.
Exceto o Nintendo 64 (cartucho).
Sonic R (Sega Saturn), Crash Bandicoot (Sony PlayStation) e The Legend of Zelda: Ocarina of Time (Nintendo 64).
Figura: Dashboard da extensão PSX.Dev para VSCode.
armips)Nota: Psy-Q era o único SDK licenciado pela Sony. SDKs alternativos podem causar problemas de compatibilidade em emuladores antigos (ex: caso Sonic XA).
Vamos ao vivo:
main.c, Makefile, third_party/nuggetmake – GCC-MIPSEL + Psy-Q convertido
Figura: Placa-mãe de um PlayStation modelo SCPH-1000.
AO LADO: Dieshot do CXD8530Q (primeira revisão), tirado da apresentação do Ken Kutaragi na Hot Chips '99.
Fonte: PlayStation Dev Wiki
A especificação das CPUs MIPS 32-bit possuía um co-processador Cop1 para float, e um D-Cache para acesso à RAM.
O PlayStation 1 não possui nenhum dos dois.
Solução: fixed-points e scratchpad.
Jogo: Spider-Man (PSX). Tente notar os artefatos (polygon jittering, z-fighting, t-junctions…).
float em C é emulado em software (lento demais)Operações básicas (formato 20.12):
// Soma e subtração: direto
int32_t a = 2048; // 0.5
int32_t b = 1024; // 0.25
int32_t c = a + b; // 3072 = 0.75
// Multiplicação: precisa compensar os bits fracionários
int32_t d = (a * b) >> 12; // 0.125
// Divisão: precisa pré-multiplicar
int32_t e = (a << 12) / b; // 2.0
Exemplo real (extraído do Sonic XA): a câmera trabalha em fixed-point, mas na
hora de desenhar, converte para pixels inteiros com >> 12:
// camera.c -- posição em 20.12, conversão para pixels
anchorx -= (camera->pos.vx >> 12) - CENTERX;
// util.c -- divisão em fixed-point
int32_t div12(int32_t a, int32_t b) {
return ((a << 12) / b) & ~(uint32_t)0xfff;
}
Razão pela qual o PSX consegue colocar polígonos na tela.
O GTE opera com instruções específicas para operações 3D. O fluxo típico para um triângulo é:
gte_ldv0, gte_ldv1, gte_ldv2)gte_rtpt)gte_nclip)gte_stsxy3)gte_avsz3, gte_stotz)
Ver ao vivo: função RotAverageNclip3 em util.c no repositório do Sonic XA.

Fonte: PlayStation Hardware Reference
Esfera low-poly com reflexão especular.
Banjo, personagem de Banjo-Kazooie, como visto no Nintendo 64.
A GPU do PSX é um rasterizador 2D. Ela não sabe qual pixel está à frente de qual. Não existe Z-buffer. Então, como desenhar polígonos na ordem certa?
A solução é a ordering table (OT): um array de linked lists indexado por
profundidade. Cada posição do array representa uma "fatia" de Z. O GTE
calcula o Z médio de cada triângulo (gte_stotz), e o triângulo é inserido na
posição correspondente da OT.
// Inserir primitiva na OT na posição calculada pelo GTE
addPrim(ot[otz], poly);
// Desenhar tudo, de trás (longe) para frente (perto)
DrawOTag(ot + OT_LENGTH - 1);
Figura: Detalhe do Psy-Q SDK.
Demo ao vivo: projeto gouraud-shading – cubo gouraud-shaded em C.
| Limitação | Workaround |
|---|---|
| Sem FPU (float em software) | Fixed-point 20.12 (4096 = 1.0) |
| Sem Z-buffer na GPU | Ordering table (linked lists por profundidade) |
| 2 MB de RAM | Scratchpad de 1 KB como "cache manual" |
| 1 MB de VRAM | Texturas, CLUTs e double buffer competem pelo mesmo espaço |
| CD-ROM (~300ms de seek) | Pre-load e streaming de dados |
| Sem perspectiva correction | Polygon jittering (artefatos visíveis) |
engine-psx)
Fan-game de Sonic The Hedgehog utilizando técnicas do hardware do PSX.
Acesse esta apresentação:
https://luksamuk.codes/talks/psx-programming-tech.html
lucasvieira at protonmail dot com luksamuk https://luksamuk.codes/ luksamuk