Skip to content

Commit 35d428b

Browse files
authored
Merge branch 'dev' into interpreter
2 parents 046a823 + 6fc37a9 commit 35d428b

98 files changed

Lines changed: 2549 additions & 1920 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build.sbt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ lazy val commonSettings = Seq(
5858

5959
lazy val runnerSettings = Seq(libraryDependencies += "org.apache.logging.log4j" % "log4j-slf4j2-impl" % "2.24.3")
6060

61+
lazy val fs2Settings = Seq(libraryDependencies ++= Seq("co.fs2" %% "fs2-core" % "3.12.0", "co.fs2" %% "fs2-io" % "3.12.0"))
62+
6163
lazy val utility = (project in file("cyfra-utility"))
6264
.settings(commonSettings)
6365

@@ -91,6 +93,7 @@ lazy val foton = (project in file("cyfra-foton"))
9193

9294
lazy val examples = (project in file("cyfra-examples"))
9395
.settings(commonSettings, runnerSettings)
96+
.settings(libraryDependencies += "org.scala-lang.modules" % "scala-parallel-collections_3" % "1.2.0")
9497
.dependsOn(foton)
9598

9699
lazy val vscode = (project in file("cyfra-vscode"))
@@ -101,13 +104,17 @@ lazy val interpreter = (project in file("cyfra-interpreter"))
101104
.settings(commonSettings)
102105
.dependsOn(dsl, compiler)
103106

107+
lazy val fs2interop = (project in file("cyfra-fs2"))
108+
.settings(commonSettings, fs2Settings)
109+
.dependsOn(runtime)
110+
104111
lazy val e2eTest = (project in file("cyfra-e2e-test"))
105112
.settings(commonSettings, runnerSettings)
106-
.dependsOn(runtime, interpreter)
113+
.dependsOn(runtime, fs2interop, interpreter)
107114

108115
lazy val root = (project in file("."))
109116
.settings(name := "Cyfra")
110-
.aggregate(compiler, dsl, foton, core, runtime, vulkan, examples, interpreter)
117+
.aggregate(compiler, dsl, foton, core, runtime, vulkan, examples, fs2interop, interpreter)
111118

112119
e2eTest / Test / javaOptions ++= Seq("-Dorg.lwjgl.system.stackSize=1024", "-DuniqueLibraryNames=true")
113120

cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.computenode.cyfra.spirv
22

3+
import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform}
34
import io.computenode.cyfra.dsl.macros.FnCall.FnIdentifier
45
import io.computenode.cyfra.spirv.SpirvConstants.HEADER_REFS_TOP
56
import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction
@@ -16,16 +17,17 @@ private[cyfra] case class Context(
1617
voidTypeRef: Int = -1,
1718
voidFuncTypeRef: Int = -1,
1819
workerIndexRef: Int = -1,
19-
uniformVarRef: Int = -1,
20+
uniformVarRefs: Map[GUniform[?], Int] = Map.empty,
21+
bindingToStructType: Map[Int, Int] = Map.empty,
2022
constRefs: Map[(Tag[?], Any), Int] = Map(),
2123
exprRefs: Map[Int, Int] = Map(),
22-
inBufferBlocks: List[ArrayBufferBlock] = List(),
23-
outBufferBlocks: List[ArrayBufferBlock] = List(),
24+
bufferBlocks: Map[GBuffer[?], ArrayBufferBlock] = Map(),
2425
nextResultId: Int = HEADER_REFS_TOP,
2526
nextBinding: Int = 0,
2627
exprNames: Map[Int, String] = Map(),
27-
memberNames: Map[Int, String] = Map(),
28+
names: Set[String] = Set(),
2829
functions: Map[FnIdentifier, SprivFunction] = Map(),
30+
stringLiterals: Map[String, Int] = Map(),
2931
):
3032
def joinNested(ctx: Context): Context =
3133
this.copy(nextResultId = ctx.nextResultId, exprNames = ctx.exprNames ++ this.exprNames, functions = ctx.functions ++ this.functions)

cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvConstants.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ private[cyfra] object SpirvConstants:
99

1010
val BOUND_VARIABLE = "bound"
1111
val GLSL_EXT_NAME = "GLSL.std.450"
12+
val NON_SEMANTIC_DEBUG_PRINTF = "NonSemantic.DebugPrintf"
1213
val GLSL_EXT_REF = 1
1314
val TYPE_VOID_REF = 2
1415
val VOID_FUNC_TYPE_REF = 3
1516
val MAIN_FUNC_REF = 4
1617
val GL_GLOBAL_INVOCATION_ID_REF = 5
1718
val GL_WORKGROUP_SIZE_REF = 6
18-
val HEADER_REFS_TOP = 7
19+
val DEBUG_PRINTF_REF = 7
20+
21+
val HEADER_REFS_TOP = 8

cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ private[cyfra] object SpirvTypes:
5454
case LGBooleanTag => 4
5555
case v if v <:< LVecTag =>
5656
vecSize(v) * typeStride(v.typeArgs.head)
57+
case _ => 4
5758

5859
def typeStride(tag: Tag[?]): Int = typeStride(tag.tag)
5960

cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import io.computenode.cyfra.*
44
import io.computenode.cyfra.dsl.*
55
import io.computenode.cyfra.dsl.Expression.E
66
import io.computenode.cyfra.dsl.Value.Scalar
7+
import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform, WriteBuffer, WriteUniform}
8+
import io.computenode.cyfra.dsl.gio.GIO
79
import io.computenode.cyfra.dsl.struct.GStruct.*
810
import io.computenode.cyfra.dsl.struct.GStructSchema
911
import io.computenode.cyfra.spirv.Context
@@ -24,6 +26,28 @@ import scala.runtime.stdLibPatches.Predef.summon
2426

2527
private[cyfra] object DSLCompiler:
2628

29+
@tailrec
30+
private def getAllExprsFlattened(pending: List[GIO[?]], acc: List[E[?]], visitDetached: Boolean): List[E[?]] =
31+
pending match
32+
case Nil => acc
33+
case GIO.Pure(v) :: tail =>
34+
getAllExprsFlattened(tail, getAllExprsFlattened(v.tree, visitDetached) ::: acc, visitDetached)
35+
case GIO.FlatMap(v, n) :: tail =>
36+
getAllExprsFlattened(v :: n :: tail, acc, visitDetached)
37+
case GIO.Repeat(n, gio) :: tail =>
38+
val nAllExprs = getAllExprsFlattened(n.tree, visitDetached)
39+
getAllExprsFlattened(gio :: tail, nAllExprs ::: acc, visitDetached)
40+
case WriteBuffer(_, index, value) :: tail =>
41+
val indexAllExprs = getAllExprsFlattened(index.tree, visitDetached)
42+
val valueAllExprs = getAllExprsFlattened(value.tree, visitDetached)
43+
getAllExprsFlattened(tail, indexAllExprs ::: valueAllExprs ::: acc, visitDetached)
44+
case WriteUniform(_, value) :: tail =>
45+
val valueAllExprs = getAllExprsFlattened(value.tree, visitDetached)
46+
getAllExprsFlattened(tail, valueAllExprs ::: acc, visitDetached)
47+
case GIO.Printf(_, args*) :: tail =>
48+
val argsAllExprs = args.flatMap(a => getAllExprsFlattened(a.tree, visitDetached)).toList
49+
getAllExprsFlattened(tail, argsAllExprs ::: acc, visitDetached)
50+
2751
// TODO: Not traverse same fn scopes for each fn call
2852
private def getAllExprsFlattened(root: E[?], visitDetached: Boolean): List[E[?]] =
2953
var blockI = 0
@@ -33,7 +57,7 @@ private[cyfra] object DSLCompiler:
3357
def getAllScopesExprsAcc(toVisit: List[E[?]], acc: List[E[?]] = Nil): List[E[?]] = toVisit match
3458
case Nil => acc
3559
case e :: tail if visited.contains(e.treeid) => getAllScopesExprsAcc(tail, acc)
36-
case e :: tail =>
60+
case e :: tail => // todo i don't think this really works (tail not used???)
3761
if allScopesCache.contains(root.treeid) then return allScopesCache(root.treeid)
3862
val eScopes = e.introducedScopes
3963
val filteredScopes = if visitDetached then eScopes else eScopes.filterNot(_.isDetached)
@@ -47,33 +71,52 @@ private[cyfra] object DSLCompiler:
4771
allScopesCache(root.treeid) = result
4872
result
4973

50-
def compile(tree: Value, inTypes: List[Tag[?]], outTypes: List[Tag[?]], uniformSchema: GStructSchema[?]): ByteBuffer =
51-
val treeExpr = tree.tree
52-
val allExprs = getAllExprsFlattened(treeExpr, visitDetached = true)
74+
// So far only used for printf
75+
private def getAllStrings(pending: List[GIO[?]], acc: Set[String]): Set[String] =
76+
pending match
77+
case Nil => acc
78+
case GIO.FlatMap(v, n) :: tail =>
79+
getAllStrings(v :: n :: tail, acc)
80+
case GIO.Repeat(_, gio) :: tail =>
81+
getAllStrings(gio :: tail, acc)
82+
case GIO.Printf(format, _*) :: tail =>
83+
getAllStrings(tail, acc + format)
84+
case _ :: tail => getAllStrings(tail, acc)
85+
86+
def compile(bodyIo: GIO[?], bindings: List[GBinding[?]]): ByteBuffer =
87+
val allExprs = getAllExprsFlattened(List(bodyIo), Nil, visitDetached = true)
5388
val typesInCode = allExprs.map(_.tag).distinct
54-
val allTypes = (typesInCode ::: inTypes ::: outTypes).distinct
89+
val allTypes = (typesInCode ::: bindings.map(_.tag)).distinct
5590
def scalarTypes = allTypes.filter(_.tag <:< summon[Tag[Scalar]].tag)
5691
val (typeDefs, typedContext) = defineScalarTypes(scalarTypes, Context.initialContext)
92+
val allStrings = getAllStrings(List(bodyIo), Set.empty)
93+
val (stringDefs, ctxWithStrings) = defineStrings(allStrings.toList, typedContext)
94+
val (buffersWithIndices, uniformsWithIndices) = bindings.zipWithIndex
95+
.partition:
96+
case (_: GBuffer[?], _) => true
97+
case (_: GUniform[?], _) => false
98+
.asInstanceOf[(List[(GBuffer[?], Int)], List[(GUniform[?], Int)])]
99+
val uniforms = uniformsWithIndices.map(_._1)
100+
val uniformSchemas = uniforms.map(_.schema)
57101
val structsInCode =
58102
(allExprs.collect {
59103
case cs: ComposeStruct[?] => cs.resultSchema
60104
case gf: GetField[?, ?] => gf.resultSchema
61-
} :+ uniformSchema).distinct
62-
val (structDefs, structCtx) = defineStructTypes(structsInCode, typedContext)
63-
val structNames = getStructNames(structsInCode, structCtx)
64-
val (decorations, uniformDefs, uniformContext) = initAndDecorateUniforms(inTypes, outTypes, structCtx)
65-
val (uniformStructDecorations, uniformStructInsns, uniformStructContext) = createAndInitUniformBlock(uniformSchema, uniformContext)
66-
val blockNames = getBlockNames(uniformContext, uniformSchema)
105+
} ::: uniformSchemas).distinct
106+
val (structDefs, structCtx) = defineStructTypes(structsInCode, ctxWithStrings)
107+
val (structNames, structNamesCtx) = getStructNames(structsInCode, structCtx)
108+
val (decorations, uniformDefs, uniformContext) = initAndDecorateBuffers(buffersWithIndices, structNamesCtx)
109+
val (uniformStructDecorations, uniformStructInsns, uniformStructContext) = createAndInitUniformBlocks(uniformsWithIndices, uniformContext)
110+
val blockNames = getBlockNames(uniformContext, uniforms)
67111
val (inputDefs, inputContext) = createInvocationId(uniformStructContext)
68112
val (constDefs, constCtx) = defineConstants(allExprs, inputContext)
69113
val (varDefs, varCtx) = defineVarNames(constCtx)
70-
val resultType = tree.tree.tag
71-
val (main, ctxAfterMain) = compileMain(tree, resultType, varCtx)
114+
val (main, ctxAfterMain) = compileMain(bodyIo, varCtx)
72115
val (fnTypeDefs, fnDefs, ctxWithFnDefs) = compileFunctions(ctxAfterMain)
73116
val nameDecorations = getNameDecorations(ctxWithFnDefs)
74117

75118
val code: List[Words] =
76-
SpirvProgramCompiler.headers ::: blockNames ::: nameDecorations ::: structNames ::: SpirvProgramCompiler.workgroupDecorations :::
119+
SpirvProgramCompiler.headers ::: stringDefs ::: blockNames ::: nameDecorations ::: structNames ::: SpirvProgramCompiler.workgroupDecorations :::
77120
decorations ::: uniformStructDecorations ::: typeDefs ::: structDefs ::: fnTypeDefs ::: uniformDefs ::: uniformStructInsns ::: inputDefs :::
78121
constDefs ::: varDefs ::: main ::: fnDefs
79122

cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package io.computenode.cyfra.spirv.compilers
33
import io.computenode.cyfra.dsl.*
44
import io.computenode.cyfra.dsl.Expression.*
55
import io.computenode.cyfra.dsl.Value.*
6-
import io.computenode.cyfra.dsl.collections.GArray.GArrayElem
6+
import io.computenode.cyfra.dsl.binding.*
77
import io.computenode.cyfra.dsl.collections.GSeq
88
import io.computenode.cyfra.dsl.macros.Source
99
import io.computenode.cyfra.dsl.struct.GStruct.{ComposeStruct, GetField}
@@ -22,10 +22,6 @@ private[cyfra] object ExpressionCompiler:
2222

2323
val WorkerIndexTag = "worker_index"
2424

25-
val WorkerIndex: Int32 = Int32(Dynamic(WorkerIndexTag))
26-
val UniformStructRefTag = "uniform_struct"
27-
def UniformStructRef[G <: Value: Tag] = Dynamic(UniformStructRefTag)
28-
2925
private def binaryOpOpcode(expr: BinaryOpExpression[?]) = expr match
3026
case _: Sum[?] => (Op.OpIAdd, Op.OpFAdd)
3127
case _: Diff[?] => (Op.OpISub, Op.OpFSub)
@@ -110,11 +106,11 @@ private[cyfra] object ExpressionCompiler:
110106
val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (c.treeid -> constRef))
111107
(List(), updatedContext)
112108

113-
case d @ Dynamic(WorkerIndexTag) =>
114-
(Nil, ctx.copy(exprRefs = ctx.exprRefs + (d.treeid -> ctx.workerIndexRef)))
109+
case w @ InvocationId =>
110+
(Nil, ctx.copy(exprRefs = ctx.exprRefs + (w.treeid -> ctx.workerIndexRef)))
115111

116-
case d @ Dynamic(UniformStructRefTag) =>
117-
(Nil, ctx.copy(exprRefs = ctx.exprRefs + (d.treeid -> ctx.uniformVarRef)))
112+
case d @ ReadUniform(u) =>
113+
(Nil, ctx.copy(exprRefs = ctx.exprRefs + (d.treeid -> ctx.uniformVarRefs(u))))
118114

119115
case c: ConvertExpression[?, ?] =>
120116
compileConvertExpression(c, ctx)
@@ -293,19 +289,19 @@ private[cyfra] object ExpressionCompiler:
293289
case fc: FunctionCall[?] =>
294290
compileFunctionCall(fc, ctx)
295291

296-
case ga @ GArrayElem(index, i) =>
292+
case ReadBuffer(buffer, i) =>
297293
val instructions = List(
298294
Instruction(
299295
Op.OpAccessChain,
300296
List(
301-
ResultRef(ctx.uniformPointerMap(ctx.valueTypeMap(ga.tag.tag))),
297+
ResultRef(ctx.uniformPointerMap(ctx.valueTypeMap(buffer.tag.tag))),
302298
ResultRef(ctx.nextResultId),
303-
ResultRef(ctx.inBufferBlocks(index).blockVarRef),
299+
ResultRef(ctx.bufferBlocks(buffer).blockVarRef),
304300
ResultRef(ctx.constRefs((Int32Tag, 0))),
305301
ResultRef(ctx.exprRefs(i.treeid)),
306302
),
307303
),
308-
Instruction(Op.OpLoad, List(IntWord(ctx.valueTypeMap(ga.tag.tag)), ResultRef(ctx.nextResultId + 1), ResultRef(ctx.nextResultId))),
304+
Instruction(Op.OpLoad, List(IntWord(ctx.valueTypeMap(buffer.tag.tag)), ResultRef(ctx.nextResultId + 1), ResultRef(ctx.nextResultId))),
309305
)
310306
val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> (ctx.nextResultId + 1)), nextResultId = ctx.nextResultId + 2)
311307
(instructions, updatedContext)
@@ -330,21 +326,23 @@ private[cyfra] object ExpressionCompiler:
330326
)
331327
val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (cs.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1)
332328
(insns, updatedContext)
333-
case gf @ GetField(dynamic @ Dynamic(UniformStructRefTag), fieldIndex) =>
329+
330+
case gf @ GetField(binding @ ReadUniform(uf), fieldIndex) =>
334331
val insns: List[Instruction] = List(
335332
Instruction(
336333
Op.OpAccessChain,
337334
List(
338335
ResultRef(ctx.uniformPointerMap(ctx.valueTypeMap(gf.tag.tag))),
339336
ResultRef(ctx.nextResultId),
340-
ResultRef(ctx.uniformVarRef),
337+
ResultRef(ctx.uniformVarRefs(uf)),
341338
ResultRef(ctx.constRefs((Int32Tag, gf.fieldIndex))),
342339
),
343340
),
344341
Instruction(Op.OpLoad, List(IntWord(ctx.valueTypeMap(gf.tag.tag)), ResultRef(ctx.nextResultId + 1), ResultRef(ctx.nextResultId))),
345342
)
346343
val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> (ctx.nextResultId + 1)), nextResultId = ctx.nextResultId + 2)
347344
(insns, updatedContext)
345+
348346
case gf: GetField[?, ?] =>
349347
val insns: List[Instruction] = List(
350348
Instruction(

0 commit comments

Comments
 (0)