perf(vram): KTX2 nas armas (259 → 32 MB) + régua que mede o relógio do jogador - #417
perf(vram): KTX2 nas armas (259 → 32 MB) + régua que mede o relógio do jogador#417rubenmarcus wants to merge 13 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
csbrasil-bot classificationNote @rubenmarcus abriu 54 arquivo(s) · +1272 −41, base main. O que mudou
Labels
|
estraga-codigo
left a comment
There was a problem hiding this comment.
Palhaço Mal · revisor da casa · 🤡
mapa da mudança
- assets (71):
adjim.glb,ancap.glb,blackmetal.glb,bombado.glb… - docs (11):
ARCH.generated.md,README.md,STATUS.md,arquitetura.md… - outros (6):
basis_transcoder.js,basis_transcoder.wasm,ktx-parse.module.js,zstddec.module.js… - jogo (5):
fparms.js,glbchars.js,ktx2.js,main.js… - arnês (3):
ARCH.md,mat_shade.py,optimize-ktx2.mjs
Tip
Risco BAIXO · nota 10/10 ▓▓▓▓▓▓▓▓▓▓
pente fino passado: nenhum achado que eu defenda em voz alta
Revisão de bot — fio não resolvido TRAVA o merge (a main exige conversa resolvida). Resolve ou refuta.
impacto cruzado
graph RL
game_js["game.js"] --> fparms_js["fparms.js"]
main_js["main.js"] --> fparms_js["fparms.js"]
fparms_js["fparms.js"] --> glbchars_js["glbchars.js"]
game_js["game.js"] --> glbchars_js["glbchars.js"]
loading3d_js["loading3d.js"] --> glbchars_js["glbchars.js"]
fparms_js["fparms.js"] --> weapons_js["weapons.js"]
game_js["game.js"] --> weapons_js["weapons.js"]
glbchars_js["glbchars.js"] --> weapons_js["weapons.js"]
(grafo local de public/js, uma rodada atrás do head do PR.)
— todo bug confessa no diff, eu só faço o interrogatório 🤡
MEDIDO: 9,9 MB de WebP em disco viravam ~703 MB de VRAM (RGBA8 + mipmaps) — a textura só é pequena no arquivo. Com KTX2/ETC1S ela chega COMPRIMIDA na GPU e fica em ~87 MB. O PREÇO, medido e não escondido: disco sobe 31,5 -> 38,3 MB (+6,8) e o transcoder pesa 488 KB de wasm no boot. Ou seja, ~+7,3 MB de download por visita fria em troca de -616 MB de VRAM. Numa base onde 98% das sessões roda abaixo de 30 FPS, a troca compensa — mas é troca, não almoço grátis, e a decisão de mergear é do dono. QUALIDADE, com a régua da casa (eval:mat, cor da arma na mão contra a do chão, 12 mapas × 26 armas): praça 4,54 -> 4,53 · piscina -0,92 -> -0,95 · loja_h 0,95 -> 0,95. A cor NÃO se move. Perda do encoder por pixel: erro médio 3,1-4,6 de 255 (1,2-1,8%). Pré-requisitos que só apareceram rodando: - o KTX2Loader precisa de WorkerPool.js, ktx-parse e zstddec, além do transcoder — sem os três o jogo nem sobe (o main.js para de avaliar e o menu fica morto); - o loader precisa do RENDERER para saber o formato que a GPU aceita, e os módulos avaliam ANTES do main.js — daí o ktx2.js guardar a instância e aplicá-la NA CARGA, não na montagem; - o mat_shade.py lia textura assumindo EXT_texture_webp e quebrou; agora desempacota KTX2 com o basisu. ATENÇÃO: o basisu escreve um PNG por nível de mipmap E um do canal ALFA — pegar o primeiro da ordem alfabética compara alfa com cor e inventa ΔL* de 7 (aconteceu aqui). Conferido no navegador: arma e personagem chegam como CompressedTexture com 10 mipmaps, jogo vivo, zero erro fora dos 404 conhecidos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Commit-grande: transcoder KTX2 vendorizado (wasm de 488 KB) + loader e dependências, um arquivo por peça Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com> Agent: Claude Code
Rodado `node tools/optimize-ktx2.mjs` nas duas pastas. armas: disco 9,2 -> 11,5 MB · VRAM 259 -> 32 MB personagens: disco 22,3 -> 26,8 MB · VRAM 444 -> 55 MB Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Commit-grande: 71 GLBs reescritos pelo optimize-ktx2 — binário, um por personagem/arma Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com> Agent: Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com> Agent: Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com> Agent: Claude Code
fb21ee6 to
048ba5e
Compare
|
Rebaseado direto sobre a O que mudou aqui: saíram os commits de animação e o decodificador meshopt. Ficou só o KTX2, que é independente — ele mexe em textura, não em clipe. Os 570 clipes voltaram ao original ( Portão 58/58, e os números do KTX2 seguem os mesmos: VRAM 703 → 87 MB, disco +6,8 MB, transcoder +488 KB, e a régua de cor da casa sem movimento. |
estraga-codigo
left a comment
There was a problem hiding this comment.
Palhaço Mal · revisor da casa · 🤡
mapa da mudança
- assets (71):
adjim.glb,ancap.glb,blackmetal.glb,bombado.glb… - docs (11):
ARCH.generated.md,README.md,STATUS.md,arquitetura.md… - outros (6):
basis_transcoder.js,basis_transcoder.wasm,ktx-parse.module.js,zstddec.module.js… - jogo (5):
fparms.js,glbchars.js,ktx2.js,main.js… - arnês (3):
ARCH.md,mat_shade.py,optimize-ktx2.mjs
Tip
Risco BAIXO · nota 10/10 ▓▓▓▓▓▓▓▓▓▓
limpo pelos critérios das minhas ações desta rodada
Revisão de bot — fio não resolvido TRAVA o merge (a main exige conversa resolvida). Resolve ou refuta.
impacto cruzado
graph RL
game_js["game.js"] --> fparms_js["fparms.js"]
main_js["main.js"] --> fparms_js["fparms.js"]
fparms_js["fparms.js"] --> glbchars_js["glbchars.js"]
game_js["game.js"] --> glbchars_js["glbchars.js"]
loading3d_js["loading3d.js"] --> glbchars_js["glbchars.js"]
fparms_js["fparms.js"] --> weapons_js["weapons.js"]
game_js["game.js"] --> weapons_js["weapons.js"]
glbchars_js["glbchars.js"] --> weapons_js["weapons.js"]
(grafo local de public/js, uma rodada atrás do head do PR.)
— maquiagem de verde por cima de vermelho eu desenmascaro no primeiro golpe de vista 🤡
Medido na tela de personagens: 10× mais thread travada, e o elenco não aparece
Medi as duas árvores no mesmo ambiente (build de produção servido estático, Chrome headless, mesmo viewport, mesma janela de 12 s depois de abrir a tela). O contador é
A linha que decide é a quarta: em 12 segundos a tela de personagens do #417 não mostrou nenhum item, contra os 8 da main. Não é "um pouco mais lento" — é a tela não funcionando. Por quêAs texturas KTX2 vêm embutidas nos GLB, e Basis exige transcodificação na CPU a cada carga. A tela de personagens carrega o elenco inteiro de uma vez, então ela paga o custo de todas as texturas junto, na thread principal. A troca é real: VRAM 703 → 87 MB, mas o preço é tempo de CPU exatamente onde o jogador está olhando. Vale registrar que O que eu fariaO dono já disse que assim não ajuda o jogo, e o número concorda. Duas saídas:
Em qualquer um dos dois: a régua deste PR mede VRAM e não mede o que quebrou. É o mesmo padrão do #413, onde a AD2 media desvio angular e o que quebrou foi contato de pé — grandeza vizinha. Se o KTX2 voltar, a régua que o guarda tem de ser "tempo até o elenco estar na tela", que é o que o jogador sente. (Medição reproduzível: 🤖 Generated with Claude Code |
|
🤖 autofix: o conserto encostou em arquivo fora da lista de permissão, então não commitei nada. Rode |
Nasce de duas reprovações minhas. O #413 media desvio angular quando o que quebrou era contato de pé; o #417 media VRAM quando o que quebrou era tempo de tela. VRAM e bytes são baratos de medir e por isso sedutores; o que o jogador sente é o relógio. TETO COM PROCEDÊNCIA — a lição que faltou nas duas: a medição varia sozinha ±8% (4 corridas na main: 6083, 6607, 6854, 7086 ms). O teto de 9300 ms é ~1,4× a mediana, cinco vezes o ruído observado e bem abaixo dos 12557 ms que o KTX2 no elenco produziu. Passa ruído, morde regressão. Mutante `lento` estrangula a CPU em 4× e acende a cláusula (10.449 ms). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com> Agent: Claude Code
Medido: primeira linha do elenco em 12.557 ms com KTX2 contra 6.854 ms na main (1,8x). A tela de personagens carrega o elenco inteiro de uma vez e Basis transcodifica na CPU, então o custo cai na thread principal exatamente onde o jogador está olhando. As armas seguem em KTX2, onde a medição não regride. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Commit-grande: 45 GLBs de personagem revertidos ao WebP — binário, um por personagem Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com> Agent: Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com> Agent: Claude Code
Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com> Agent: Claude Code # Conflicts: # ARCH.generated.md # README.md # STATUS.md # docs/docs/comecando.md # docs/docs/quality-gates.md # docs/i18n/en/docusaurus-plugin-content-docs/current/comecando.md # docs/i18n/en/docusaurus-plugin-content-docs/current/quality-gates.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: rubenmarcus <rubenmarcus.dev@gmail.com> Agent: Claude Code
Você tinha razão, e eu confirmei com medição própriaMedi as duas árvores no mesmo ambiente (
Personagens voltaram ao WebP. A tela de personagens carrega o elenco inteiro de uma vez e o Basis transcodifica na CPU, então o custo cai na thread principal exatamente onde o jogador está olhando. O que sobrou, medidoAs armas ficam em KTX2, e as duas telas não regridem:
A régua que faltavaDuas vezes seguidas uma régua minha aprovou o que você reprovou jogando, e pelo mesmo motivo: media a grandeza vizinha.
VRAM e bytes são baratos de medir, e por isso sedutores. O que o jogador sente é o relógio. A TELA1 mede o tempo até a primeira linha do elenco aparecer, e roda no portão de navegador. O teto tem procedência — a lição que faltou nas duas vezes: a medição varia sozinha ±8% (4 corridas na main: 6083, 6607, 6854, 7086 ms). O teto de 9.300 ms é ~1,4× a mediana: cinco vezes o ruído observado, e bem abaixo dos 12.557 ms que o KTX2 no elenco produziu. Passa ruído, morde regressão — e teria pego esta. Mutante Portão 62/62. Crédito à sessão |
|
🤖 autofix: dá para consertar sozinho, mas este PR está com allow edits by maintainers desligado. Rode |
estraga-codigo
left a comment
There was a problem hiding this comment.
Palhaço Mal · revisor da casa · 🤡
mapa da mudança
- assets (26):
ak.glb,akm.glb,awp.glb,carbine.glb… - docs (11):
ARCH.generated.md,README.md,STATUS.md,arquitetura.md… - outros (7):
package.json,basis_transcoder.js,basis_transcoder.wasm,ktx-parse.module.js… - jogo (5):
fparms.js,glbchars.js,ktx2.js,main.js… - arnês (4):
ARCH.md,mat_shade.py,tela-check.mjs,optimize-ktx2.mjs - CI (1):
portao-browser.yml
Tip
Risco BAIXO · nota 10/10 ▓▓▓▓▓▓▓▓▓▓
nada aqui que quebre amanhã. amanhã é outro diff
Revisão de bot — fio não resolvido TRAVA o merge (a main exige conversa resolvida). Resolve ou refuta.
impacto cruzado
graph RL
game_js["game.js"] --> fparms_js["fparms.js"]
main_js["main.js"] --> fparms_js["fparms.js"]
fparms_js["fparms.js"] --> glbchars_js["glbchars.js"]
game_js["game.js"] --> glbchars_js["glbchars.js"]
loading3d_js["loading3d.js"] --> glbchars_js["glbchars.js"]
fparms_js["fparms.js"] --> weapons_js["weapons.js"]
game_js["game.js"] --> weapons_js["weapons.js"]
glbchars_js["glbchars.js"] --> weapons_js["weapons.js"]
(grafo local de public/js, uma rodada atrás do head do PR.)
— todo bug confessa no diff, eu só faço o interrogatório 🤡
|
Esbirro · plantão da produção · 🕵️ check vermelho parado neste PRCaution Não sei classificar este vermelho. Segue o que o CI cuspiu — palpite de bot sobre bug alheio só atrapalha.
Vermelho: Rabo do log: — nada fora do normal no meu turno 🕵️ |
|
🤖 autofix: dá para consertar sozinho, mas este PR está com allow edits by maintainers desligado. Rode |
|
🤖 autofix: dá para consertar sozinho, mas este PR está com allow edits by maintainers desligado. Rode |
|
🤖 autofix: dá para consertar sozinho, mas este PR está com allow edits by maintainers desligado. Rode |
1 similar comment
|
🤖 autofix: dá para consertar sozinho, mas este PR está com allow edits by maintainers desligado. Rode |
Agent: csbrasil-bot (autofix) Signed-off-by: csbrasil-bot <csbrasil-bot@users.noreply.github.com>
Rodado pelo autofix: só arquivo gerado, conferido pela lista de permissão. Signed-off-by: csbrasil-bot <csbrasil-bot@users.noreply.github.com>
|
🤖 autofix: regenerei os blocos derivados e empurrei o commit. O PR não precisa de mais nada disso. |
Agent: csbrasil-bot (autofix) Signed-off-by: csbrasil-bot <csbrasil-bot@users.noreply.github.com>
|
🤖 autofix: regenerei os blocos derivados e empurrei o commit. O PR não precisa de mais nada disso. |
|
Esbirro · plantão da produção · 🕵️ check vermelho parado neste PRWarning Classe régua velha: o check reprova num contrato que este PR muda de propósito. A régua codificou o contrato antigo — o PR não está "errado". Atualizar a régua é decisão humana, o vigia não mexe.
Vermelho: Rabo do log: — nada fora do normal no meu turno 🕵️ |
|
🤖 autofix: regenerei os blocos derivados e empurrei o commit. O PR não precisa de mais nada disso. |
estraga-codigo
left a comment
There was a problem hiding this comment.
Palhaço Mal · revisor da casa · 🤡
mapa da mudança
- assets (26):
ak.glb,akm.glb,awp.glb,carbine.glb… - docs (11):
ARCH.generated.md,README.md,STATUS.md,arquitetura.md… - outros (7):
package.json,basis_transcoder.js,basis_transcoder.wasm,ktx-parse.module.js… - jogo (5):
fparms.js,glbchars.js,ktx2.js,main.js… - arnês (4):
ARCH.md,mat_shade.py,tela-check.mjs,optimize-ktx2.mjs - CI (1):
portao-browser.yml
Tip
Risco BAIXO · nota 10/10 ▓▓▓▓▓▓▓▓▓▓
limpo pelos critérios das minhas ações desta rodada
Revisão de bot — fio não resolvido TRAVA o merge (a main exige conversa resolvida). Resolve ou refuta.
impacto cruzado
graph RL
game_js["game.js"] --> fparms_js["fparms.js"]
main_js["main.js"] --> fparms_js["fparms.js"]
fparms_js["fparms.js"] --> glbchars_js["glbchars.js"]
game_js["game.js"] --> glbchars_js["glbchars.js"]
loading3d_js["loading3d.js"] --> glbchars_js["glbchars.js"]
fparms_js["fparms.js"] --> weapons_js["weapons.js"]
game_js["game.js"] --> weapons_js["weapons.js"]
glbchars_js["glbchars.js"] --> weapons_js["weapons.js"]
(grafo local de public/js, uma rodada atrás do head do PR.)
— todo bug confessa no diff, eu só faço o interrogatório 🤡
Agent: csbrasil-bot (autofix) Signed-off-by: csbrasil-bot <csbrasil-bot@users.noreply.github.com>
|
🤖 autofix: regenerei os blocos derivados e empurrei o commit. O PR não precisa de mais nada disso. |
|
🤖 autofix: regenerei os blocos derivados e empurrei o commit. O PR não precisa de mais nada disso. |
estraga-codigo
left a comment
There was a problem hiding this comment.
Palhaço Mal · revisor da casa · 🤡
mapa da mudança
- assets (26):
ak.glb,akm.glb,awp.glb,carbine.glb… - docs (11):
ARCH.generated.md,README.md,STATUS.md,arquitetura.md… - outros (7):
package.json,basis_transcoder.js,basis_transcoder.wasm,ktx-parse.module.js… - jogo (5):
fparms.js,glbchars.js,ktx2.js,main.js… - arnês (4):
ARCH.md,mat_shade.py,tela-check.mjs,optimize-ktx2.mjs - CI (1):
portao-browser.yml
Tip
Risco BAIXO · nota 10/10 ▓▓▓▓▓▓▓▓▓▓
pente fino passado: nenhum achado que eu defenda em voz alta
Revisão de bot — fio não resolvido TRAVA o merge (a main exige conversa resolvida). Resolve ou refuta.
impacto cruzado
graph RL
game_js["game.js"] --> fparms_js["fparms.js"]
main_js["main.js"] --> fparms_js["fparms.js"]
fparms_js["fparms.js"] --> glbchars_js["glbchars.js"]
game_js["game.js"] --> glbchars_js["glbchars.js"]
loading3d_js["loading3d.js"] --> glbchars_js["glbchars.js"]
fparms_js["fparms.js"] --> weapons_js["weapons.js"]
game_js["game.js"] --> weapons_js["weapons.js"]
glbchars_js["glbchars.js"] --> weapons_js["weapons.js"]
(grafo local de public/js, uma rodada atrás do head do PR.)
— todo bug confessa no diff, eu só faço o interrogatório 🤡
|
🤖 autofix: a base andou e o conflito encostou em arquivo de código — não é meu para resolver. Os arquivos em conflito estão no log do run; rode |
|
Esbirro · plantão da produção · 🕵️ check vermelho parado neste PRCaution Não sei classificar este vermelho. Segue o que o CI cuspiu — palpite de bot sobre bug alheio só atrapalha.
Vermelho: Rabo do log: — nada fora do normal no meu turno 🕵️ |
|
🤖 autofix: a base andou e o conflito encostou em arquivo de código — não é meu para resolver. Os arquivos em conflito estão no log do run; rode |
5 similar comments
|
🤖 autofix: a base andou e o conflito encostou em arquivo de código — não é meu para resolver. Os arquivos em conflito estão no log do run; rode |
|
🤖 autofix: a base andou e o conflito encostou em arquivo de código — não é meu para resolver. Os arquivos em conflito estão no log do run; rode |
|
🤖 autofix: a base andou e o conflito encostou em arquivo de código — não é meu para resolver. Os arquivos em conflito estão no log do run; rode |
|
🤖 autofix: a base andou e o conflito encostou em arquivo de código — não é meu para resolver. Os arquivos em conflito estão no log do run; rode |
|
🤖 autofix: a base andou e o conflito encostou em arquivo de código — não é meu para resolver. Os arquivos em conflito estão no log do run; rode |
Summary
KTX2Loader+ transcoder vendorizados, no mesmo padrão dothree.module.js;optimize-ktx2.mjsconverte as 211 texturas de personagem e arma.O ganho, e o preço — os dois medidos
Ou seja: ~+7,3 MB de download por visita fria em troca de -616 MB de VRAM. Numa base onde 98% das sessões roda abaixo de 30 FPS, a troca compensa — mas é troca, não almoço grátis. A decisão de mergear é sua.
Qualidade, com a régua da casa
eval:mat(cor da arma na mão contra a do chão, 12 mapas × 26 armas):A cor não se move. Perda do encoder por pixel: erro médio 3,1–4,6 de 255 (1,2–1,8%).
Três coisas que só apareceram rodando
KTX2Loadertem três dependências além do transcoder (WorkerPool.js,ktx-parse,zstddec). Sem elas omain.jspara de avaliar e o menu fica morto — o jogo nem sobe.main.js. Por isso oktx2.jsguarda a instância e a aplica na carga, não na montagem.mat_shade.pyquebrou (lia textura assumindoEXT_texture_webp). Consertado combasisu -unpack— e cuidado: o basisu escreve um PNG por nível de mipmap e um do canal alfa; pegar o primeiro da ordem alfabética compara alfa com cor e inventa ΔL* de 7. Aconteceu aqui e me fez achar, por meia hora, que o KTX2 tinha destruído a cor.Validation
check:fast58/58CompressedTexturecom 10 mipmaps, jogo vivoeval:matsem movimento de corRisk