Start work on shader pipeline system

- Unbulit, untested so far
 - Will ultimately supersede shader contexts/templating
 - Laying framework for better compile errors via Span.java
This commit is contained in:
JozsefA 2021-06-25 14:10:19 -07:00
parent d30ff87203
commit 2325db4cdf
10 changed files with 307 additions and 6 deletions

View file

@ -10,13 +10,13 @@ import java.util.regex.Pattern;
public class TaggedStruct {
// https://regexr.com/5t207
static final Pattern taggedStruct = Pattern.compile("#\\[(\\w*)]\\s*struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d \\t#\\[\\](),;\\n]*)}\\s*;");
public static final Pattern taggedStruct = Pattern.compile("#\\[(\\w*)]\\s*struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d \\t#\\[\\](),;\\n]*)}\\s*;");
int srcStart, srcEnd;
String source;
String tag;
String name;
String body;
public int srcStart, srcEnd;
public String source;
public String tag;
public String name;
public String body;
List<TaggedField> fields = new ArrayList<>(4);
Map<String, String> fields2Types = new HashMap<>();

View file

@ -0,0 +1,20 @@
package com.jozufozu.flywheel.backend.pipeline;
import com.jozufozu.flywheel.backend.pipeline.span.Span;
import java.util.regex.Pattern;
public class ShaderFunction {
public static final Pattern assignment = Pattern.compile("(\\w+)\\s*=");
private final Span returnType;
private final Span name;
private final Span body;
public ShaderFunction(Span self, Span returnType, Span name, Span body) {
this.returnType = returnType;
this.name = name;
this.body = body;
}
}

View file

@ -0,0 +1,42 @@
package com.jozufozu.flywheel.backend.pipeline;
import com.jozufozu.flywheel.backend.loading.Program;
import com.jozufozu.flywheel.backend.loading.TaggedField;
import com.jozufozu.flywheel.backend.loading.TypeHelper;
import com.jozufozu.flywheel.backend.pipeline.span.Span;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ShaderStruct {
// https://regexr.com/5t207
public static final Pattern struct = Pattern.compile("struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d \\t#\\[\\](),;\\n]*)}\\s*;");
public Span name;
public Span body;
List<StructField> fields = new ArrayList<>(4);
Map<String, String> fields2Types = new HashMap<>();
public ShaderStruct(Span self, Span name, Span body) {
Matcher fielder = StructField.fieldPattern.matcher(body.getValue());
while (fielder.find()) {
fields.add(new StructField(fielder));
fields2Types.put(fielder.group(2), fielder.group(1));
}
}
public void addPrefixedAttributes(Program builder, String prefix) {
for (StructField field : fields) {
int attributeCount = TypeHelper.getAttributeCount(field.type);
builder.addAttribute(prefix + field.name, attributeCount);
}
}
}

View file

@ -0,0 +1,108 @@
package com.jozufozu.flywheel.backend.pipeline;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import com.jozufozu.flywheel.backend.ShaderSources;
import com.jozufozu.flywheel.backend.pipeline.span.ErrorSpan;
import com.jozufozu.flywheel.backend.pipeline.span.Span;
import com.jozufozu.flywheel.backend.pipeline.span.StringSpan;
import net.minecraft.util.ResourceLocation;
public class SourceFile {
// #use "valid_namespace:valid/path_to_file.glsl"
private static final Pattern includePattern = Pattern.compile("#use \"(\\w+:[\\w./]+)\"");
// https://regexr.com/60n3d
public static final Pattern functionDeclaration = Pattern.compile("(\\w+)\\s+(\\w+)\\s*\\(([\\w,\\s]*)\\)\\s*\\{");
public static final Pattern versionDetector = Pattern.compile("#version[^\\n]*");
public final ResourceLocation name;
private final String source;
private final ShaderSources loader;
private final Map<String, ShaderFunction> functions = new HashMap<>();
public SourceFile(ShaderSources loader, ResourceLocation name, String source) {
this.loader = loader;
this.name = name;
this.source = source;
parseFunctions();
}
public String getSource() {
return source;
}
protected void parseFunctions() {
Matcher matcher = functionDeclaration.matcher(source);
while (matcher.find()) {
Span type = Span.fromMatcherGroup(this, matcher, 1);
Span name = Span.fromMatcherGroup(this, matcher, 2);
int blockStart = matcher.end();
int blockEnd = findEndOfBlock(blockStart);
Span self;
Span body;
if (blockEnd > blockStart) {
self = new StringSpan(this, matcher.start(), blockEnd);
body = new StringSpan(this, blockStart, blockEnd);
} else {
self = new ErrorSpan(this, matcher.start(), matcher.end());
body = new ErrorSpan(this, blockStart);
}
ShaderFunction function = new ShaderFunction(self, type, name, body);
functions.put(name.getValue(), function);
}
}
private int findEndOfBlock(int end) {
char[] rest = source.substring(end).toCharArray();
int blockDepth = 0;
for (int i = 0; i < rest.length; i++) {
char ch = rest[i];
if (ch == '{') blockDepth++;
if (ch == '}') blockDepth--;
if (blockDepth < 0) {
return end + i;
}
}
return -1;
}
public String printSource() {
StringBuilder builder = new StringBuilder();
builder.append("Source for shader '").append(name).append("':\n");
int i = 1;
for (String s : source.split("\n")) {
builder.append(String.format("%1$4s: ", i++))
.append(s)
.append('\n');
}
return builder.toString();
}
public static Stream<String> lines(String s) {
return new BufferedReader(new StringReader(s)).lines();
}
}

View file

@ -0,0 +1,35 @@
package com.jozufozu.flywheel.backend.pipeline;
import com.jozufozu.flywheel.backend.loading.LayoutTag;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StructField {
public static final Pattern fieldPattern = Pattern.compile("(\\S+)\\s*(\\S+);");
public String name;
public String type;
public LayoutTag layout;
public StructField(Matcher fieldMatcher) {
type = fieldMatcher.group(2);
name = fieldMatcher.group(3);
}
public String getName() {
return name;
}
public String getType() {
return type;
}
@Override
public String toString() {
return "TaggedField{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
'}';
}
}

View file

@ -0,0 +1,16 @@
package com.jozufozu.flywheel.backend.pipeline;
import com.jozufozu.flywheel.core.shader.IMultiProgram;
import com.jozufozu.flywheel.core.shader.StateSensitiveMultiProgram;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import javax.annotation.Nullable;
public class WorldShaderPipeline<P extends WorldProgram> {
@Nullable // TODO: temporary null return
public IMultiProgram<P> compile(SourceFile file) {
return null;
}
}

View file

@ -0,0 +1,7 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
package com.jozufozu.flywheel.backend.pipeline;
import mcp.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;

View file

@ -0,0 +1,18 @@
package com.jozufozu.flywheel.backend.pipeline.span;
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
public class ErrorSpan extends Span {
public ErrorSpan(SourceFile in, int loc) {
super(in, loc, loc);
}
public ErrorSpan(SourceFile in, int start, int end) {
super(in, start, end);
}
@Override
public String getValue() {
return "";
}
}

View file

@ -0,0 +1,40 @@
package com.jozufozu.flywheel.backend.pipeline.span;
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
import java.util.regex.Matcher;
public abstract class Span {
protected final SourceFile in;
protected final int start;
protected final int end;
public Span(SourceFile in, int start, int end) {
this.in = in;
this.start = start;
this.end = end;
}
public SourceFile getSourceFile() {
return in;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
public abstract String getValue();
public static Span fromMatcherGroup(SourceFile src, Matcher m, int group) {
return new StringSpan(src, m.start(group), m.end(group));
}
public static Span fromMatcher(SourceFile src, Matcher m) {
return new StringSpan(src, m.start(), m.end());
}
}

View file

@ -0,0 +1,15 @@
package com.jozufozu.flywheel.backend.pipeline.span;
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
public class StringSpan extends Span {
public StringSpan(SourceFile in, int start, int end) {
super(in, start, end);
}
@Override
public String getValue() {
return in.getSource().substring(start, end);
}
}