174 lines
3.8 KiB
Markdown
174 lines
3.8 KiB
Markdown
# Shader Compiler
|
|
|
|
A compiler for a custom, platform-agnostic shader language that compiles to platform specific shader languages (currently only HLSL).
|
|
|
|
## Features
|
|
|
|
A simple passthrough shader (`passthrough.shd`) can look as follows
|
|
```hlsl
|
|
vertex main :: (position : float4 @position) -> float4 {
|
|
return position;
|
|
}
|
|
|
|
pixel main :: () -> float4 @target {
|
|
return float4(1, 1, 1, 1);
|
|
}
|
|
```
|
|
The shader contains both vertex and pixel shader code, where you specify the entry points as above. Entry points can have any and overlapping names, which will be exposed in the meta data of a compiled shader.
|
|
There is basic support for most HLSL built-in math functions for the following types:
|
|
- Scalar types: int, float
|
|
- Vector types: float2, float3, float4, int2, int3, int4
|
|
- Matrices: float4x4
|
|
All of the above can be constructed with their namesake constructors i.e. `float4(x, y, z, w);`.
|
|
We also support Samplers and Texture2D
|
|
|
|
If you want to declare and use variables you can do it as follows
|
|
```hlsl
|
|
x : float = 2.0; // no 'f' suffix required or even supported (it gives an error)
|
|
y : float = 4.0;
|
|
v : float2 = float2(x, y);
|
|
v2 := float2(x, y);
|
|
```
|
|
|
|
You can also do arithmetic as you would expect
|
|
```
|
|
x : float = 2.0 * 4.0 + (3 * 2); // int literals automatically convert to floats.
|
|
```
|
|
|
|
There is basic struct support
|
|
```hlsl
|
|
Camera_Data :: struct {
|
|
projection : float4x4;
|
|
view : float4x4;
|
|
}
|
|
```
|
|
|
|
You can also define constant buffers
|
|
|
|
```
|
|
camera :: Constant_Buffer {
|
|
projection : float4x4;
|
|
view : float4x4;
|
|
}
|
|
```
|
|
|
|
You can mark these with `@` hints to mark specific mappings for your engine
|
|
|
|
```
|
|
camera :: Constant_Buffer @camera {
|
|
projection : float4x4;
|
|
view : float4x4;
|
|
}
|
|
```
|
|
|
|
Structured buffers - simply called `Buffer` - are now also supported
|
|
|
|
```
|
|
buffer :: Buffer {
|
|
color : float4;
|
|
model : float4x4;
|
|
}
|
|
|
|
vertex main :: (position : float3 @position, instance_id : int) -> float4 @outposition {
|
|
return mul(position, buffer[instance_id].model);
|
|
}
|
|
|
|
pixel main :: (instance_id : int) {
|
|
return buffer[instance_id].color;
|
|
}
|
|
```
|
|
|
|
You will get a `Buffer` instance returned in the compiled result which has all the fields in the buffer exposed. See more below.
|
|
|
|
## Jai Usage Example
|
|
|
|
To compile a shader and use the result, you can do the following in jai
|
|
```jai
|
|
|
|
|
|
ctx : Compiler_Context;
|
|
|
|
add_define(*ctx, "SKINNING"); // Pass environment defines here, you can also use the `#add_define` in your shaders for debugging.
|
|
compile_file(*compiler, "shader.ink", allocator);
|
|
|
|
if ctx.had_error {
|
|
log_error("%\n", report_messages(ctx.messages),, temp);
|
|
return;
|
|
}
|
|
|
|
// The ctx now contains all the needed information like the source text, entry points, constant buffers etc.
|
|
```
|
|
|
|
### Output data
|
|
|
|
When parsing a shader you pass a `Compiler_Context` struct which in turn will contain all the output data in the end. See `module.jai` for more info.
|
|
|
|
An example of output data are buffers (constant, structured)
|
|
|
|
```
|
|
Buffer :: struct {
|
|
name : string;
|
|
|
|
fields : Static_Array(Property_Field, 16);
|
|
|
|
// hints : Field_Hint; // optional hint...
|
|
hints : [..]Field_Hint;
|
|
|
|
buffer_index : u32;
|
|
}
|
|
|
|
```
|
|
|
|
A field is just a simple struct with a name and type (and hints such as semantics or custom hints in the future)
|
|
```
|
|
Field_Hint :: struct {
|
|
kind : Hint_Kind;
|
|
|
|
target_index : int;
|
|
custom_hint_name : string;
|
|
}
|
|
|
|
Field :: struct {
|
|
name : string;
|
|
|
|
type : Field_Type;
|
|
hints : [..]Field_Hint;
|
|
}
|
|
|
|
Field_Kind :: enum {
|
|
Int :: 0;
|
|
Half :: 1;
|
|
Float :: 2;
|
|
Double :: 3;
|
|
Texture2D :: 8;
|
|
Sampler :: 9;
|
|
|
|
Function;
|
|
Struct;
|
|
Array; // Not yet supported
|
|
}
|
|
|
|
Field_Type :: struct {
|
|
kind : Field_Kind;
|
|
|
|
name : string; //@Note(niels): for structs
|
|
|
|
children : [..]Field;
|
|
}
|
|
|
|
Hint_Kind :: enum {
|
|
None;
|
|
|
|
Position;
|
|
Target;
|
|
|
|
Custom;
|
|
}
|
|
```
|
|
|
|
## Notable missing features
|
|
|
|
- While
|
|
- Multiple render targets
|
|
- Interpolation specifiers
|
|
- Importing files such as shared utils etc. with something other than textual `#load` |