Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement HXSL Syntax.code support #1264

Merged
merged 2 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion hxsl/Ast.hx
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ enum TExprDef {
TWhile( e : TExpr, loop : TExpr, normalWhile : Bool );
TMeta( m : String, args : Array<Const>, e : TExpr );
TField( e : TExpr, name : String );
TSyntax(target : String, code : String, args : Array<SyntaxArg> ); // target = "code" should be treated as "insert regardless of target"
}

typedef TVar = {
Expand Down Expand Up @@ -313,6 +314,17 @@ enum TGlobal {
UnpackUnorm4x8;
}

enum SyntaxArgAccess {
Read;
Write;
ReadWrite;
}

typedef SyntaxArg = {
e: TExpr,
access: SyntaxArgAccess,
}

enum Component {
X;
Y;
Expand Down Expand Up @@ -538,7 +550,7 @@ class Tools {
if( hasSideEffect(p) )
return true;
return false;
case TVarDecl(_), TDiscard, TContinue, TBreak, TReturn(_):
case TVarDecl(_), TDiscard, TContinue, TBreak, TReturn(_), TSyntax(_, _, _):
return true;
case TSwitch(e, cases, def):
for( c in cases ) {
Expand Down Expand Up @@ -582,6 +594,7 @@ class Tools {
case TConst(_), TVar(_), TGlobal(_), TDiscard, TContinue, TBreak:
case TMeta(_, _, e): f(e);
case TField(e, _): f(e);
case TSyntax(_, _, args): for (arg in args) f(arg.e);
}
}

Expand All @@ -604,6 +617,7 @@ class Tools {
case TConst(_), TVar(_), TGlobal(_), TDiscard, TContinue, TBreak: e.e;
case TMeta(m, args, e): TMeta(m, args, f(e)); // don't map args
case TField(e, name): TField(f(e), name);
case TSyntax(target, code, args): TSyntax(target, code, [for (arg in args) ({ e : f(arg.e), access : arg.access })]);
}
return { e : ed, t : e.t, p : e.p };
}
Expand Down
24 changes: 24 additions & 0 deletions hxsl/Checker.hx
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,30 @@ class Checker {
// not closure support
error("Global function must be called immediately", e.pos);
}
case ECall({ expr: EField({ expr: EIdent("Syntax") }, target) }, args):
if ( args.length == 0 )
error("Syntax." + target + " should have a string as first argument", e.pos);
var code = switch ( args[0].expr ) {
case EConst(CString(code)): code;
default: error("Syntax." + target + " should have a string as first argument", args[0].pos);
}
var sargs: Array<Ast.SyntaxArg> = [];
for ( i in 1...args.length ) {
var arg = args[i];
switch ( arg.expr ) {
case EMeta(flags = ("rw"|"r"|"w"), _, flaggedArg):
sargs.push({ e : typeExpr(flaggedArg, Value), access : switch( flags ) {
case "r": Read;
case "w": Write;
case "rw": ReadWrite;
default: throw "assert";
}
});
default:
error("Syntax." + target + " arguments should have an access meta of @r, @w or @rw", arg.pos);
}
}
return { e: TSyntax(target, code, sargs), t: TVoid, p: e.pos };
case ECall(e1, args):
function makeCall(e1) {
return switch( e1.t ) {
Expand Down
23 changes: 23 additions & 0 deletions hxsl/Dce.hx
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,29 @@ class Dce {
check(val, writeTo, isAffected);
writeTo.pop();
isAffected.append(v,15);
case TSyntax(_, _, args):
for ( arg in args ) {
if ( arg.access != Read ) {
var tvars : Array<VarDeps> = [];
function findTVars( e : TExpr ) {
switch ( e.e ) {
case TVar(v): tvars.push(get(v));
default: e.iter(findTVars);
}
}
findTVars(arg.e);
for ( v in tvars ) {
writeTo.push(v, 15);
for ( arg2 in args ) {
if ( arg2.access != Write ) check(arg2.e, writeTo, isAffected);
}
writeTo.pop();
isAffected.append(v, 15);
}
} else {
check(arg.e, writeTo, isAffected);
}
}
default:
e.iter(check.bind(_, writeTo, isAffected));
}
Expand Down
2 changes: 2 additions & 0 deletions hxsl/Eval.hx
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,8 @@ class Eval {
TMeta(name, args, e2);
case TField(e, name):
TField(evalExpr(e), name);
case TSyntax(target, code, args):
TSyntax(target, code, [for ( arg in args ) ({ e : evalExpr(arg.e), access : arg.access })]);
};
return { e : d, t : t, p : e.p }
}
Expand Down
16 changes: 16 additions & 0 deletions hxsl/GlslOut.hx
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,22 @@ class GlslOut {
addExpr(val, tabs);
add(".");
add(name);
case TSyntax("code" | "glsl", code, args):
var pos = 0;
var argRegex = ~/{(\d+)}/g;
while ( argRegex.matchSub(code, pos) ) {
var matchPos = argRegex.matchedPos();
add(code.substring(pos, matchPos.pos));
var index = Std.parseInt(argRegex.matched(1));
// if (index >= args.length) throw "Attempting to use substitution index of " + index + ", which is out of bounds of argument list";
if ( index < args.length )
addValue(args[index].e, tabs);

pos = matchPos.pos + matchPos.len;
}
add(code.substr(pos));
case TSyntax(_, _, _):
// Do nothing: Code for other language
}
}

Expand Down
16 changes: 16 additions & 0 deletions hxsl/HlslOut.hx
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,22 @@ class HlslOut {
addValue(e, tabs);
add(".");
add(f);
case TSyntax("code" | "hlsl", code, args):
var pos = 0;
var argRegex = ~/{(\d+)}/g;
while ( argRegex.matchSub(code, pos) ) {
var matchPos = argRegex.matchedPos();
add(code.substring(pos, matchPos.pos));
var index = Std.parseInt(argRegex.matched(1));
// if (index >= args.length) throw "Attempting to use substitution index of " + index + ", which is out of bounds of argument list";
if ( index < args.length )
addValue(args[index].e, tabs);

pos = matchPos.pos + matchPos.len;
}
add(code.substr(pos));
case TSyntax(_, _, _):
// Do nothing: Code for other language
}
}

Expand Down
37 changes: 36 additions & 1 deletion hxsl/Linker.hx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ private class ShaderInfos {
public var onStack : Bool;
public var hasDiscard : Bool;
public var isCompute : Bool;
public var hasSyntax : Bool;
public var marked : Null<Bool>;
public function new(n, v) {
this.name = n;
Expand Down Expand Up @@ -235,11 +236,45 @@ class Linker {
locals.set(v.id, true);
case TFor(v, _, _):
locals.set(v.id, true);
case TSyntax(target, code, args):
var mappedArgs: Array<SyntaxArg> = [];
for ( arg in args ) {
var e = switch ( arg.access ) {
case Read:
mapExprVar(arg.e);
case Write:
var e = curShader != null ? mapSyntaxWrite(arg.e) : arg.e;
mapExprVar(e);
case ReadWrite:
// Make sure syntax writes are appended after reads.
var e = mapExprVar(arg.e);
if (curShader != null) e = mapSyntaxWrite(e);
e;
}
mappedArgs.push({ e: e, access: arg.access });
}
if ( curShader != null ) curShader.hasSyntax = true;
return { e : TSyntax(target, code, mappedArgs), t : e.t, p : e.p };
default:
}
return e.map(mapExprVar);
}

function mapSyntaxWrite( e : TExpr ) {
switch ( e.e ) {
case TVar(v):
var v = allocVar(v, e.p);
if( !curShader.writeMap.exists(v.id) ) {
debug(curShader.name + " syntax write " + v.path);
curShader.writeMap.set(v.id, v);
curShader.writeVars.push(v);
}
return { e : TVar(v.v), t : v.v.type, p : e.p };
default:
return e.map(mapSyntaxWrite);
}
}

function addShader( name : String, vertex : Null<Bool>, e : TExpr, p : Int ) {
var s = new ShaderInfos(name, vertex);
curShader = s;
Expand Down Expand Up @@ -414,7 +449,7 @@ class Linker {

// force shaders containing discard to be included
for( s in shaders )
if( s.hasDiscard || s.isCompute ) {
if( s.hasDiscard || s.isCompute || s.hasSyntax ) {
initDependencies(s);
entry.deps.set(s, true);
}
Expand Down
14 changes: 14 additions & 0 deletions hxsl/Printer.hx
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,20 @@ class Printer {
addExpr(e, tabs);
add(".");
add(name);
case TSyntax(target, code, args):
add("Syntax.");
add(target);
add("(");
addConst(CString(code));
for ( arg in args ) {
switch ( arg.access ) {
case Read: add(", @r ");
case Write: add(", @w ");
case ReadWrite: add(", @rw ");
}
addExpr(arg.e, tabs);
}
add(")");
}

}
Expand Down
15 changes: 15 additions & 0 deletions hxsl/Serializer.hx
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,13 @@ class Serializer {
case TField(e,name):
writeExpr(e);
writeString(name);
case TSyntax(target, code, args):
writeString(target);
writeString(code);
writeArr(args, (arg) -> {
writeExpr(arg.e);
out.addByte(arg.access.getIndex());
});
}
writeType(e.t);
// no position
Expand Down Expand Up @@ -391,6 +398,14 @@ class Serializer {
case 19: TWhile(readExpr(), readExpr(), input.readByte() != 0);
case 20: TMeta(readString(), readArr(readConst), readExpr());
case 21: TField(readExpr(), readString());
case 22: TSyntax(readString(), readString(), readArr(() -> {
return {
e: readExpr(),
access: Ast.SyntaxArgAccess.createByIndex(input.readByte()),
read: false,
write: false,
};
}));
default: throw "assert";
}
return {
Expand Down
24 changes: 24 additions & 0 deletions hxsl/Splitter.hx
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,30 @@ class Splitter {
inf.local = true;
inf.write++;
checkExpr(loop);
case TSyntax(_, _, args):
var arg : Ast.SyntaxArg = null;
function checkSyntaxExpr( e : Ast.TExpr) {
switch ( e.e ) {
case TVar(v):
var inf = get(v);
// inf.read is decremented in order to keep accurate count of reads
// as it will be incremented by checkExpr afterwards
switch ( arg.access ) {
case Read: inf.read--;
case Write: inf.write++;
case ReadWrite:
inf.read--;
inf.write++;
}
default:
e.iter(checkSyntaxExpr);
}
}
for (i in 0...args.length) {
arg = args[i];
checkSyntaxExpr(arg.e);
checkExpr(arg.e);
}
default:
e.iter(checkExpr);
}
Expand Down