Especificação da linguagem de shaders e do CSIR do ChrisOS¶
Sobre este capítulo Especificações e referências primárias
Neste capítulo
- Especificação da linguagem de shaders e do CSIR do ChrisOS
- Status
- Escopo
- Stages suportados
- Limite de source
- Versão do compilador
- Directive de version
- Comentários
- Limite de identifiers
- Limite de tokens
- AST e nesting
- Symbols e temporaries
- Error budget
- Types suportados
- Qualifiers reconhecidos
- Restrição de global scope
- Layout locations
- Vertex inputs
- Varyings
- Fragment output
- Built-in variables
- Statements
- If/else
- For é unrolled em compile time
- Increment/decrement
- Functions
- Calls são expandidos semanticamente
- Arithmetic
- Modulo
- Indexing
- Swizzles
- Matrix operations
- Constructors
- Built-in functions
- texture()
- Limite de samplers
- Uniform slots
- Reflection de uniforms
- Layout de uniform
- Pipeline de compilação
- Compiler cache
- Dumps
- ChrisOS shader IR
- Limites de IR
- IR verifier
- IR optimizer
- TGSI
- Program linking
- Relink com falha
- Execução em software
- Software triangle rasterizer
- Paridade software/VirGL
- Integração VirGL
- Shader sources embutidos
- Formato CSIR serializado
- CSIR header
- CSIR payload
- Portabilidade do CSIR
- Checksum CSIR
- Load de CSIR
- Guest shader objects
- Resource lifetime
- Segurança e robustez
- Semânticas que não são GLSL completo
- Requisitos de compatibilidade
- Próximos trabalhos
- Resumo de conformidade
- Nota de revisão
Status¶
O ChrisOS possui um pequeno compilador e runtime de shaders para sua própria pilha gráfica.
O próprio source é explícito:
trata-se de um subconjunto GLSL do ChrisOS, não de uma implementação GLSL 3.30.
Esta especificação descreve o subconjunto, o pipeline de compilação, o modelo de link de programas, a representação intermediária, o caminho de execução em software, a saída TGSI, o formato CSIR serializado e o ownership de objetos guest implementados na revisão e05a17fd76333114a3fb5c2452f38ca747d4ac56.
Escopo¶
O subsistema possui cinco camadas distintas:
- source text semelhante a GLSL;
- lexer/parser/semantic frontend;
- IR de shader do ChrisOS;
- execução do IR em software ou geração de TGSI;
- integração do program com os backends software/VirGL.
Um arquivo iniciado com #version 330 não comprova suporte completo a GLSL 3.30.
A directive é apenas sintaxe aceita dentro de uma linguagem propositalmente restrita.
Stages suportados¶
A API pública define:
vertex = 0
fragment = 1
geometry = 2
compute = 3
Entretanto sh_compile() aceita atualmente somente:
- vertex;
- fragment.
Geometry, tessellation e compute-style compilation são rejeitados.
As constants extras reservam vocabulário; não implicam implementação.
Limite de source¶
O source deve satisfazer:
0 < source_length < 4096
pois:
SH_SRC_MAX = 4096
Uma fonte com exatamente 4096 bytes já excede o limite.
Versão do compilador¶
A constant pública é:
SH_COMPILER_VERSION = 1
Ela descreve a família de implementação do compiler ChrisOS.
Não representa uma versão GLSL.
Directive de version¶
O lexer reconhece no início de linha:
#version N
com:
110 <= N <= 330
O número é registrado no compiler state.
Outras preprocessor directives são rejeitadas.
#extension, por exemplo, não é suportado.
Aceitar um número de versão não habilita o conjunto completo de features daquela especificação GLSL.
Comentários¶
São aceitos:
//line comments;/* ... */block comments.
Block comment não terminado gera compile error.
Limite de identifiers¶
Names internos usam:
SH_NAME_MAX = 40
Identifier que alcance esse limite é rejeitado.
As estruturas de reflection também usam fields fixos de 40 bytes.
Limite de tokens¶
O compiler possui:
SH_TOK_MAX = 768
tokens.
Ultrapassar esse limite é compile error.
AST e nesting¶
O frontend usa:
SH_AST_MAX = 512
SH_NEST_MAX = 32
Esgotamento de AST nodes ou nesting excessivo gera erro.
A scope table possui:
SH_SCOPE_MAX = 48
entries.
Symbols e temporaries¶
Limites:
SH_SYM_MAX = 64
SH_TEMP_MAX = 96
São hard bounds da implementação atual.
Error budget¶
O compilador retém no máximo aproximadamente os primeiros:
SH_ERR_MAX = 8
erros antes de os stages posteriores deixarem de prosseguir de forma útil.
Diagnostics incluem shader name, line, column, source line e caret quando possível.
Types suportados¶
O sistema de tipos cobre:
void;bool;int;float;vec2,vec3,vec4;ivec2,ivec3,ivec4;mat3,mat4;sampler2D.
Não fazem parte do subset atual double precision, unsigned vectors, image types, SSBO types ou user-defined structs.
Qualifiers reconhecidos¶
O lexer reconhece:
in
out
uniform
const
layout
smooth
O compiler rejeita explicitamente diversos qualifiers GLSL, entre eles:
attribute
varying
highp
mediump
lowp
inout
centroid
flat
noperspective
invariant
precise
readonly
writeonly
coherent
volatile
restrict
shared
patch
sample
Portabilidade deve ser avaliada contra esse subset, não contra GLSL desktop genérico.
Restrição de global scope¶
in, out e uniform são válidos apenas em global scope.
Usá-los em local declarations é rejeitado.
sampler2D precisa ser uniform.
Layout locations¶
É suportada sintaxe como:
layout(location = 0) in vec4 position;
Vertex attributes e stage-interface variables podem receber explicit locations.
O binder atual suporta no máximo oito attribute locations e oito varying/interface slots.
Conflitos são rejeitados.
Vertex inputs¶
Um vertex shader expõe no máximo:
8 attributes
no model atual de program/reflection.
Locations podem ser explícitas ou autoassigned ao próximo slot livre.
Reflection informa name, type, location e component count.
Varyings¶
Vertex outputs e fragment inputs são ligados por name e depois validados por type.
O linker constrói remap de fragment-input slot para vertex-output slot.
Fragment input sem matching vertex output falha.
Mesmo nome com type diferente também falha.
Há no máximo oito varying slots.
Fragment output¶
Um fragment shader precisa possuir output para que o program linke.
A semantic layer atual exige:
- exatamente um fragment output;
- type
vec4.
Multiple render targets não fazem parte do subset.
Built-in variables¶
A semantic layer introduz:
gl_Position : vec4
gl_FragCoord : vec4
gl_Position só está disponível no vertex stage.
gl_FragCoord só está disponível no fragment stage.
Um vertex shader linkável precisa escrever gl_Position.
Statements¶
O subset suporta:
- declarations;
- assignments;
- expression statements;
- blocks;
if/else;forrestrito;return;discardem fragment shader;- empty statements.
Outras forms são compile errors.
If/else¶
A condition precisa ser scalar-compatible.
O IR usa:
IR_IF
IR_ELSE
IR_ENDIF
O verifier verifica nesting e balance.
Não existem arbitrary branch labels no shader IR.
For é unrolled em compile time¶
O for atual é propositalmente restrito.
O initializer precisa declarar integer induction variable com initial value avaliável em compile time.
A condition deve poder ser avaliada estaticamente em função dessa variável.
O step precisa ser uma das integer-step forms suportadas.
O body é então emitido semanticamente repetidas vezes.
O guard de implementação é:
8 iterações
Se a condition continuar verdadeira além desse limite, compilation falha com:
loop bound exceeds the unroll limit
A loop variable não pode ser atribuída dentro do body.
Logo não existe dynamic loop geral no IR atual.
Increment/decrement¶
Pre/post increment não é um recurso geral de expression.
Ele só é aceito no contexto restrito de loop step.
Uso em expression comum é rejeitado.
Functions¶
User functions são suportadas com restrições.
Há no máximo quatro parameters por function.
Função non-void precisa produzir return value.
O return deve ser o último statement conforme as regras atuais.
Calls são expandidos semanticamente¶
User-function calls são processados durante semantic analysis; não há runtime call instruction correspondente no IR final.
O compiler mantém call depth máximo de:
8
e rejeita recursion.
Logo não existe recursive shader execution.
Arithmetic¶
O frontend cobre operators como:
+ - * /
< > <= >= == !=
&& ||
unary - and !
Compatibilidade scalar/vector segue os helpers do compiler, não toda overload resolution de GLSL.
Algumas operações são lowered a identidades simples no IR.
Modulo¶
% só é suportado quando ambos operands resolvem como constant integers e divisor é nonzero.
Não existe runtime integer remainder geral no shader IR.
Indexing¶
Vector indexing exige constant integer index.
Dynamic indexing é rejeitado.
O index precisa estar dentro do component count.
Swizzles¶
Swizzles são parsed e semanticamente verificados.
Component inválido é rejeitado.
Os tests verificam explicitamente que selecionar z de um vec2 produz diagnostic.
Matrix operations¶
O subset implementa:
mat3;mat4;- matrix × vector;
- matrix × matrix.
Matrix × scalar é rejeitado.
Uniform matrices usam column-oriented vec4 slots.
A test suite confirma a convenção efetiva por execução de MVP.
Constructors¶
Scalar/vector/matrix constructors são aceitos nas forms reconhecidas pela semantic layer.
Component count é verificado.
Scalar pode ser broadcast nos contexts suportados.
Não se deve presumir toda conversion behavior de GLSL.
Built-in functions¶
A lista implementada nesta revisão é:
texture
dot
cross
length
normalize
abs
sin
cos
min
max
clamp
mix
pow
reflect
Calls fora dessa lista podem resolver para user functions suportadas.
Name não resolvido gera erro.
texture()¶
texture() requer:
sampler2D;- coordinate vector com pelo menos duas components.
É lowered para:
IR_SAMPLE
e retorna vec4.
O compiler atual permite sampling em vertex ou fragment, sujeito ao backend.
Limite de samplers¶
No máximo:
4 samplers
são atribuídos pelo semantic binder.
Sampler slots são separados dos ordinary uniform vec4 slots.
Uniform slots¶
Non-sampler uniforms consomem array de vec4-like constant slots.
O limite é:
32 uniform vectors por stage
mat4 consome quatro.
mat3 consome três.
Scalar/vector usa um.
Reflection de uniforms¶
O linked program expõe no máximo 32 uniform entries refletidas.
Same-name uniform presente nos dois stages vira um logical program uniform quando types coincidem.
Set desse uniform atualiza storage correspondente nos dois stages.
Type mismatch de same-name uniform faz o link falhar.
Layout de uniform¶
O program mantém:
128 floats para vertex
128 floats para fragment
equivalentes a 32 vec4 slots por stage.
mat4 usa 16 floats consecutivos.
mat3 é expandida em três slots de quatro floats, com padding na quarta lane.
Pipeline de compilação¶
Para source não cached:
lex
-> parse
-> semantic analysis
-> IR optimization
-> IR verification
-> TGSI emission
Cada stage principal mede cycle count.
A API fornece timings de lex, parse, semantic, IR e TGSI.
Compiler cache¶
Compiler state bem-sucedido é cached por:
- hash do source;
- stage;
- bytes exatos do source.
O cache atual possui oito entries efetivas.
Depois do fill inicial, hashed slot pode ser substituído.
Esse cache guarda compiler representation, não GPU binary.
Dumps¶
A API expõe dumps textuais de:
- AST;
- IR;
- TGSI;
- compiler log.
São interfaces de diagnóstico e desenvolvimento, não ABIs serializados estáveis.
ChrisOS shader IR¶
As instructions atuais são:
NOP
CONST
MOV
SWZ
SETLANE
ADD
SUB
MUL
MAX
MIN
ABS
DOT
RSQ
RCP
SIN
COS
POW
TRUNC
CMP
MULMV
MULMM
SAMPLE
LOAD_ATTR
LOAD_VAR
LOAD_UNI
LOAD_FCOORD
STORE_POS
STORE_VAR
STORE_COLOR
IF
ELSE
ENDIF
DISCARD
O IR é pequeno e estruturado exatamente em torno do subset do frontend.
Limites de IR¶
SH_IR_MAX = 384 instructions
SH_IMM_MAX = 160 float immediates
SH_TEMP_MAX = 96 temporaries
IR acima desses bounds é inválido.
IR verifier¶
O verifier checa, entre outros:
- stage válido;
- opcode válido;
- temporary indexes;
- constant ranges;
- structured control flow balanceado;
- duplicate
else; STORE_POSsó em vertex;STORE_COLORsó em fragment;DISCARDsó em fragment;- sampler indexes;
- attribute indexes;
- varying indexes;
- uniform-load ranges;
- matrix dimensions.
Ele é usado tanto após frontend compilation quanto no load de CSIR serializado.
IR optimizer¶
O optimizer atual executa quatro passes simples de dead-result elimination para operations puras que produzem temporaries.
Results não usados viram IR_NOP.
Não é um optimizer SSA geral.
Não há global value numbering, loop optimization ou register-allocation framework.
TGSI¶
Shader compilado com sucesso é convertido de ChrisOS IR para TGSI text.
Buffer máximo:
SH_TGSI_MAX = 3600
Esse TGSI é consumível pelo device path VirGL.
O compiler não gera native machine code NVIDIA/AMD/Intel.
Program linking¶
Um ShProgram normalmente contém um vertex shader e um fragment shader.
Link exige:
- ambos compilados;
- vertex escreve
gl_Position; - fragment possui output válido;
- fragment inputs combinam com vertex outputs;
- varying types iguais;
- sem conflicts de uniforms;
- TGSI emitível para os dois stages.
Successful link incrementa generation.
Relink com falha¶
Se o program já estava linked e um relink posterior falha, a implementation mantém o program anterior ativo e registra:
kept previous program
Isso permite hot development sem destruir o último shader válido.
Execução em software¶
O mesmo IR possui CPU path:
sh_soft_vs()
sh_soft_fs()
sh_soft_triangle()
Vertex e fragment functions executam o IR diretamente.
Isso fornece reference path independente de VirGL.
Software triangle rasterizer¶
sh_soft_triangle() combina:
- software vertex execution;
- raster setup;
- varying interpolation;
- fragment execution;
- depth buffer;
- color packing.
O helper restringe dimensions a:
width <= 128
height <= 128
É principalmente facility de correctness/reference, não o full desktop renderer.
Paridade software/VirGL¶
Para uma feature ser realmente portable dentro da graphics stack ChrisOS, importam dois paths:
IR -> software executor
IR -> TGSI -> VirGL
Compilar para TGSI não prova software parity, e vice-versa.
Os host shader tests exercitam semantics de IR e TGSI generation.
Integração VirGL¶
A device API recebe:
gfx3d_dev_shader(ctx, stage, tgsi, &handle)
A camada gfx3d opera em software, mock ou VirGL.
Quando VirGL não está disponível e não foi forced, a camada superior pode degradar para software.
O design portanto é source/IR backend-independent com execução específica abaixo.
Shader sources embutidos¶
O tree contém exemplos para:
- triangle color;
- varying color;
- MVP;
- texturing;
- lighting;
- world transform/normal/texturing.
Muitos usam:
#version 330
mas continuam escritos para o subset ChrisOS.
São regression inputs, não GLSL 330 conformance suite.
Formato CSIR serializado¶
Shader compilado pode ser salvo com:
sh_shader_save_csi()
e carregado com:
sh_shader_load_csi()
O formato armazena IR verificado e immediates, não o GLSL source original.
CSIR header¶
O record inicia com oito 32-bit words, total de 32 bytes.
Fields:
| Word | Significado |
|---|---|
| 0 | magic = 0x52495343 |
| 1 | format version = 1 |
| 2 | stage |
| 3 | IR instruction count |
| 4 | immediate-float count |
| 5 | temporary count |
| 6 | additive checksum dos raw IR bytes |
| 7 | reserved/zero |
Em host little-endian os magic bytes são:
C S I R
CSIR payload¶
Após o header:
raw Ir[nir]
raw float[nimm]
são copiados diretamente.
O size deve ser exatamente:
[ 32 + nir cdot sizeof(Ir) + nimm cdot sizeof(float) ]
Trailing data não é aceito.
Portabilidade do CSIR¶
CSIR v1 copia diretamente:
- native
uint32_theader words; - native
Irstructs; - native C
floatarrays.
Logo é um artefato de implementação ChrisOS, não interchange format architecture-neutral.
O layout C little-endian atual faz parte da compatibilidade prática.
Um formato futuro portável deve serializar fields explicitamente.
Checksum CSIR¶
O checksum é simple 32-bit sum de cada raw byte no IR array.
Bytes dos float immediates não entram no checksum.
É corruption detection, não integrity criptográfica.
Load de CSIR¶
O loader valida:
- minimum size;
- magic;
- version 1;
- stage vertex/fragment;
- IR count <=384;
- immediate count <=160;
- temp count <=96;
- exact size;
- raw-IR checksum;
- IR verifier.
Depois regenera TGSI.
Os tests corrompem deliberadamente a image e exigem rejeição.
Guest shader objects¶
A guest API mantém bounded tables:
16 guest shaders
8 guest programs
Cada handle possui owner.
Operações de outro owner são rejeitadas.
Drop de owner libera todos os shader/program objects associados.
Esse boundary importa quando compilation é exposta a CLVM/user apps.
Resource lifetime¶
Shaders e programs são heap-backed.
A implementation mantém live-object counter.
Os tests compile/free repetidamente e confirmam retorno ao count original.
Isso fornece evidência direta contra lifecycle leaks simples.
Segurança e robustez¶
Shader source é tratado com bounds e verification.
Defesas incluem:
- source/token/AST/symbol/IR/temp limits;
- bounded diagnostics;
- bounded function expansion;
- static loop-unroll limit;
- stage-specific verifier;
- exact CSIR size check;
- owner checks em guest handles.
Essas medidas reduzem attack surface, mas não tornam o compiler formalmente verificado.
Semânticas que não são GLSL completo¶
Diferenças materiais incluem:
- apenas vertex/fragment;
- sem full preprocessor;
- sem dynamic loops;
- recursion proibida;
- no máximo quatro function parameters;
- vector indexing apenas constante;
- integer modulo apenas constante;
- qualifiers restritos;
- um único fragment color output;
- apenas quatro samplers;
- pequenos fixed resource limits;
- fixed compiler storage;
- built-in set incompleto.
Apps precisam targetar o subset explicitamente.
Requisitos de compatibilidade¶
Não devem mudar silenciosamente para assets persistidos/gerados:
- CSIR magic/version/layout;
- IR opcode meanings;
- type IDs serializados;
- numeric stage values;
- uniform/varying/attribute slot interpretation;
- matrix packing convention;
- TGSI semantic mapping quando driver objects dependem dela.
Extensões de source language podem ser aditivas, mas alterar semantics existentes pode quebrar software e VirGL.
Próximos trabalhos¶
Uma revisão futura deveria considerar:
- language profile/version explícito independente de
#version; - CSIR architecture-neutral;
- checksum/hash mais forte;
- grammar e builtin catalogue machine-readable;
- resource-limit query API;
- loops/control flow mais amplos com verified IR;
- integer semantics mais completas;
- differential software-vs-VirGL tests;
- fuzzing de lexer/parser/CSIR loader;
- compatibility suite separando comportamento ChrisOS do GLSL geral.
Resumo de conformidade¶
Uma implementação conforme precisa preservar:
- source <4096 bytes;
- somente vertex/fragment stages;
- type/resource limits documentados;
- restricted loop/function semantics;
- stage link por name/type;
gl_Positionobrigatório no vertex;- um
vec4fragment output; - verified ChrisOS IR;
- meanings dos IR opcodes;
- software execution semantics;
- TGSI generation para VirGL;
- CSIR v1 serialization/load quando o formato é usado.
Nota de revisão¶
Esta especificação foi reconciliada contra ChrisOS e05a17fd76333114a3fb5c2452f38ca747d4ac56.
A afirmação correta de compatibilidade não é "ChrisOS suporta GLSL 3.30". É: ChrisOS implementa um subconjunto GLSL-like com limites explícitos, reduz esse source a IR próprio verificado e executa o IR em software ou via TGSI/VirGL.