Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b5165df

Browse files
authoredOct 31, 2024··
Merge pull request #29 from JuanDiegoMontoya/main
Update GLSL article and articles now display update date and author
2 parents afd8652 + 09f0b32 commit b5165df

File tree

3 files changed

+92
-38
lines changed

3 files changed

+92
-38
lines changed
 
Loading
Lines changed: 90 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,92 @@
11
---
22
title: 'GLSL Development Made Shrimple'
33
slug: 'glsl-development-made-shrimple'
4-
description: 'Tips and tools to make GLSL development easier'
4+
description: 'Tips and tools to make GLSL development easier.'
55
date: '2024-10-17'
66
authors: ['jaker']
77
tags: ['glsl', 'opengl', 'vulkan', 'beginner', 'visual studio', 'visual studio code', 'article']
8+
last_update:
9+
date: '2024-10-31'
10+
author: Jaker
811
---
912

10-
# GLSL Linters
13+
While a common way to use GLSL, editing bare text files or embedded strings is not a scalable way to write programs.
1114

12-
Life is so much better when you get instant feedback on the errors you make.
15+
This article will show how to make programming in GLSL more tolerable with linting and various means of code reuse.
1316

1417
<!-- truncate -->
1518

16-
## Visual Studio Code
19+
## GLSL Linters
20+
21+
My only requirement for a GLSL linter is that it prevents me from being surprised by shader compilation errors when I run my program. That means, in addition to reporting errors it finds, it should support features like `#include` and allow me to set defines at compile-time.
22+
23+
### Visual Studio Code
24+
1725
- [GLSL Lint](https://marketplace.visualstudio.com/items?itemName=dtoplak.vscode-glsllint): provides syntax highlighting and error detection.
18-
- Requires glslangValidator from [the Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) or compiled yourself. The path to the executable must be supplied in the extension settings.
19-
- Compiler flags are supplied as a list in the extension settings.
20-
- I use `-C` (show multiple errors), `--glsl-version 460` (automatically sets the shader `#version`), and `--P #extension GL_GOOGLE_include_directive` (so I don't have to write that in every file).
21-
- OpenGL users should add `--target-env opengl` for it to use OpenGL semantics.
22-
- File extensions can be associated with specific shader stages in the extension settings. By default, it will detect common file extensions like .vert, .frag, and .comp. It also understands .frag.glsl, etc. automatically.
23-
- Supports my convoluted `#include` hierarchies.
26+
- Requires glslangValidator from [the Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) or compiled yourself. The path to the executable must be supplied in the extension settings.
27+
- Compiler flags are supplied as a list in the extension settings.
28+
- I use `-C` (show multiple errors), `--glsl-version 460` (automatically sets the shader `#version`), and `--P #extension GL_GOOGLE_include_directive` (so I don't have to write that in every file).
29+
- OpenGL users should add `--target-env opengl` for it to use OpenGL semantics.
30+
- Each "part" of an argument separated by a space needs to be provided as a separate item of the list:
31+
- File extensions can be associated with specific shader stages in the extension settings. By default, it will detect common file extensions like .vert, .frag, and .comp. It also understands .frag.glsl, etc. automatically.
32+
- Supports my convoluted `#include` hierarchies.
2433
- [Error Lens](https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens): makes errors easier to read. Not specifically related to GLSL, but still useful to have.
2534

26-
## Visual Studio
35+
Note that Visual Studio Code requires restarting for changes to extension settings to take effect.
36+
37+
Here is an example of arguments provided to GLSL Lint:
38+
39+
![A list of arguments sent to glslangValidator from GLSL Lint's settings.](glslangValidatorArgs.png)
40+
41+
### Visual Studio
42+
2743
- [GLSL language integration (for VS 2022)](https://marketplace.visualstudio.com/items?itemName=DanielScherzer.GLSL2022): provides syntax highlighting and error detection.
28-
- Similar to GLSL Lint for Visual Studio Code in terms of features.
29-
- Can use an external compiler, such as glslangValidator.
30-
- `%VULKAN_SDK%/Bin/glslangValidator.exe`
31-
- Compiler flags are supplied as a single string
32-
- I use these flags `-C --target-env vulkan1.3 --P "#extension GL_GOOGLE_include_directive: enable" --glsl-version 460`
33-
- I haven't had much luck with this extension understanding my setup for `#include`, but it could be (and probably is) a skill issue on my part.
44+
- Similar to GLSL Lint for Visual Studio Code in terms of features.
45+
- Can use an external compiler, such as glslangValidator.
46+
- `%VULKAN_SDK%/Bin/glslangValidator.exe`
47+
- Compiler flags are supplied as a single string
48+
- I use these flags `-C --target-env vulkan1.3 --P "#extension GL_GOOGLE_include_directive: enable" --glsl-version 460`
49+
- I haven't had much luck with this extension understanding my setup for `#include`, but it could be (and probably is) a skill issue on my part.
3450
- [inline_glsl](https://marketplace.visualstudio.com/items?itemName=kristian-r.inlineglsl): provides syntax highlighting and error detection inside C strings containing GLSL.
35-
- Requires annotating C strings containing GLSL with a comment.
36-
- Has no extension settings.
37-
- Only supports OpenGL GLSL.
38-
- Does not use an external GLSL compiler.
51+
- Requires annotating C strings containing GLSL with a comment.
52+
- Has no extension settings.
53+
- Only supports OpenGL GLSL.
54+
- Does not use an external GLSL compiler.
3955

40-
# Code Reuse
56+
## Code Reuse
57+
58+
### `#include` support
4159

42-
## `#include` support
4360
OpenGL GLSL doesn't support `#include` (GL_ARB_shading_language_include barely counts), so we must find an external way to support it. There are a few viable ways to gain support for `#include` in your shaders if you're using OpenGL, in increasing effort:
4461

4562
- [stb_include.h] provides a simple interface for expanding includes in shader sources without evaluating other preprocessor directives (which means it expands `#include` directives in inactive preprocessor blocks).
46-
- [My fork of it](https://github.com/nothings/stb/pull/1336) fixes the const-incorrect API, which can annoyingly require `const_cast` to use in C++.
47-
- [My super secret forbidden fork of it](https://github.com/JuanDiegoMontoya/Frogfood/blob/main/vendor/stb_include.h) fixes nested includes and some other minor issues, but introduces a C++17 standard library include (`<filesystem>`) for implementer convenience.
63+
- [My fork of it](https://github.com/nothings/stb/pull/1336) fixes the const-incorrect API, which can annoyingly require `const_cast` to use in C++.
64+
- [My super secret forbidden fork of it](https://github.com/JuanDiegoMontoya/Frogfood/blob/main/vendor/stb_include.h) fixes nested includes and some other minor issues, but introduces a C++17 standard library include (`<filesystem>`) for implementer convenience.
65+
- [ARB_shading_language_include](https://registry.khronos.org/OpenGL/extensions/ARB/ARB_shading_language_include.txt) extends OpenGL by letting the user define a virtual filesystem that will be searched when include directives are found.
4866
- Writing your own preprocessor?!?
49-
- Just make sure it supports nested includes.
67+
- Just make sure it supports nested includes.
68+
- Even if you don't use its virtual filesystem, `ARB_shading_language_include` adds support for C-style `#line` (containing a string) which can improve error messages when used.
5069
- [glslang](https://github.com/KhronosGroup/glslang) and [shaderc](https://github.com/google/shaderc) (whose shader compiler is essentially a glslang wrapper) provide C++ interfaces for processing, compiling, and linking shaders.
51-
- If you want to supply shaders to OpenGL with `glShaderSource` (and let's face it: you should), you can first use glslang to only preprocess the shader, which will expand `#include`s and other directives, then return a string. glslang explicitly warns against this usage as it's not officially supported, but it worked on my machine! The downside to this approach is that errors reported by the driver will be in the "wrong" place after expanding includes. This can be mitigated by using a linter (see above) or fully compiling and linking the shader with glslang, which itself will report errors in the correct places.
52-
- If you want to supply shaders to OpenGL with `glShaderBinary` (you don't), glslang can compile shaders into a SPIR-V binary with little more code than it takes to preprocess them.
53-
- Both glslang and shaderc require writing an include handler to tell the compiler where to find included files. This gets a bit hairy with nested includes. I'm surprised there isn't a default implementation, so [here's a link to my hacky one](https://github.com/JuanDiegoMontoya/Frogfood/blob/main/src/Fvog/Shader2.cpp#L70-L116).
70+
- If you want to supply shaders to OpenGL with `glShaderSource` (and let's face it: you should), you can first use glslang to only preprocess the shader, which will expand `#include`s and other directives, then return a string. glslang explicitly warns against this usage as it's not officially supported, but it worked on my machine! The downside to this approach is that errors reported by the driver will be in the "wrong" place after expanding includes. This can be mitigated by using a linter (see above) or fully compiling and linking the shader with glslang, which itself will report errors in the correct places.
71+
- If you want to supply shaders to OpenGL with `glShaderBinary` (you don't), glslang can compile shaders into a SPIR-V binary with little more code than it takes to preprocess them.
72+
- Both glslang and shaderc require writing an include handler to tell the compiler where to find included files. This gets a bit hairy with nested includes. I'm surprised there isn't a default implementation, so [here's a link to my hacky one](https://github.com/JuanDiegoMontoya/Frogfood/blob/main/src/Fvog/Shader2.cpp#L70-L116).
5473

55-
### Vulkan
74+
#### Vulkan
5675

5776
Since Vulkan GLSL users are likely to be already using glslang in some fashion (be it the CLI or API), adding support for `#include` is straightforward. CLI users don't have to do anything. API users must write an include handler as outlined above. In either case, I suggest adding `#extension GL_GOOGLE_include_directive : enable` to the preamble to preserve your fingers (`--P` in the CLI, `TShader::setPreamble` in the API).
58-
## Sharing Code Between the Device and Host
77+
78+
shaderc automatically enables `GL_GOOGLE_include_directive`, so its users do not need to enable it themselves.
79+
80+
### Sharing Code Between the Device and Host
81+
5982
Writing the same structure definitions for buffers in both C or C++ and GLSL is annoying and prone to error.
60-
### My Solution
83+
84+
#### My Solution
85+
6186
is to abuse macros. It also requires shading language includes.
6287

6388
The first step is to write a "shared header" of common definitions that can be understood by both GLSL and C++. This file is split into sections that are only compiled in one language or the other:
89+
6490
```glsl
6591
#ifndef COMMON_H
6692
#define COMMON_H
@@ -76,36 +102,38 @@ The first step is to write a "shared header" of common definitions that can be u
76102
77103
#define FROG_UINT32 uint
78104
#define FROG_VEC4 vec4
105+
#define alignas(x)
79106
80107
#endif
81108
82109
#endif // COMMON_H
83110
```
84111

85112
The second step is to put structure definitions in a file that both languages understand. This can be a separate header, or in the body of the shader itself. For an example of the latter:
113+
86114
```glsl
87115
// Common section
88116
#include "Common.h"
89117
90118
struct Args
91119
{
92120
#ifdef __cplusplus // Simple constructor to initialize with safe defaults
93-
Args() : dimensions(0, 0), samples(1) {}
121+
Args() : dimensions(0, 0), samples(1) {}
94122
#endif
95-
FROG_IVEC2 dimensions;
96-
FROG_UINT32 samples;
123+
FROG_IVEC2 dimensions;
124+
FROG_UINT32 samples;
97125
};
98126
99127
#ifndef __cplusplus // GLSL-only section
100128
101129
layout(binding = 0) readonly buffer ArgsBuffer
102130
{
103-
Args args;
131+
Args args;
104132
};
105133
106134
void main()
107135
{
108-
// Do some shadery things
136+
// Do some shadery things
109137
}
110138
111139
#endif
@@ -114,4 +142,28 @@ void main()
114142
C++ source files can include this file to see the definition of `Args`.
115143

116144
Note that including shader sources like this only works if the `#version` directive can be omitted (e.g. if it's part of the preamble). It cannot be placed into a preprocessor block due to wacky GLSL rules:
117-
> The `#version` directive must occur in a shader before anything else, except for comments and white space.
145+
> The `#version` directive must occur in a shader before anything else, except for comments and white space.
146+
147+
As usual, care must be taken to ensure the host and device impementations don't disagree in your structs' packing. [`alignas`](https://en.cppreference.com/w/cpp/language/alignas) can be used to force a particular alignment on the host, or explicit padding words can be added where the device would otherwise implicitly assume there to be padding.
148+
149+
```glsl
150+
struct Frog // With alignas
151+
{
152+
alignas(16) FROG_VEC3 position;
153+
alignas(16) FROG_VEC3 direction;
154+
};
155+
```
156+
157+
```glsl
158+
struct Frog // With explicit padding
159+
{
160+
FROG_VEC3 position;
161+
FROG_UINT32 _padding00;
162+
FROG_VEC3 direction;
163+
FROG_UINT32 _padding01;
164+
};
165+
```
166+
167+
If GLSL's packing rules confuse you, I suggest reading about them in [the spec](https://registry.khronos.org/OpenGL/specs/gl/glspec46.core.pdf#page=168) (7.6.2.2 Standard Uniform Block Layout). Beware sources that aren't the spec, as they are often wrong!
168+
169+
Happy shading!

‎docusaurus.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ const config: Config = {
4646
{
4747
docs: false,
4848
blog: {
49+
showLastUpdateTime: true,
50+
showLastUpdateAuthor: true,
4951
showReadingTime: true,
5052
feedOptions: {
5153
type: ['rss', 'atom'],

0 commit comments

Comments
 (0)
Please sign in to comment.