README.md 4.14 KB
Newer Older
Johannes Braun's avatar
Johannes Braun committed
1
# GLShader Processor
Johannes Braun's avatar
Johannes Braun committed
2

Johannes Braun's avatar
Johannes Braun committed
3
This is my attempt to create a preprocessor for GLSL code in C++, as well as a platform-dependant GLSL compiler with [glGetProgramBinary](https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glGetProgramBinary.xhtml) based on [GL_ARB_separate_shader_objects](https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_separate_shader_objects.txt).
Johannes Braun's avatar
Johannes Braun committed
4
5

## How to use?
Johannes Braun's avatar
Johannes Braun committed
6
7
8
9
### Build libraries
You can use cmake to build the binaries to later link against.
Please use a recent compiler which supports c++17 and experimental::filesystem.

Johannes Braun's avatar
Johannes Braun committed
10
11
12
13
14
15
16
17
18
19
### Load file
Include `<glsp/glsp.hpp>` and that's it.
To load and process a file, you'd call `glsp::processed_file proc = glsp::preprocess_file("path/to/file.glsl", {}, {});`.

### Include Paths
The second parameter of the `preprocess_file` function determines the include search paths for when processing a file.
Example: `auto file = glsp::preprocess_file("path/to/file.glsl", {"my/shaders/"}, {});`.

### Predefined definitions
In the third function parameter, you can add predefined definitions.
Johannes Braun's avatar
Johannes Braun committed
20
#### Examples:
Johannes Braun's avatar
Johannes Braun committed
21

Johannes Braun's avatar
Johannes Braun committed
22
```c++
Johannes Braun's avatar
Johannes Braun committed
23
24
// Simple valueless definition
glsp::definition def_no_val("NO_VAL");
Johannes Braun's avatar
Johannes Braun committed
25

Johannes Braun's avatar
Johannes Braun committed
26
27
// Parameterless macro
glsp::definition def_my_val("MY_VAL", 2);
Johannes Braun's avatar
Johannes Braun committed
28

Johannes Braun's avatar
Johannes Braun committed
29
30
// Parameterized macro with parameters a, b and c.
glsp::definition def_add_mul("AddMul", { {"a", "b", "c"}, "(a + b * c)" });
Johannes Braun's avatar
Johannes Braun committed
31
32
33
34
35

// Two kinds of formatted definitions.
auto fmt_def1 = glsp::definition::from_format("MY_MACRO(a, b, fun) (fun(a, b)-1)");
auto fmt_def2 = "OTHER_MACRO(x) (x * 2.f - 1.f)"_gdef;

Johannes Braun's avatar
Johannes Braun committed
36
// Pass definitions to preprocessor.
Johannes Braun's avatar
Johannes Braun committed
37
38
39
40
41
auto file = glsp::preprocess_file("file", {}, { def_my_val, def_no_val, def_add_mul, fmt_def1, fmt_def2 });
```
A formatted definition must have one of the following formats:
* Valueless definition: `MACRO`
* Parameterless macro with value: `MACRO val`
Johannes Braun's avatar
Johannes Braun committed
42
43
44
45
* Parameterized with n parameters and empty or non-empty replacement: `MACRO(p0, p1, ..., pn) rep`

### State
You can use `glsp::state` as follows to allow for persistent predefined definitions and include directories.
Johannes Braun's avatar
Johannes Braun committed
46
```c++
Johannes Braun's avatar
Johannes Braun committed
47
48
49
50
51
52
53
// Once
glsp::state preproc_state;
preproc_state.add_definition("my_def(a, b, c) (-a + b * c)"_gdef);
preproc_state.add_definition({ "MY_VAL", 2 });
preproc_state.add_definition({ "NO_VAL" });
preproc_state.add_definition({ "AddMul",{ { "a", "b", "c" }, "a + b * c" } });
preproc_state.add_include_dir("../shaders/");
Johannes Braun's avatar
Johannes Braun committed
54
// ...
Johannes Braun's avatar
Johannes Braun committed
55
56
// Somewhere else
auto file = preproc_state.preprocess_file("my_file.glsl");
Johannes Braun's avatar
Johannes Braun committed
57
58
59
60
61
```

### Binary Compiler
The `glsp::compiler` class derives from `glsp::state` and provides the functionality to compile and cache your GLSL text files to the system's proprietary binary format and load them from there.
The resulting compiled program binary can only be used for separable programs with [opengl pipeline objects](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glCreateProgramPipelines.xhtml).
Johannes Braun's avatar
Johannes Braun committed
62
63
64
65
66
67
68
69
70
71
72
73
Shader files compiled with the `glsp::compiler` need to have proper extensions declaring their shader stage:

| Extension | Type                      |
| :-------- | :-------------------------|
| .vert     | GL_VERTEX_SHADER          |
| .geom     | GL_GEOMETRY_SHADER        |
| .tesc     | GL_TESS_CONTROL_SHADER    |
| .tese     | GL_TESS_EVALUATION_SHADER |
| .frag     | GL_FRAGMENT_SHADER        |
| .comp     | GL_COMPUTE_SHADER         |

#### Compiler usage example:
Johannes Braun's avatar
Johannes Braun committed
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
```c++
glsp::compiler compiler(".bin", "path/to/cache/");
compiler.set_default_prefix(opengl_prefix); // optional prefix string, e.g. containing the #version tag or default extensions.
compiler.set_default_postfix(opengl_postfix); // optional postfix, e.g. bindless uniform layout declarations.

// Definitions and includes like with glsp::state
compiler.add_definition(...);
compiler.add_include_dir("my/include/dir/")

glsp::shader_binary binary = compiler.compile("path/to/shader.vert", glsp::format::gl_binary, false, more_includes, more_defines);

// Data is empty if there was a syntax-, compiler- or linker-error
if(!binary.data.empty())
{
    my_program_id = glCreateProgram();
    glProgramParameteri(_id, GL_PROGRAM_SEPARABLE, GL_TRUE); // Only a single program 
    glProgramBinary(_id, GLenum(bin.format), bin.data.data(), int(bin.data.size()));
}
else
{
    // Error handling...
}
Johannes Braun's avatar
Johannes Braun committed
96
```