Skip to content

Commit

Permalink
Major refractors pt.2
Browse files Browse the repository at this point in the history
  • Loading branch information
IMS212 committed Mar 5, 2024
1 parent d602bfd commit bba7f8a
Show file tree
Hide file tree
Showing 752 changed files with 8,838 additions and 9,486 deletions.
8 changes: 4 additions & 4 deletions docs/usage/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Iris has some built-in functionality that can assist you in developing a shader

## Shader Code Transformation

Iris uses [glsl-transformer](https://github.com/IrisShaders/glsl-transformer) to apply various patches to the GLSL code of a shader pack before sending it to the driver for compilation. There are generally two types of patches being applied; those necessary for compatibility with Iris, and compatibility patches that are done to make sure the shader pack works on as many systems as possible. For reference, the compatibility patches can be found in [`CompatibilityTransformer`](/src/main/java/net/coderbot/iris/pipeline/transform/CompatibilityTransformer.java) while the other patches are grouped into the other files.
Iris uses [glsl-transformer](https://github.com/IrisShaders/glsl-transformer) to apply various patches to the GLSL code of a shader pack before sending it to the driver for compilation. There are generally two types of patches being applied; those necessary for compatibility with Iris, and compatibility patches that are done to make sure the shader pack works on as many systems as possible. For reference, the compatibility patches can be found in [`CompatibilityTransformer`](/src/main/java/net/irisshaders/iris/pipeline/transform/CompatibilityTransformer.java) while the other patches are grouped into the other files.

Some terms:

Expand All @@ -31,19 +31,19 @@ The goal is to present a maximally uniform interface to the shader pack by smoot

Naturally, shader packs that are currently in development could simply be fixed by their maintainers, but not all shader packs are still actively developed even if they have a significant following. Some shader packs don't test on certain systems which can also create incompatibilities that are often fixable through patching. **The compatibility patches are only applied if problematic pieces of code are detected, and they always print a warning message to the log prefixed with `(CompatibilityTransformer)` each time they do something**.

The following is a list of the compatibility patches that are applied to shader packs. Additional information on the specifics of each patch can be found in the [source code](/src/main/java/net/coderbot/iris/pipeline/transform/transformer/CompatibilityTransformer.java).
The following is a list of the compatibility patches that are applied to shader packs. Additional information on the specifics of each patch can be found in the [source code](/src/main/java/net/irisshaders/iris/pipeline/transform/transformer/CompatibilityTransformer.java).

- Empty external declarations, which are just a single semicolon at the global level `;`, are removed. This is a workaround for a bug where they are not recognized as legal external declarations by some drivers. A semicolon following a function definition like `void main() {};` is in fact not part of the function definition but its own external declaration, namely an empty one.
- The `const` keyword is removed from declaration (statements) that refer to `const` parameters in their initializer expression, the part that comes after the `=`. Parameters with the `const` qualifier are not constant but rather immutable, meaning they may not be assigned to. Declarations with `const` are, depending on the driver and GLSL version, treated as constant meaning they only accept expressions that can be evaluated at compile time. Immutable parameters don't fulfill this requirement and thus cause a compilation error when they are used in the initializer of a constant. This is done to ensure better compatibility drivers' varying behavior at different versions. See Section 4.3.2 on Constant Qualifiers and Section 4.3.3 on Constant Expressions in the GLSL 4.1 and 4.2 specifications for more information. Additionally, see https://wiki.shaderlabs.org/wiki/Compiler_Behavior_Notes for the varying behavior of drivers.
- When an input variable, declared with `in`, is declared and used in a geometry or fragment shader, but there is no corresponding output variable in the shader of the previous stage, some drivers will error. To mitigate this, the missing declaration is inserted and initialized with a default value at the top of the `main` function.
- When an input variable, declared with `in`, is declared and used in a geometry or fragment shader, but there is no corresponding output variable in the shader of the previous stage, some drivers will error. To mitigate this, the missing declaration is inserted and initialized with a default value at the top of the `main` function.
- If the out declaration does exist but is never assigned to, an initialization is created. If the out declaration has an array type, compatibility patching is skipped for it and a warning is produced.
- When the types of declared and used input and output variables don't match, some drivers will error. To mitigate this, the type of the declaration is changed to match the type in the later stage (the fragment shader). An internal variable with the original type is added so that the code can assign a value to it. At the end of the `main` function this value is either truncated or padded to patch the expected type.
- Unused functions are removed. Some drivers don't do certain semantic checks on unused functions which may result in errors when the code is then compiled with stricter drivers that do perform these checks before unused code removal. This heuristic is not perfect and may fail to remove unreachable functions that are used in another unreachable function.
- In struct bodies (of the form `{ <struct members> }`) unsized array specifiers are moved from the type to the identifier of the member. A member `int[] foo` is transformed into `int foo[]`. This is done because the specification only requires support for the latter form while the former is unsupported by some drivers.

### Version Statement

The version statement `#version <number> <profile>` where the number is required, but the profile is optionally one of `core` or `compatibility` is patched on versions starting with 1.17. For reference, the relevant code can be found in [`TransformPatcher`](/src/main/java/net/coderbot/iris/pipeline/transform/TransformPatcher.java) in the section afer `Root.indexBuildSession`. If the core profile is used or the profile is missing, and the version is at least 150, then only compatibility patches are applied, as long as the shader is not a vertex shader. On vertex shaders an exception is thrown in this case. They are required to either use a version lower than 330, which is then changed to be exactly 330, or declare the compatibility profile, which is then changed to the core profile.
The version statement `#version <number> <profile>` where the number is required, but the profile is optionally one of `core` or `compatibility` is patched on versions starting with 1.17. For reference, the relevant code can be found in [`TransformPatcher`](/src/main/java/net/irisshaders/iris/pipeline/transform/TransformPatcher.java) in the section afer `Root.indexBuildSession`. If the core profile is used or the profile is missing, and the version is at least 150, then only compatibility patches are applied, as long as the shader is not a vertex shader. On vertex shaders an exception is thrown in this case. They are required to either use a version lower than 330, which is then changed to be exactly 330, or declare the compatibility profile, which is then changed to the core profile.

The profile of compute shaders is always set to core.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

/**
* Deprecated interface, switch to {@link com.terraformersmc.modmenu.api.ModMenuApi} and {@link com.terraformersmc.modmenu.api.ConfigScreenFactory} instead
*
* <p>
* Will be removed in 1.18 snapshots
*/
@Deprecated
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/kroppeb/stareval/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public static <T> T make(T item, Consumer<T> init) {
init.accept(item);
return item;
}

}


Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package kroppeb.stareval.exception;

public abstract class ParseException extends Exception{
public abstract class ParseException extends Exception {
public ParseException() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@
public class BasicVariableExpression implements VariableExpression {
final private String name;
final private Type type;

public BasicVariableExpression(String name, Type type) {
this.name = name;
this.type = type;
}

@Override
public void evaluateTo(FunctionContext c, FunctionReturn r) {
c.getVariable(name).evaluateTo(c, r);
}

@Override
public Expression partialEval(FunctionContext context, FunctionReturn functionReturn) {
if(context.hasVariable(this.name)){
if (context.hasVariable(this.name)) {
context.getVariable(this.name).evaluateTo(context, functionReturn);
return type.createConstant(functionReturn);
}else{
} else {
return this;
}
}

}
9 changes: 5 additions & 4 deletions src/main/java/kroppeb/stareval/expression/CallExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@
public class CallExpression implements Expression {
private final TypedFunction function;
private final Expression[] arguments;

public CallExpression(TypedFunction function, Expression[] arguments) {
this.function = function;
this.arguments = arguments;
}

@Override
public void evaluateTo(FunctionContext context, FunctionReturn functionReturn) {
this.function.evaluateTo(this.arguments, context, functionReturn);
}
@Override

@Override
public void listVariables(Collection<? super VariableExpression> variables) {
for (Expression argument : this.arguments) {
argument.listVariables(variables);
Expand Down Expand Up @@ -61,7 +62,7 @@ public Expression partialEval(FunctionContext context, FunctionReturn functionRe
noneSimplified = false;
} else {
allFullySimplified = false;
if(simplified != this.arguments[i]){
if (simplified != this.arguments[i]) {
noneSimplified = false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

public abstract class ConstantExpression implements Expression {
private final Type type;

protected ConstantExpression(Type type) {
this.type = type;
}

public Type getType() {
return this.type;
}

@Override
public void listVariables(Collection<? super VariableExpression> variables) {
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/kroppeb/stareval/expression/Expression.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

public interface Expression {
void evaluateTo(FunctionContext context, FunctionReturn functionReturn);
default Expression partialEval(FunctionContext context, FunctionReturn functionReturn){

default Expression partialEval(FunctionContext context, FunctionReturn functionReturn) {
return this;
}

void listVariables(Collection<? super VariableExpression> variables);
}
20 changes: 10 additions & 10 deletions src/main/java/kroppeb/stareval/function/BasicFunctionContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,27 @@

public class BasicFunctionContext implements FunctionContext {
final private Map<String, Expression> variables = new Object2ObjectOpenHashMap<>();
public void setVariable(String name, Expression value){

public void setVariable(String name, Expression value) {
variables.put(name, value);
}
public void setIntVariable(String name, int value){

public void setIntVariable(String name, int value) {
setVariable(name, (VariableExpression) (c, r) -> r.intReturn = value);
}
public void setFloatVariable(String name, float value){
setVariable(name, (VariableExpression) (c,r) -> r.floatReturn = value);

public void setFloatVariable(String name, float value) {
setVariable(name, (VariableExpression) (c, r) -> r.floatReturn = value);
}

@Override
public Expression getVariable(String name) {
Expression expression = variables.get(name);
if(expression == null)
if (expression == null)
throw new RuntimeException("Variable hasn't been set: " + name);
return expression;
}

@Override
public boolean hasVariable(String name) {
return variables.containsKey(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@

public interface FunctionContext {
Expression getVariable(String name);

boolean hasVariable(String name);
}
91 changes: 48 additions & 43 deletions src/main/java/kroppeb/stareval/function/FunctionResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;

import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

Expand All @@ -13,8 +18,8 @@ public class FunctionResolver {
private final Map<String, Map<Type, List<Supplier<? extends TypedFunction>>>> dynamicFunctions;

public FunctionResolver(
Map<String, Map<Type, List<TypedFunction>>> functions,
Map<String, Map<Type, List<Supplier<? extends TypedFunction>>>> dynamicFunctions) {
Map<String, Map<Type, List<TypedFunction>>> functions,
Map<String, Map<Type, List<Supplier<? extends TypedFunction>>>> dynamicFunctions) {
this.functions = functions;
this.dynamicFunctions = dynamicFunctions;
}
Expand Down Expand Up @@ -49,6 +54,42 @@ public List<? extends TypedFunction> resolve(String name, Type returnType) {
return u;
}

public void logAllFunctions() {
final Set<String> names = new LinkedHashSet<>();
names.addAll(this.functions.keySet());
names.addAll(this.dynamicFunctions.keySet());
for (final String name : names) {
final Map<Type, List<TypedFunction>> overloads = new Object2ObjectLinkedOpenHashMap<>();
Map<Type, List<TypedFunction>> normal = this.functions.get(name);
if (normal != null)
overloads.putAll(normal);

Map<Type, List<Supplier<? extends TypedFunction>>> dynamic = this.dynamicFunctions.get(name);
if (dynamic != null)
overloads.putAll(
dynamic
.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue()
.stream()
.map(Supplier::get)
.collect(Collectors.toList())
)
)
);

for (Map.Entry<Type, List<TypedFunction>> returnTypeOverloads : overloads.entrySet()) {
for (TypedFunction typedFunction : returnTypeOverloads.getValue()) {
System.out.println(TypedFunction.format(typedFunction, name));
}
System.out.println();
}
System.out.println();
}
}

public static class Builder {
private final Map<String, List<TypedFunction>> functions = new Object2ObjectLinkedOpenHashMap<>();
private final Map<String, Map<Type, List<Supplier<? extends TypedFunction>>>> dynamicFunctions = new Object2ObjectLinkedOpenHashMap<>();
Expand All @@ -63,9 +104,9 @@ public <T extends TypedFunction> void addDynamic(String name, Type returnType, S

public void addDynamicFunction(String name, Type returnType, Supplier<? extends TypedFunction> function) {
this.dynamicFunctions
.computeIfAbsent(name, (n) -> new Object2ObjectLinkedOpenHashMap<>())
.computeIfAbsent(returnType, (n) -> new ObjectArrayList<>())
.add(function);
.computeIfAbsent(name, (n) -> new Object2ObjectLinkedOpenHashMap<>())
.computeIfAbsent(returnType, (n) -> new ObjectArrayList<>())
.add(function);
}

public void addFunction(String name, TypedFunction function) {
Expand All @@ -78,7 +119,7 @@ public FunctionResolver build() {
Map<Type, List<TypedFunction>> typeMap = new Object2ObjectLinkedOpenHashMap<>();
for (TypedFunction function : entry.getValue()) {
typeMap.computeIfAbsent(function.getReturnType(), i -> new ObjectArrayList<>())
.add(function);
.add(function);
}
functions.put(entry.getKey(), typeMap);
}
Expand All @@ -87,40 +128,4 @@ public FunctionResolver build() {
}
}

public void logAllFunctions() {
final Set<String> names = new LinkedHashSet<>();
names.addAll(this.functions.keySet());
names.addAll(this.dynamicFunctions.keySet());
for (final String name : names) {
final Map<Type, List<TypedFunction>> overloads = new Object2ObjectLinkedOpenHashMap<>();
Map<Type, List<TypedFunction>> normal = this.functions.get(name);
if (normal != null)
overloads.putAll(normal);

Map<Type, List<Supplier<? extends TypedFunction>>> dynamic = this.dynamicFunctions.get(name);
if (dynamic != null)
overloads.putAll(
dynamic
.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue()
.stream()
.map(Supplier::get)
.collect(Collectors.toList())
)
)
);

for (Map.Entry<Type, List<TypedFunction>> returnTypeOverloads : overloads.entrySet()) {
for (TypedFunction typedFunction : returnTypeOverloads.getValue()) {
System.out.println(TypedFunction.format(typedFunction, name));
}
System.out.println();
}
System.out.println();
}
}

}
Loading

0 comments on commit bba7f8a

Please sign in to comment.