SDL agora oferece suporte a DOS
(github.com/libsdl-org)- Foi adicionado ao SDL um port para DOS baseado em DJGPP, e ele foi mesclado ao
mainjá com um conjunto amplo de recursos, incluindo vídeo, áudio, entrada, threading, temporizadores, sistema de arquivos e cadeia de build - Foram implementados recursos voltados ao ambiente DOS, como vídeo VGA e VESA 1.2+, reprodução de áudio da família Sound Blaster, teclado e mouse PS/2, joystick baseado em BIOS, threading cooperativo e temporizador PIT
- Os problemas de seek/read do DJGPP foram contornados despejando e restaurando o buffer ao fazer seek, eliminando leituras incorretas e atrasos de vários segundos em
SDL_LoadWAV; o caminho de áudio também foi refinado para reduzir reentrada de IRQ e stutter - A tela preta em fullscreen estava ligada à seleção do modo INDEX8; em vez de manter uma hint específica para DOS, o ajuste seguiu para uma ordenação lógica dos modos, e um commit adicional também corrigiu o problema de transparência do cursor
- Os testes em hardware real foram limitados, e ainda faltam alguns recursos, como gravação de áudio,
SDL_LoadObjecte uma implementação específica de DOS paraSDL_TIME, mas o merge foi concluído após passar em 46 checks e foi classificado como recurso da versão 3.6.0
Escopo do suporte à plataforma DOS
- Foi adicionado ao SDL um port para DOS, que alcançou um nível relativamente maduro com base em DJGPP
- O trabalho foi dividido entre várias pessoas, e na etapa final foram acrescentadas correções de estabilidade e complementos para recursos faltantes
- O DevilutionX foi extensivamente testado no DOSBox, mas não houve testes em hardware real
- Alguns recursos também foram deliberadamente deixados de fora por falta de uma forma adequada de testá-los
- Os recursos suportados estão descritos de forma detalhada
- O vídeo inclui framebuffer VGA e VESA 1.2+, cores RGB e indexadas em 8 bits, programação da paleta VGA DAC, vsync e page flipping por hardware, além de salvamento e restauração do estado VBE ao sair
- O áudio oferece suporte a Sound Blaster 16, Sound Blaster Pro e Sound Blaster 2.0/1.x, usando DMA baseada em IRQ e caminho auto-init com buffer duplo
- A entrada inclui teclado PS/2 com scancodes estendidos, mouse via INT 33h e joystick de gameport baseado em BIOS INT 15h
- O threading usa um escalonador cooperativo com
setjmp/longjmpe patching de stack, além dos fallbacks genéricos para mutex, semaphore, TLS e condition variable - O pump de eventos e a função de delay incluem pontos de yield para manter a responsividade do áudio e de outras threads
- Os temporizadores usam uma implementação baseada em PIT com
uclock()do DJGPP, com resolução de cerca de 1,19 MHz - O sistema de arquivos trata
GetBasePatheGetPrefPathcomsearchpath()do DJGPP e também inclui fallback para operações de sistema de arquivos POSIX - O build inclui arquivo de toolchain para cross-compilation com CMake, job de CI para DJGPP e cache preseed para configuração mais rápida
- Também foi deixado claro o que não está incluído
- Gravação de áudio não está presente; apenas reprodução é suportada
- Não há implementação nativa de
SDL_TIME; é reutilizado ogettimeofdayUnix por meio da camada POSIX do DJGPP - Carregamento de bibliotecas compartilhadas não é suportado, portanto não há
SDL_LoadObject
Processo de implementação e mudanças principais
- O port para DOS foi evoluindo ao longo de vários commits, com adição gradual de vídeo, áudio, entrada, temporizadores, threading e cadeia de build
- Depois do trabalho inicial, foram sendo complementados em sequência o buffering de stdio, implementação de áudio, subsistema de vídeo, sistema de arquivos, mouse, teclado, CI e detecção de plataforma
- Em stdio e acesso a arquivos, foi contornado um problema característico de seek/read do DJGPP
- Houve uma tentativa de desativar o buffer dos SDL_IOStreams de stdio, mas depois isso foi substituído por um método de despejar e restaurar o buffer ao fazer seek
- Essa mudança é muito mais rápida do que desativar completamente o buffer, e também evita leituras incorretas após
fseek - Com isso,
SDL_LoadWAVdeixou de levar vários segundos para lertest/sample.wave passou a retornar os dados corretos
- O processamento de áudio também foi ajustado repetidamente com foco em estabilidade
- A implementação começou com Sound Blaster 16, e depois ganhou suporte a mono 8 bits pré-SB16 e estéreo SB Pro
- A mixagem de áudio saiu de uma execução direta no handler de IRQ para o loop principal e depois voltou para a thread de áudio do SDL
- A direção foi alterada para evitar problemas de reentrada dentro da IRQ, e durante carregamento a metade antiga do buffer DMA passou a ser preenchida com silêncio para reduzir stutter
- Também foram organizados os ajustes de sample rate, polling do estado do DSP, justificativa para alocação de memória DMA e remoção do wrapper de IRET após restaurar o vetor de interrupção
- O vídeo também teve recursos ampliados para atender às limitações do ambiente DOS
- Foi adicionada uma implementação inicial baseada na interface VESA funcionando com o renderizador de software
- Depois vieram suporte a paleta de 8 bits, page flipping VBE, restauração de estado, vsync em modo single-buffer e modo framebuffer VESA banked
- Em VBE 1.2+ sem LFB, a cópia para o framebuffer é feita via bank switching, e nesse modo o page flipping é desativado
- O estado completo do VBE é salvo e restaurado na inicialização e no encerramento do vídeo para que a troca de modo seja limpa
- O tratamento de entrada e interrupções também foi refinado até um nível utilizável na prática
- O teclado lida com scancodes estendidos e até com a tecla Pause, usando um ring buffer simples para armazenar eventos
- O mouse usa a function
0x1Bda INT 33h para consultar e usar a sensibilidade - No joystick, o polling dos eixos foi limitado a cerca de 60 Hz para reduzir o custo do loop de temporização da BIOS, enquanto os botões seguem em polling direto para manter a responsividade
- Código e dados de ISR são travados na memória para evitar page faults durante interrupções
- Problemas de build e detecção de plataforma também foram corrigidos
- Foi adicionado um job de CI para DJGPP, além da detecção de plataforma DOS no CMake
SDL_PLATFORM_DOSfoi incluído na lista de exclusão deSDL_RunApp()para evitar conflito com o launcher específico de DOS- Como o DJGPP define
__unix__, mas o DOS não tem GTK nem display server,SDL_Gtk_Quit()foi excluído no DOS para evitar erro de linkedição - Também foi considerado o fato de alguns toolchains DJGPP usarem o prefixo
i386-pc-msdosdjgpp-gcc
Estado dos testes e limitações restantes
- Os testes automatizados não terminaram todos de forma totalmente suave, mas chegaram a um ponto em que era possível concluir com patches
- Alguns problemas em funções padrão de formatação impediram que os testes automatizados fossem até o fim, e isso foi contornado com patches para permitir a execução
- Ainda restavam casos com falha, mas eles não foram incluídos porque não havia confiança sobre qual seria a correção correta dessas funções de formatação
- No geral, foi resumido que a maioria dos demos funciona em um nível razoavelmente esperado
- Também foram adicionados resultados de uso real
- No DOSBox e em DOS 6.22 em uma placa Vortex86, a janela não fullscreen funcionou bem tanto nos programas de teste quanto no código de usuário
- Já o fullscreen, naquele momento, exibia uma tela preta vazia em exemplos como
draw.exe --fullscreen - O desempenho foi descrito como lento, mas utilizável
- Alguns problemas em programas de teste também foram identificados
sprite.exeencerra imediatamente no DOSBoxwm.exeedraw.exenão renderizam, mas encerram ao pressionar ESCtestpalettegera segfault
Problema de seleção de profundidade de cor em fullscreen e ajuste
- A causa direta da tela preta em fullscreen era o comportamento em que
SDL_GetClosestFullscreenDisplayMode()caía em um modo INDEX8- Se a aplicação não consegue lidar com renderização INDEX8, a tela fica preta
- Na implementação interna, o INDEX8 passou a ser considerado apenas quando o usuário já tiver configurado explicitamente um modo fullscreen INDEX8
- Inicialmente, foi adicionada uma solução para DOS que escondia modos INDEX8 atrás de
SDL_HINT_DOS_ALLOW_INDEX8_MODES- A ideia era exigir opt-in explícito apenas quando a aplicação pudesse lidar corretamente com eles
- Porém, na branch principal já havia entrado uma mudança para escolher a maior profundidade de bits em vez da menor, e seguiu-se um fluxo para verificar se isso resolveria o problema
- Essa mudança resolveu a questão do bpp, mas criou outro problema: uma solicitação de best fit para 640x480 acabava escolhendo 1024x768
- No fim, essa alteração foi revertida, e a direção ficou em tratar uma correção melhor em um PR separado
- No resultado final, a hint específica de DOS foi removida e substituída por uma ordenação lógica dos modos
- Foi adicionado o commit
Remove SDL_HINT_DOS_ALLOW_INDEX8_MODES and order modes logically - Quando #15442 for mesclado, também deve passar a funcionar corretamente a seleção automática de modo para apps que não definem paleta nem escolhem diretamente o modo fullscreen
- Também ficou claro que a intenção não era continuar expandindo indefinidamente esse PR para cobrir outros problemas antigos do SDL
- Foi adicionado o commit
Renderização dos demos e correção do cursor
- O problema de demos aparecendo em preto não dependia apenas deste PR, mas também do estado de merge de #15442
- Enquanto
SDL_GetClosestFullscreenDisplayMode()continuar preferindo a menor profundidade de cor, este port escolhe INDEX8, e se o app não definir a paleta a tela fica preta - Foi confirmado que, ao mesclar esse PR localmente, todos os casos testados passaram a funcionar
- Enquanto
- O problema visual restante era a transparência do cursor
- Após verificação local, descobriu-se adicionalmente que apenas o cursor não estava transparente
- Para corrigir isso, foi adicionado o commit
Don't convert cursor if dest is not INDEX8 - Depois da correção, em modo RGB passa-se a usar uma versão não otimizada, mas o comportamento fica correto tanto em RGB quanto em INDEX8
- Ainda existe margem para desempenho um pouco melhor em XRGB1555 e RGB565, mas isso foi tratado como baixa prioridade
Revisão e decisão de merge
- Foi considerado que o PR era adequado para squash merge
- Como o GitHub mantém a referência ao PR no commit resultante, entendeu-se que o histórico do trabalho continuaria rastreável
- Também foi sugerido adicionar créditos extras no commit final
- O texto incluía formulações concretas para acrescentar dois
Co-authored-bye umTested-by
- O revisor comentou que, após o merge, ainda reescreveria algumas expressões dos scripts de build de forma mais limpa
- Pouco antes do merge final, a direção foi consolidada como mesclar também outros PRs relacionados e então seguir com o PR de DOS
- Após “Last call on DOS pull request!”, foi confirmado o estado de merge dos PRs relacionados
- Em seguida, ele foi mesclado ao
maincom 46 checks passed
- Depois do merge, o escopo de release também foi claramente definido
- Essa mudança é tratada como recurso da versão 3.6.0
-
Não será feito cherry-pick para a 3.4.x
- No dia seguinte ao merge, a branch de trabalho do DOS foi removida
Tarefas futuras e problemas de hardware restantes
- Também foi levantado um problema em que a implementação de
4f07(SetDisplayStart)de algumas GPUs Nvidia não funciona corretamente- Foi incluído um link para a thread no VOGONS, com a observação de que algumas GPUs aparecem como suportadas nos relatórios, mas na prática não funcionam
- Foi mencionado que a faixa de testes pode ser mais ampla, de GeForce 9300 até 3060, mas isso não representa uma cobertura completa, e sim o conjunto de hardware disponível
- O mesmo problema de exibição também foi observado nos testes do projeto
- Não foi considerado desejável que o SDL desative recursos com base no fabricante da GPU, e por isso também foi levantada a possibilidade de uma hint de controle pelo usuário
- Surgiu a ideia de que uma nova hint para controlar
page_flip_availablediretamente pelo usuário poderia ser melhor - O tema foi encerrado com a perspectiva de que isso poderia ser adicionado depois, sem tratamento imediato
- Surgiu a ideia de que uma nova hint para controlar
- Após o merge, também foi mencionada uma hint para uso direto do framebuffer
- Foi observado que, ao ativar
SDL_HINT_DOS_ALLOW_DIRECT_FRAMEBUFFER, o problema citado comSetDisplayStartpode deixar de ser tão importante
- Foi observado que, ao ativar
1 comentários
Comentários do Hacker News
Agora, basta existir um SDL para UEFI para que seja possível rodar jogos até no ambiente pré-boot do SO
Também queria saber se a segurança ficou mais robusta ou se ainda continua acessível https://www.zdnet.com/article/minix-intels-hidden-in-chip-operating-system/
Só que, pelo que eu saiba, a UEFI não tem driver de som, e hoje em dia até chips de codec de áudio só têm datasheets sob NDA, então escrever isso na mão também é complicado
O mais absurdo é que o graphics output protocol não tem informação de vsync, então não dá para fazer blitting sem tearing, e isso é literalmente pior do que VGA
Só de imaginar dar boot por um menu tipo grub e aparecer uma lista inteira de jogos clássicos já dá uma empolgação
O que torna esse screenshot especialmente engraçado é que o próprio DosBOX foi feito em cima do SDL
Isso usa DJGPP, então troca a CPU para modo 32 bits via DPMI
Por isso acaba não passando aquela sensação realmente old school de segmented memory, near pointer e todo tipo de limite de 64 KB aparecendo por toda parte
Legal
Fiquei curioso para saber como isso ficaria junto com executáveis MS-DOS para 386+ do FreeBASIC, que suporta bindings de SDL
[1] - https://github.com/freebasic/fbc
Já faz anos que penso em portar de volta para DOS o OHRRPGCE, que originalmente era do DOS
E, considerando como o SDL eliminou agressivamente quase todos os ports e suportes a SO que existiam na era do SDL 1.2, é bem surpreendente que o SDL3 tenha recuperado suporte a DOS
Perfeito
Hoje de manhã eu estava desenvolvendo no Turbo C dentro do DOSBox-X dentro do Debian GNU/Linux dentro do VMware Fusion no macOS, então essa notícia veio na hora certa
Tenho uma lembrança vaga de ter trabalhado com turboc décadas atrás
Tecnicamente, isso já era possível com HXDOS
Porque ele emulava DirectDraw bem o bastante para o SDL conseguir usar
Então fiquei curioso para saber para qual alvo de SDL isso é compilado
Se é fullscreen exclusivo de Win32, ou alguma resolução VESA tipo 640x480
Em projetos open source como o SDL, esse tipo de suporte normalmente depende de quão intrusivas são as mudanças e se o contribuinte realmente vai continuar fazendo manutenção
Cada projeto tem sua própria política, e eu não conheço a do SDL, mas como já existem tantos ports, imagino que eles saibam bem no que estão se metendo
Meu exemplo favorito é o openbsd luna88k https://www.openbsd.org/luna88k.html
Não faço ideia de quantos usuários reais isso tem. Acho que era uma máquina bem rara, lançada provavelmente só no Japão, e se houver usuários, a maioria deve estar por lá, fora do meu campo de visão, então na prática parece que o único usuário é o portador
Mesmo assim, a cada release, algumas semanas depois da data oficial, surgem do nada os arquivos e pacotes do luna88k como se tivessem saído da floresta
Imagino que seja porque compilar num luna88k real demora bastante, e, de qualquer forma, isso por si só já basta para manter a plataforma como hardware oficialmente suportado pelo OpenBSD
Eu mesmo não quero ter um luna88k, mas respeito muito a pessoa que faz isso continuar funcionando
Dá a sensação de que o SDL está voltando às suas raízes da era Loki
Legal
Por quê? Não sei, mas se é legal, já basta
Como dá para ver no Internet Archive, com só teclado e mouse já é possível rodar praticamente em qualquer lugar algo com a complexidade de um AAA de meados dos anos 90
Jogos como Tomb Raider, Command & Conquer e Quake entram nisso, e, se você quer uma plataforma que simplesmente funciona, é algo bem atraente
Com SDL, isso fica muito mais fácil
Fico muito feliz
Isso me deixa genuinamente contente