Skip to content

Commit

Permalink
Merge pull request #289 from ninjamike1211/main
Browse files Browse the repository at this point in the history
feat: Shaders.Properties: added custom uniforms and some Iris exclusive options
  • Loading branch information
ninjamike1211 authored Jun 28, 2024
2 parents 1f9a441 + 1ffa82e commit 3f4e8a4
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: allowConcurrentCompute
description: allowConcurrentCompute
sidebar:
label: allowConcurrentCompute
order: 2
badge:
text: Iris Only
variant: tip
---

### `allowConcurrentCompute=<true|false>`

#### Location: shaders.properties

Enables concurrent compute passes. See below for details.


## Concurrency between compute passes

In OptiFine, concurrency between compute passes **is not possible**. A `glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)` command is executed before and after every compute shader, preventing different compute passes from ever executing in parallel. However, it means that all `texture()` and `imageLoad()`/`imageStore()` commands are guaranteed to return the results of all previous compute or composite passes, even for multiple compute shaders attached to the same composite program.

NOTE: Notably, the `GL_SHADER_STORAGE_BARRIER_BIT` and `GL_FRAMEBUFFER_BARRIER_BIT` flags are omitted in this call. While omitting `GL_SHADER_STORAGE_BARRIER_BIT` is valid as no release version of Iris or OptiFine supports shader storage buffer objects in any context, it is unclear whether it is valid to omit `GL_FRAMEBUFFER_BARRIER_BIT`. TODO: More investigation is needed here.

This is also the behavior in Iris when `allowConcurrentCompute` is set to `false`, which is the default.

### Enabling allowConcurrentCompute

If `allowConcurrentCompute` is set to `true` in `shaders.properties`, a different concurrency model is enabled for compute shaders, allowing enhanced flexibility for shader developers. **This is an Iris-exclusive feature.**

For a given composite pass, a `glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)` command is issued **after the last compute pass for that composite pass**. As a result, no matter if a composite pass has a single corresponding compute pass or 27 corresponding compute passes, only one memory barrier is issued while executing that composite pass.

This ensures that all `texture()` calls and all `imageLoad()` / `imageStore()` calls receive up-to-date values following the execution of all compute passes for a given composite pass, as opposed to out-of-date or undefined values.

There are two important corrolaries of this changed memory barrier behavior:

#### The Sequential Dispatch Corrolary

A compute shader belonging to composite pass A is always executed before a compute shader belonging to composite pass B, if composite pass B is executed after composite pass A.

Sequential dispatch between two given compute passes is required if one of the given compute passes is dependent on the output of a the other given compute pass.

It is possible to define a compute pass without the corresponding composite pass being defined. As a result, it is possible to have both `composite.csh` and `composite1.csh` be defined without either `composite.fsh`/`composite.vsh` or `composite1.fsh`/`composite1.vsh` being defined. This allows exploiting the sequential dispatch corrolary without being restricted by the number of composite passes that the shader pack is utilizing, or the structuring of those composite passes relative to the compute passes.


#### The Parallel Dispatch Corrolary

A compute shader belonging to a given composite pass MAY be executed at the same time as another compute pass belonging to the same composite pass.

Parallel dispatch can lead to significantly increased performance because it allows the GPU to execute multiple compute shaders at the same time.

However, care must be taken with parallel dispatch because you are **bypassing the conventional safety guarantees of composite passes**.

As a result, if two parallel compute passes attempt to access the same image without using atomic operations, inconsistent behavior MAY result. This is highly dependent on drivers, FPS, operating system, hardware, and all sorts of other factors.

There are two ways to mitigate this issue:

1. Elminate resource sharing: Ensure that no resources are used at the same time by two compute passes.
2. Atomic-only resource sharing: Only utilize atomic operations to access a shared resource.


## Further reading

- An in-depth pair of blog posts touching on using advanced concurrency techniques in compute shaders specifically in the context of Minecraft path-tracing shaders has been published by BruceKnowsHow:
- [Good and Bad Conditional Branching in GPU Shaders](https://lavish-waitress-2da.notion.site/Good-and-Bad-Conditional-Branching-in-GPU-Shaders-17cca16e30be4e38baef9c9166ac4c24)
- [Branchless Multi-Bounce Path-Tracing with a Ray-Buffer](https://lavish-waitress-2da.notion.site/Branchless-Multi-Bounce-Path-Tracing-with-a-Ray-Buffer-c9cd87ff41bd455b8dd8d629011167b0)
12 changes: 8 additions & 4 deletions src/content/docs/reference/Shaders.Properties/blend.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ sidebar:
---

### `blend.<program>=<off|src dst srcA dstA>`
### `blend.<program>.<buffer>=<off|src dst srcA dstA>`

#### Location: shaders.properties

Controls the alpha blending for a specific gbuffers program, and optionally per-buffer.

Replace:
- `<program>` with a gbuffers program
- optionally `<buffer>` specifies the blending for a specific buffer (i.e. colortex5)

Setting the value to `off` will disable alpha blending, otherwise the blending parameters are specified:
- `src` is the source color multiplier
Expand All @@ -25,6 +23,12 @@ Setting the value to `off` will disable alpha blending, otherwise the blending p

Each of the parameters should be filled with one of the following: `ZERO`, `ONE`, `SRC_COLOR`, `ONE_MINUS_SRC_COLOR`, `DST_COLOR`, `ONE_MINUS_DST_COLOR`, `SRC_ALPHA`, `ONE_MINUS_SRC_ALPHA`, `DST_ALPHA`, `ONE_MINUS_DST_ALPHA`, `SRC_ALPHA_SATURATE`.

The default alpha blending parameters are: `SRC_ALPHA`, `ONE_MINUS_SRC_ALPHA`, `ONE`, `ONE_MINUS_SRC_ALPHA` respectively.
The default alpha blending parameters for transparent geometry are: `SRC_ALPHA`, `ONE_MINUS_SRC_ALPHA`, `ONE`, `ONE_MINUS_SRC_ALPHA` respectively.

More info on alpha blending can be found at the [Khronos Wiki](https://www.khronos.org/opengl/wiki/Blending)
More info on alpha blending can be found at the [Khronos Wiki](https://www.khronos.org/opengl/wiki/Blending)


## Per-Buffer Blending
#### `blend.<program>.<buffer>=<off|src dst srcA dstA>`

By specifying a buffer name (e.g. colortex5) in `<buffer>` you can apply the blending to a specific buffer only. Any buffers that aren't specified will use the program's blending attributes (see above).
102 changes: 102 additions & 0 deletions src/content/docs/reference/Shaders.Properties/custom_uniforms.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
title: Custom Uniforms
description: Custom Uniforms
sidebar:
label: Custom Uniforms
order: 1
---

##### `uniform.<float|int|bool|vec2|vec3|vec4>.<name>=<expression>`
##### `variable.<float|int|bool|vec2|vec3|vec4>.<name>=<expression>`

#### Location: shaders.properties

Iris lets you define custom uniforms which are evaluated on the CPU and uploaded on program change, rather than in shader code. This reduces the amount of duplicated code or unnecessary texture reads/writes as shaders cannot directly access variables across files.

Two types of values can be created: variables and uniforms. Uniforms are values which are calculated and uploaded to the GPU for shader programs to access. Variables are equivalent to uniforms, but are not uploaded to the GPU (they can be used as intermediate values).


## Construction
A uniform/variable can be either a `float`, `int`, `bool`, `vec2`, `vec3`, or `vec4` data type. Although you can access existing matrix uniforms, you cannot create custom matrix uniforms/variables.

Uniforms and variables can be constructed from the following:
- **Other uniform**s except dynamic uniforms (`entityColor`, `blockEntityId`, `fogMode`, `fogColor`, `chunkOffset`)
- **Literals** (number/boolean value) and `pi`
- Operators
- float/int/vector: `+`, `-`, `*`, `/`, `%` (remainder)
- boolean: `!`, `&&`, `||`
- any: `>`, `>=`, `<`, `<=`, `==`, `!=`
- Vector constructors (`vec2(x,y)`, `vec3(x,y,z)`, `vec4(x,y,z,w)`)
- Functions (see table)


## Element access
Vector elements can be accessed similar to GLSL (`.xyzw`, `.rgba`, `stpq`, and `.0123`). Swizzling is not supported, so only a single element can be pulled, for example `cameraPosition.y` would return the y component of `cameraPosition`. Only vector uniforms and variables can be accessed this way, intermidiate values cannot (e.g. `min(vec2(0.0, 1.0), vec2(1.0, 0.0)).x` is not allowed, instead store the result of the `min` to a variable and reference that with `.x`).

Matrix elements (from existing matrix uniforms only) can be accessed with the following syntax: `matrix.<row>.<column>` where `<row>` and `<column>` are replaced with the row/column index (starting at 0). For example `gbufferModelView.0.3` would return the value at the 1st row 4th column of `gbufferModelView`.

## Functions
The following functions are available to use in custom uniforms/variables.

| Function | Description |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `torad(deg)` / `radians(deg)` | Degrees to radians |
| `todeg(rad)` / `degrees(rad)` | Radians to degrees |
| `sin(x)` | Sine |
| `cos(x)` | Cosine |
| `tan(x)` | Tangent |
| `asin(x)` | Inverse sine |
| `acos(x)` | Inverse cosine |
| `atan(x)` | Inverse tangent |
| `atan(y, x)` / `atan2(y, x)` | Inverse tangent with 2 parameters |
| `exp(x)` | Exponential (e^x) |
| `pow(x, y)` | Power exponential (x^y) |
| `exp2(x)` | Power of 2 exponential (2^x) |
| `exp10(x)` | Power of 10 exponential (10^x) |
| `log(x)` | Natural logarithm (ln) |
| `log(base, value)` | Arbitrary base logarithm (log base) |
| `log2(x)` | Base 2 logarithm (log base 2) |
| `log10(x)` | Base 10 logarithm (log base 10) |
| `sqrt(x)` | Square root |
| `abs(x)` | Absolute value |
| `sign(x)` / `signum(x)` | Sign of `x` (either `-1`, `0`, or `1`) |
| `floor(x)` | Floor (nearest integer \<= `x`) |
| `ceil(x)` | Ceil (nearest integer \>= `x`) |
| `frac(x)` | Fractional component (after decimal point) |
| `min(x, y)` | Minimum value |
| `max(x, y)` | Maximum value |
| `clamp(x, min, max)` | Clamp `x` between `min` and `max` |
| `mix(x, y, a)` | Linear interpolation between `x` and `y` by `a` |
| `edge(k, x)` | `0` if `x < k`, otherwise `1` (equivalent to GLSL `step`) |
| `fmod(x, y)` | Floor modulus (`x - y * floor(x/y)`) |
| `random()` | Random float between `0` (inclusive) and `1` (exclusive) generated each frame |
| `random(min, max)` | Random float between `min` (inclusive) and `max` (exclusive) generated each frame |
| `randomInt()` | Random integer between `-2147483648` and `2147483647` generated each frame |
| `randomInt(min, max)` | Random integer between `min` and `max-1` generated each frame |
| `if(cond, val, [cond2, val2, ...], val_else)` | Returns the first `val` whose boolean `cond` is true, otherwise return `val_else` |
| `smooth([id], val, [fadeUpTime, [fadeDownTime]])` | Smooths `val` over time, fade times are halflife in seconds (default 1s), `id` is optional unique ID |
| `between(a, min, max)` | `true` if `a` is between `min` and `max` inclusive, otherwise `false` |
| `equals(a, b, epsilon)` | `true` if `abs(a-b) <= epsilon`, `false` otherwise |
| `in(x, val1, val2, ...)` | `true` if `x` equals any val, `false` otherwise |

Unless otherwise noted, each function can take in a float or int and outputs the same type. In addition, the following functions can work with vector inputs/output: `abs`, `floor`, `ceil`, `min`, `max`, `clamp`, `if`, `smooth`, `in`.


## Examples
Here, take some *yummy* ~~candy~~ examples! What, the white van? Ignore that, you like ~~candy~~ examples don't you?

```
uniform.bool.isOakBiome = in(biome, BIOME_FOREST, BIOME_DARK_FOREST)
uniform.bool.isHotBiome = in(biome_category, CAT_MESA, CAT_SAVANNA, CAT_DESERT)
uniform.float.sprintFactor = smooth(if(is_sprinting, 1.0, 0.0), 0.7, 0.3)
uniform.float.sunHeight = sin(2.0*pi * sunAngle)
variable.float.waterColorR = if(in(biome, BIOME_SWAMP), 0.38, in(biome, BIOME_LUKEWARM_OCEAN, BIOME_DEEP_LUKEWARM_OCEAN), 0.271, in(biome, BIOME_WARM_OCEAN), 0.263, in(biome, BIOME_COLD_OCEAN, BIOME_DEEP_COLD_OCEAN, BIOME_SNOWY_TAIGA, BIOME_SNOWY_BEACH), 0.239, in(biome, BIOME_FROZEN_RIVER, BIOME_FROZEN_OCEAN, BIOME_DEEP_FROZEN_OCEAN), 0.224, in(biome, BIOME_MEADOW), 0.055, in(biome, BIOME_MANGROVE_SWAMP), 0.227, 0.247)
variable.float.waterColorG = if(in(biome, BIOME_SWAMP), 0.482, in(biome, BIOME_LUKEWARM_OCEAN, BIOME_DEEP_LUKEWARM_OCEAN), 0.678, in(biome, BIOME_WARM_OCEAN), 0.835, in(biome, BIOME_COLD_OCEAN, BIOME_DEEP_COLD_OCEAN, BIOME_SNOWY_TAIGA, BIOME_SNOWY_BEACH), 0.341, in(biome, BIOME_FROZEN_RIVER, BIOME_FROZEN_OCEAN, BIOME_DEEP_FROZEN_OCEAN), 0.22, in(biome, BIOME_MEADOW), 0.306, in(biome, BIOME_MANGROVE_SWAMP), 0.478, 0.463)
variable.float.waterColorB = if(in(biome, BIOME_SWAMP), 0.392, in(biome, BIOME_LUKEWARM_OCEAN, BIOME_DEEP_LUKEWARM_OCEAN), 0.949, in(biome, BIOME_WARM_OCEAN), 0.933, in(biome, BIOME_COLD_OCEAN, BIOME_DEEP_COLD_OCEAN, BIOME_SNOWY_TAIGA, BIOME_SNOWY_BEACH), 0.839, in(biome, BIOME_FROZEN_RIVER, BIOME_FROZEN_OCEAN, BIOME_DEEP_FROZEN_OCEAN), 0.788, in(biome, BIOME_MEADOW), 0.812, in(biome, BIOME_MANGROVE_SWAMP), 0.416, 0.894)
uniform.vec3.waterColor = vec3(waterColorR, waterColorG, waterColorB)
```

See I told you it was *yummy*.
22 changes: 22 additions & 0 deletions src/content/docs/reference/Shaders.Properties/indirect_pass.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: indirect.pass
description: indirect.pass
sidebar:
label: indirect.pass
order: 2
badge:
text: Iris Only
variant: tip
---

#### `indirect.pass = <bufferObjectNumber> <offsetInBuffer>`

#### Location: shaders.properties

Allows you to dispatch a compute shader with the work group amount specified from a [SSBO](/reference/buffers/ssbo).

To use this, replace:
- `<bufferObjectNumber>` with the "index" of the SSBO
- `<offsetInBuffer>` with the offset to the work group count in bytes

The object at offset in the SSBO must be an `uvec3` which stores the number of work groups in each axis. ***If you do not do this, your PC will most likely crash trying to dispatch 2147483647^3 work groups. Don't do that.***
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: occlusion.culling
description: occlusion.culling
sidebar:
label: occlusion.culling
order: 2
badge:
text: Iris Only
variant: tip
---

### `occlusion.culling=<true|false>`

#### Location: shaders.properties

Disables occlusion culling, which culls geometry which is behind other opaque geometry. Only applies to the main pass ([gbuffers](/reference/programs/gbuffers)).

Notably this affects whether caves are rendered when above ground, and whether the surface is rendered when deep in a cave. Disabling this may help reduce light leaking in caves by covering the top of the shadow map with the surface. However this also renders dramatically more terrain which can hurt performance.
18 changes: 18 additions & 0 deletions src/content/docs/reference/Shaders.Properties/skipAllRendering.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: skipAllRendering
description: skipAllRendering
sidebar:
label: skipAllRendering
order: 2
badge:
text: Iris Only
variant: tip
---

### `skipAllRendering=<true|false>`

#### Location: shaders.properties

Disables most of the [gbuffers](/reference/programs/gbuffers) pass, including terrain, entities, and block entities. Does not disable post processing shaders or shadows.

This option is intended for path tracing packs which do not utilize the [gbuffers](/reference/programs/gbuffers) pass and wish to avoid that geometry being sent to the screen.

0 comments on commit 3f4e8a4

Please sign in to comment.