- Foi apresentado um projeto de demonstração em que uma única base de código escrita em Rust funciona em todas as principais plataformas de GPU e CPU, incluindo CUDA, Vulkan (SPIR-V), Metal, DirectX 12, WebGPU e CPU
- A programação tradicional para GPU costuma ser complexa e gerar duplicação por exigir linguagens separadas como GLSL e HLSL, mas esta demonstração dá suporte a todos os alvos de GPU usando apenas código Rust puro
- Como principais implementações, integra os projetos Rust GPU (SPIR-V), Rust CUDA (NVVM IR) e Naga (camada de conversão de linguagens de GPU) — o mesmo algoritmo de ordenação bitônica roda na CPU e em todas as GPUs, e recursos da linguagem Rust como no_std, compilação condicional, Newtype, Enum e Trait também se aplicam diretamente ao código de GPU
- Ainda restam pontos a melhorar, como integração oficial ao
rustc, depuração e consistência de API, mas trata-se de uma tentativa que pode marcar um ponto de virada para a computação multiplataforma em GPU
Viabilizando computação multiplataforma em GPU com Rust
Introdução e significado do projeto
- Com uma única base de código Rust, é possível executar o mesmo código de kernel em CUDA (NVIDIA), Vulkan (SPIR-V), Metal (Apple), DirectX 12 (Windows), WebGPU (navegador) e CPU
- Sem usar linguagens dedicadas a shader ou kernel (como GLSL e HLSL), torna-se possível processar as mesmas operações em GPU e CPU usando apenas código Rust puro
- Isso reduz drasticamente a duplicação de código e a complexidade entre GPU e CPU, além de levar as vantagens da linguagem e do ecossistema Rust — como segurança de tipos, testes, documentação e gerenciamento de build — também para a programação de GPU
Contexto
- A programação tradicional de GPU exige o uso de linguagens de shader especializadas para cada plataforma (por exemplo: GLSL, HLSL, MSL, WGSL etc.)
- Como consequência, o código de CPU e GPU fica separado, o que aumenta a duplicação de lógica e a complexidade de desenvolvimento
- Para lidar com isso, a comunidade Rust vem buscando uma abordagem de compilar Rust comum tendo GPU como alvo
- Rust GPU: compila código Rust para SPIR-V, executando em Vulkan e GPUs compatíveis com SPIR-V
- Rust CUDA: compila código Rust para o IR do NVIDIA CUDA (NVVM IR, PTX), executando em CUDA
- Naga: camada intermediária que oferece conversão entre várias linguagens de GPU (WGSL, SPIR-V, GLSL, MSL, HLSL), usada principalmente no projeto
wgpu. É responsável pela portabilidade entre backends
- Cada projeto começou de forma independente, com APIs e estruturas diferentes, mas a colaboração recente tornou possível a execução em GPU de uma base de código compartilhada
Como foi implementado
- Na demonstração de exemplo, o algoritmo de ordenação bitônica foi implementado em um único código Rust, e o mesmo código roda em todos os alvos, GPU e CPU
- Principais termos dos componentes
- Host: código Rust executado na CPU (inicia o trabalho)
- Device: GPU/CPU onde o kernel é realmente executado
- Driver API: APIs de baixo nível para comunicação com o dispositivo, como CUDA, Vulkan, Metal e DX12
- Backend: abstração em Rust sobre a Driver API alvo (
cust, ash, wgpu etc.)
- Combinando feature flags e alvos do Rust, é possível selecionar o backend e controlar o build
- Ex.: opções de build independentes para cada backend, como
wgpu, ash e cuda
- Também é possível implementar uma estrutura que constrói vários backends em um único binário e os seleciona dinamicamente em tempo de execução
Fluxo de compilação do kernel
- Dependendo do alvo e das features, os binários de execução em GPU (SPIR-V, PTX etc.) são gerados no build e embutidos no arquivo objeto
- Em tempo de execução, o kernel embutido é carregado e, via Naga e afins, convertido para o formato exigido por cada plataforma antes de ser executado
- Ex.:
- macOS: SPIR-V convertido para MSL → execução em Metal
- Windows: SPIR-V convertido para HLSL → execução em DX12
- Linux/Android: SPIR-V → execução em Vulkan
- CUDA: PTX compilado para SASS, enviado para a GPU e executado
Técnicas de programação para GPU amigáveis ao Rust
-
Suporte a no_std
- Como a GPU não tem suporte de sistema operacional, o uso de
no_std do Rust é indispensável
- Como o ecossistema básico do Rust já assume ambientes sem SO, como embarcados, firmware e kernel, a GPU também pode ser suportada pelo modelo padrão do Rust sem precisar de um “modo especial” separado
-
Compilação condicional
- A combinação de atributos
cfg com feature flags permite escrever de forma clara e concisa o código que distingue plataformas e separa caminhos de GPU e CPU
- IDE e compilador entendem todos os caminhos de código, garantindo alta confiabilidade e produtividade
-
Uso de newtype
- Erros de mapeamento implícito de índices e structs, comuns em GPU, podem ser evitados no nível de tipos com o uso de newtype
- Com o atributo
#[repr(transparent)], é possível obter abstração de tipo sem overhead prático
-
Enum e representações seguras
- Em vez de magic numbers, usa-se
Enum do Rust, com #[repr(u32)] para garantir mapeamento para inteiros nativos
- Pattern matching e exhaustiveness (tratamento de todos os casos) ajudam a montar código seguro
- Porém, ao trocar valores de
Enum por buffers compartilhados entre CPU e GPU, é preciso garantir que todos os valores sejam enums válidos
-
Algoritmos genéricos baseados em Trait
- Com
Trait, é possível abstrair operações de GPU como comparação, conversão e cálculo comuns a vários tipos de valor
- Ao especificar claramente os trait bounds em algoritmos genéricos, concilia-se type safety e otimização
-
#[inline] e otimização de desempenho
- O uso de
#[inline] ajuda a fazer com que camadas de abstração desapareçam no resultado final da compilação
- Considerando as características da GPU (desempenho, pilha limitada etc.), o projeto busca eliminar o custo da abstração
-
Composição de struct e agrupamento semântico
- Parâmetros complexos de GPU são agrupados em
struct por unidade de significado, garantindo segurança de tipos e evitando explosão de parâmetros
- O padrão smart constructor bloqueia estados inválidos já na etapa de compilação
-
Layout de memória e controle com #[repr(C)]
- Para compatibilidade de dados com a GPU, o layout da struct é definido explicitamente com
#[repr(C)]
- O texto menciona a necessidade futura de mais suporte da linguagem, como automatização de padding específico por GPU
-
Pattern matching
- Como uma forma expandida de switch/case, permite tratar com clareza todas as ramificações e estados no código de GPU
- O compilador pode checar caminhos de código e aplicar otimizações de desempenho
-
Funções genéricas
- Permitem implementar a mesma lógica para vários tipos, sem depender do tipo de dado
- Com trait bounds e monomorfização, melhoram manutenção e testabilidade
-
Macros derive
- Implementam automaticamente traits adequados para GPU, como
Copy, Clone, Debug, PartialEq e Pod
- Isso aumenta a segurança e reduz boilerplate
-
Sistema de módulos e gestão de workspace
- O sistema de pacotes e módulos do Rust organiza o código de host, kernels, tipos e fontes específicas de backend
- Com Cargo workspace e workspace dependency, obtém-se consistência de dependências entre crates e maior facilidade de manutenção
-
Formatação, lint e documentação
- Ferramentas padrão do Rust, como
rustfmt e clippy, podem ser usadas exatamente da mesma forma para o código de GPU, mantendo qualidade consistente
- Código de GPU também pode ser documentado com doc comments e
cargo doc
-
Scripts de build
- Com o
build.rs do Cargo, é possível automatizar builds de kernel baseados em feature flags e o embedding dos binários
-
Testes unitários e produtividade no desenvolvimento
- O código do kernel de GPU pode ser testado também na CPU, facilitando desenvolvimento e detecção de bugs
- É possível usar ferramentas tradicionais como depuração com
println e gdb/lldb
- Kernels Vulkan também podem ser testados em CI com drivers de software como SwiftShader e lavapipe
- Há integração fluida com ferramentas de terceiros para testes, medição de cobertura de código e testes baseados em propriedades
Experiência de desenvolvimento ainda incompleta e desafios
- Como os backends de GPU ainda não estão embutidos oficialmente no compilador Rust, é necessário usar backends de codegen separados (
spirv, nvvm) e fixar versões nightly
- O alvo CUDA depende do LLVM 7.1 da NVIDIA, exigindo builds separados em distribuições Linux mais recentes
- Ainda faltam uma boa experiência de build e depuração de kernel, além de melhor rastreamento de erros e informações de debug
- As APIs do Rust GPU e do Rust CUDA, assim como os nomes de bibliotecas padrão, diferem entre si, causando confusão
- No longo prazo, é necessário reforçar a consistência e a integração voltadas a GPU em toda a linguagem Rust e seu ecossistema
Participação da comunidade e futuro
- A execução do mesmo código Rust em todas as principais plataformas de GPU já foi demonstrada
- Daqui para frente, os desafios incluem melhorar build e depuração, ampliar o suporte da linguagem Rust e das APIs, e ajustar desempenho
- Desenvolvedores que quiserem participar e contribuir podem consultar os repositórios GitHub de
rust-gpu e rust-cuda
1 comentários
Comentários do Hacker News
É realmente impressionante que essa tecnologia seja possível
Mas meu caso de uso é executar em hardware arbitrário de clientes, então tendo a não confiar em todas as camadas de abstração construídas sobre APIs de GPU
O objetivo é aproveitar ao máximo os detalhes de baixo nível da GPU, e abordagens que tratam esses detalhes como incômodo acabam levando a bugs e perda de desempenho
Isso porque cada alvo é significativamente diferente
Para superar isso, acho que um sistema parecido teria de ser fornecido diretamente pelos próprios fabricantes
Mas como ainda não há consenso entre eles, parece que as diferenças entre plataformas continuam grandes
Em certos casos há exceções como o Angle, mas mesmo nesses casos a estabilidade só vem por meio de limitações de funcionalidade, o que no fim traz perda de desempenho
Ainda assim, o fato de abordagens como compilação condicional serem possíveis claramente ajuda
Rust é uma linguagem de sistemas, então é possível ter tanto controle quanto se quiser
Pretendemos refletir os detalhes e APIs de GPU na linguagem e nas bibliotecas core/std, e expor os recursos da GPU e do driver pelo sistema
cfg()(sou o autor)
Penso exatamente a mesma coisa
Sempre sou cauteloso ao construir algo comercial sobre camadas de abstração, adaptadores e camadas de tradução que talvez não recebam suporte suficiente no futuro
Já estamos quase em 2025, mas ainda sinto falta desesperadamente de um padrão aberto que seja suportado por todos os fabricantes e permita usar todos os recursos do hardware de GPU mais recente
Dado o estado atual das coisas, também parece significativo que a Nvidia, que criou a mais forte barreira de entrada no software, esteja sentada como representante da Khronos
Parece que você se importa bastante com desempenho, então queria perguntar por curiosidade
Para mim, o estado atual das GPUs se parece muito com o que já vimos antes nas CPUs
Nas CPUs, havia uma estrutura de compilador em três camadas, com otimização em uma camada intermediária e geração de código específico para cada hardware na camada final
A vantagem disso é que a camada de abstração dura bastante tempo, e o compilador vai ficando mais inteligente com o tempo
Fico curioso se algo assim é possível no lado das GPUs
Ou se a diversidade das GPUs é grande demais para isso, tornando a ideia inviável ou antieconômica, ou ainda se esse é obviamente o caminho mas a tecnologia ainda não chegou lá
Exatamente isso
Não vejo muito qual seria a vantagem de rodar Rust em GPUs da Nvidia em vez de simplesmente usar código CUDA existente
Entendo adicionar abstrações, mas no fim fica com aquela sensação de “faz de tudo, mas de forma genérica”
Na verdade, tudo é abstração
O próprio CUDA, no fim das contas, não passa de uma abstração que unifica conceitualmente hardwares que na prática são completamente diferentes
Eu desenvolvo apps de áudio nativos, e aqui cada ciclo de computação importa
Além disso, preciso da API de compute completa, não apenas de shaders gráficos
Fico curioso se o pipeline
Rust -> WebGPU -> SPIR-V -> MSL -> Metalé sólido em termos de desempenhoParece frágil e imprevisível por ter etapas demais de transformação
O mesmo vale para
... -> Vulkan -> MoltenVk -> ...Em contraste,
Julia -> Metalpula o MSL e consegue aproveitar diretamente otimizações específicas do Apple Silicon, como Unified MemoryA inovação aqui não é a linguagem de shader, e sim o uso de uma linguagem de programação completa, como Rust
Rust oferece vários recursos como newtype, trait e macro
Ao usar rust-gpu, você não precisa necessariamente passar pela camada do WebGPU
Isso porque rust-gpu é um backend de geração de código do compilador
A estrutura permite compilar Rust MIR diretamente para SPIR-V
O pipeline
Rust -> WebGPU -> SPIR-V -> MSL -> Metalé sólido em termos de desempenho?Em essência, é um conceito parecido com a forma como a Apple usa o Clang para otimização voltada a GPU
SPIR-V é uma representação intermediária, como a IR usada no LLVM, então pode ser otimizada por sistema
Em teoria, uma única base de código pode mirar todas as GPUs raster suportadas
Já a stack
Julia -> Metaltem portabilidade relativamente menorPara desenvolvedores limitados a uma plataforma, como em plugins de áudio, isso talvez não importe, mas para empresas multiplataforma como u-he ou Spectrasonics, um pipeline mais complexo baseado em SPIR-V pode ser mais atraente
Para computação numérica e otimização subsequente, Julia combina muito mais do que Rust, que é uma linguagem de sistemas
Se você olhar a matriz de compatibilidade do Rust-CUDA, dá para ver que a demanda por Rust em programação CUDA é muito pequena
Falta a maior parte dos recursos que as pessoas gostam no CUDA, e se houvesse demanda real haveria avanços maiores, mas não é o que acontece
Parece que programadores de CUDA não têm muita vontade de usar Rust
https://github.com/Rust-GPU/Rust-CUDA/blob/main/guide/src/features.md
Mesmo quando tenho código que eu gostaria de rodar na GPU, tudo em programação de GPU é tão doloroso que acabo desistindo
Acho que a verdadeira utilidade do rust-gpu talvez seja transformar desenvolvedores de CPU em desenvolvedores de GPU, mesmo aceitando alguma perda de desempenho
Se você já está confortável no mundo de GPU e domina cuda/vulkan/metal/dx, provavelmente não vai achar esse tipo de ferramenta tão atraente
Sou só um desenvolvedor web simples, então talvez seja uma pergunta idiota, mas nunca fiz programação de GPU
Fico pensando se o WebGPU, por ser uma API única compatível com todos os backends de GPU, não resolveria todos esses problemas
WebGPU também parece ser um dos backends suportados, então se for esse o caso, isso não seria só colocar outra abstração em cima de abstrações já existentes, acabando de qualquer forma em backends nativos de GPU?
Não é isso
WebGPU é uma API que, do lado da CPU, controla a GPU para executar shaders e várias outras tarefas gráficas
Já o Rust-GPU é uma linguagem para escrever o código de shader que realmente roda na GPU, de forma parecida com HLSL, GLSL e WGSL
Quando a Microsoft tinha mais influência, havia o DirectX
Mas hoje em dia não sei até que ponto os fabricantes de GPU estão implementando APIs dedicadas para suas tecnologias proprietárias
Existem vários recursos peculiares como DLSS, MFG e RTX
Se eu fosse um vilão de desenho animado, poderia deixar as APIs existentes lentas de propósito e só oferecer desempenho de verdade em APIs novas e proprietárias do fornecedor
Dito isso, eu também sou desenvolvedor web e não sei muito bem, mas pelo menos os LLMs acabam aprendendo esse tipo de coisa
Eu diria que WebGPU está mais para uma API de mínimo denominador comum
Por exemplo, o editor Zed mira diretamente Metal na versão para Mac
E também há divergência sobre o que exatamente significa “comum”
Assim como OpenGL vs Vulkan, empresas influentes mostram movimentos para transformar seus próprios ecossistemas, como CUDA, Metal e DirectX, em padrão de mercado
Se fosse realmente tão simples assim, o CUDA não seria hoje o enorme fosso competitivo da Nvidia
A base importante desse projeto é o esforço da implementação WebGPU wgpu-rs
WebGPU não é ideal para apps nativos
Ele foi projetado com base em versões antigas do Vulkan, especialmente o período pré-RTX, e desde então as APIs nativas propriamente ditas evoluíram muito mais
Ainda está num nível meio tosco, mas é difícil acreditar que algo assim já seja possível
Se esse tipo de avanço continuar, sinto que há potencial para quebrar a forte dependência de fornecedores no software de GPU e permitir competição real entre fabricantes de hardware
Consigo até imaginar um mundo em que modelos de machine learning sejam escritos em Rust e executados tanto em Nvidia quanto em AMD
Claro que, para obter desempenho máximo, seria preciso escrever código específico para cada fornecedor, mas isso é um problema de otimização
Mesmo assim, ainda daria para usar kernels portáveis que rodam em múltiplas plataformas
Existe um framework de machine learning em Rust chamado https://burn.dev, com vários backends como CUDA e ROCm
Pode valer a pena dar uma olhada
Acho difícil que, em menos de dez anos, exista um futuro em que modelos de machine learning sejam escritos em Rust e rodem tanto em Nvidia quanto em AMD
Na prática, todo o ecossistema, como jax e torch, é baseado em Python
Fazer todos os desenvolvedores profissionais migrarem para ferramentas em Rust é algo quase impossível até de imaginar
Se você contar as camadas de abstração
Existem pelo menos seis complexidades ocultas desse tipo
Fico em dúvida se é possível atravessar todas essas camadas e ainda refletir as peculiaridades da plataforma no desempenho sem perdas
O que rust-gpu faz, no fim, é compilar para SPIR-V, ou seja, a IR do Vulkan
Então as camadas 2 e 3 podem ser puladas ou mantidas em paralelo
Ferramentas do ecossistema de desenvolvimento Rust como cargo, cargo test, cargo clippy e rust-analyzer também podem ser aproveitadas diretamente no desenvolvimento de shaders para GPU
Na verdade, acho que a programação de GPU não é difícil porque a arquitetura da GPU seja alienígena demais, e sim porque todo o ecossistema é preso a fornecedores e a ferramentas antigas
A demo realmente se parece mais com uma máquina de Rube Goldberg complicada, mas isso acontece porque é a primeira vez que algo assim se torna possível
Com o tempo, isso deve ficar mais natural e integrado
E outra vantagem do ecossistema Rust é que você pode desenvolver com o nível de abstração ou de concretude que quiser
Por exemplo, dá para usar recursos específicos de plataforma com
std::arch, ou até escrever assemblyTambém é possível trocar alocadores e panic handlers, e quando o recurso externally implemented items, que está por vir, for ativado, a flexibilidade para lidar com camadas de abstração no nível desejado deve aumentar ainda mais
Bom ponto
Mas as camadas 4 a 6 sempre existem também em shaders ou código CUDA
As camadas 1 e 3, na prática, só seriam substituídas por outras camadas, especialmente em cenário multiplataforma
Mesmo que esse projeto em Rust adicione uma camada de abstração, seria algo como apenas uma camada a mais
E, como alguém que trabalha na prática justamente nas camadas 4 a 6, posso garantir que a complexidade escondida ali é enorme
Para ser sincero, às vezes entram ainda mais camadas :P
De forma realista, a maioria dos usuários vai lidar no máximo até a camada (3) ou (4)
Na prática, não é um aumento tão grande no número de etapas
E, só para constar, acima da camada 6 também existem mais camadas de abstração
Firmware e microarquitetura implementam o conjunto de instruções que imaginamos estar vendo
Não acho que isso seja tão diferente de operar compiladores e runtimes distintos para diferentes arquiteturas de CPU
Há também convenções de chamada diferentes, diferenças de endianness, e no nível de hardware existem ainda firmware e microcódigo
É realmente impressionante que crates existentes em
no_std+no allocrodem na GPU quase sem alteraçõesDá a sensação de que isso abre muitas possibilidades de aplicação
Muito impressionante
A lista de projetos de Rust para GPU já ficou enorme
Este aqui parece uma abstração de nível mais baixo que burn, e burn por sua vez é mais de baixo nível que candle
Agora parece que falta só adicionar um backend como naga aos projetos acima
Dá a sensação de que todo mundo está construindo algo sobre bases diferentes, mas talvez isso aconteça porque o trabalho com naga é relativamente recente
Também quero acrescentar que o burn parece focar em suporte de plataforma
Mas, pelo que vejo, o único backend que usa naga é o wgpu
Então, no fim, não bastaria usar só wgpu?
Resumindo, é wgpu/ash(vulkan, metal) ou então cuda
Mais uma observação: outro crate próximo desse esforço
https://github.com/tracel-ai/cubecl
[0]: https://github.com/tracel-ai/burn
[1]: https://github.com/huggingface/candle/
Há informações organizadas sobre o CubeCL lá
Fico em dúvida se isso é realmente “Rust” rodando na GPU
Dando uma olhada por cima no código, parece uma estrutura em que, sobre a sintaxe de Rust carregada de macros de programação, acaba se apoiando uma linguagem de shader no final
Como programação de GPU é algo muito diferente, acho que exige cuidado especial
Colocar abstrações assim pode acabar inviabilizando certas otimizações
Fico muito feliz de ver esse projeto
Tenho a sensação de que isso está ajudando bastante desenvolvedores que não querem se envolver em guerras de plataforma
Exemplos como https://github.com/cogentcore/webgpu também são ótimos
Eu uso golang e só quero conseguir aproveitar bem a GPU em todas as plataformas, e graças a isso dá para usar GPU em qualquer lugar
Muito obrigado ao Rust