From b2029b7f9abca45182d4f9b6c06575065c870c73 Mon Sep 17 00:00:00 2001 From: spamegg Date: Mon, 16 Jun 2025 13:12:11 +0300 Subject: [PATCH 01/59] convert to new Scala 3 syntax, fix warnings, restructure test directories and packages --- .scalafmt.conf | 1 + .../cyfra/spirv/BlockBuilder.scala | 10 +- .../io/computenode/cyfra/spirv/Context.scala | 2 +- .../io/computenode/cyfra/spirv/Opcodes.scala | 2 +- .../computenode/cyfra/spirv/SpirvTypes.scala | 22 ++-- .../cyfra/spirv/compilers/DSLCompiler.scala | 18 ++- .../spirv/compilers/ExpressionCompiler.scala | 114 +++++++++--------- .../spirv/compilers/ExtFunctionCompiler.scala | 2 +- .../spirv/compilers/FunctionCompiler.scala | 4 +- .../cyfra/spirv/compilers/GSeqCompiler.scala | 4 +- .../spirv/compilers/GStructCompiler.scala | 10 +- .../compilers/SpirvProgramCompiler.scala | 20 +-- .../cyfra/spirv/compilers/WhenCompiler.scala | 4 +- .../io/computenode/cyfra/dsl/Algebra.scala | 20 +-- .../io/computenode/cyfra/dsl/Control.scala | 2 +- .../io/computenode/cyfra/dsl/Expression.scala | 18 +-- .../io/computenode/cyfra/dsl/Functions.scala | 2 +- .../scala/io/computenode/cyfra/dsl/GSeq.scala | 24 ++-- .../io/computenode/cyfra/dsl/GStruct.scala | 8 +- .../io/computenode/cyfra/dsl/Value.scala | 2 +- .../computenode/cyfra/dsl/macros/FnCall.scala | 2 +- .../computenode/cyfra/dsl/macros/Source.scala | 10 +- .../computenode/cyfra/dsl/macros/Util.scala | 4 +- .../cyfra/{ => e2e}/ArithmeticTests.scala | 0 .../cyfra/{ => e2e}/FunctionsTests.scala | 0 .../cyfra/{ => e2e}/GSeqTests.scala | 0 .../cyfra/{ => e2e}/GStructTests.scala | 0 .../cyfra/{ => e2e}/ImageTests.scala | 2 +- .../cyfra/{ => e2e}/WhenTests.scala | 0 .../cyfra/{ => e2e}/juliaset/JuliaSet.scala | 3 +- .../vulkan/SequenceExecutorTest.scala | 3 +- .../samples/cyfra/oldsamples/Raytracing.scala | 6 +- .../foton/animation/AnimationRenderer.scala | 2 +- .../foton/rt/shapes/ShapeCollection.scala | 2 +- .../cyfra/runtime/Executable.scala | 2 +- .../computenode/cyfra/runtime/GFunction.scala | 4 +- .../computenode/cyfra/runtime/mem/GMem.scala | 4 +- .../cyfra/runtime/mem/Vec4FloatMem.scala | 3 +- .../cyfra/utility/ImageUtility.scala | 4 +- .../cyfra/vulkan/VulkanContext.scala | 2 +- .../cyfra/vulkan/command/Fence.scala | 6 +- .../vulkan/compute/ComputePipeline.scala | 2 +- .../cyfra/vulkan/core/DebugCallback.scala | 3 +- .../cyfra/vulkan/core/Device.scala | 5 +- .../cyfra/vulkan/core/Instance.scala | 10 +- .../vulkan/executor/AbstractExecutor.scala | 2 +- .../cyfra/vulkan/executor/MapExecutor.scala | 2 +- .../vulkan/executor/SequenceExecutor.scala | 4 +- .../computenode/cyfra/vulkan/util/Util.scala | 2 +- .../cyfra/vulkan/util/VulkanObject.scala | 3 +- .../vulkan/util/VulkanObjectHandle.scala | 6 +- 51 files changed, 186 insertions(+), 201 deletions(-) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/{ => e2e}/ArithmeticTests.scala (100%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/{ => e2e}/FunctionsTests.scala (100%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/{ => e2e}/GSeqTests.scala (100%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/{ => e2e}/GStructTests.scala (100%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/{ => e2e}/ImageTests.scala (98%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/{ => e2e}/WhenTests.scala (100%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/{ => e2e}/juliaset/JuliaSet.scala (96%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/{ => e2e}/vulkan/SequenceExecutorTest.scala (94%) diff --git a/.scalafmt.conf b/.scalafmt.conf index 99311d4f..482486d5 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -8,6 +8,7 @@ optIn.configStyleArguments = false rewrite.rules = [RedundantBraces, RedundantParens, SortModifiers, PreferCurlyFors, Imports] rewrite.sortModifiers.preset = styleGuide rewrite.trailingCommas.style = always +rewrite.scala3.convertToNewSyntax = true indent.defnSite = 2 newlines.inInterpolation = "avoid" diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala index 60d68892..26086ae9 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala @@ -11,10 +11,10 @@ import scala.quoted.Expr private[cyfra] object BlockBuilder: - def buildBlock(tree: E[_], providedExprIds: Set[Int] = Set.empty): List[E[_]] = - val allVisited = mutable.Map[Int, E[_]]() + def buildBlock(tree: E[?], providedExprIds: Set[Int] = Set.empty): List[E[?]] = + val allVisited = mutable.Map[Int, E[?]]() val inDegrees = mutable.Map[Int, Int]().withDefaultValue(0) - val q = mutable.Queue[E[_]]() + val q = mutable.Queue[E[?]]() q.enqueue(tree) allVisited(tree.treeid) = tree @@ -28,8 +28,8 @@ private[cyfra] object BlockBuilder: allVisited(childId) = child q.enqueue(child) - val l = mutable.ListBuffer[E[_]]() - val roots = mutable.Queue[E[_]]() + val l = mutable.ListBuffer[E[?]]() + val roots = mutable.Queue[E[?]]() allVisited.values.foreach: node => if inDegrees(node.treeid) == 0 then roots.enqueue(node) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala index e5a647b2..a8fb18d2 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala @@ -18,7 +18,7 @@ private[cyfra] case class Context( voidFuncTypeRef: Int = -1, workerIndexRef: Int = -1, uniformVarRef: Int = -1, - constRefs: Map[(Tag[_], Any), Int] = Map(), + constRefs: Map[(Tag[?], Any), Int] = Map(), exprRefs: Map[Int, Int] = Map(), inBufferBlocks: List[ArrayBufferBlock] = List(), outBufferBlocks: List[ArrayBufferBlock] = List(), diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Opcodes.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Opcodes.scala index 0fa61949..38809183 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Opcodes.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Opcodes.scala @@ -18,7 +18,7 @@ private[cyfra] object Opcodes { def length = 1 - override def toString = s"Word(${bytes.mkString(", ")}${if (bytes.length == 4) s" [i = ${BigInt(bytes).toInt}])" else ""}" + override def toString = s"Word(${bytes.mkString(", ")}${if bytes.length == 4 then s" [i = ${BigInt(bytes).toInt}])" else ""}" } private[cyfra] case class WordVariable(name: String) extends Words { diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala index 76c527ab..122f6505 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala @@ -13,13 +13,13 @@ private[cyfra] object SpirvTypes: val UInt32Tag = summon[Tag[UInt32]] val Float32Tag = summon[Tag[Float32]] val GBooleanTag = summon[Tag[GBoolean]] - val Vec2TagWithoutArgs = summon[Tag[Vec2[_]]].tag.withoutArgs - val Vec3TagWithoutArgs = summon[Tag[Vec3[_]]].tag.withoutArgs - val Vec4TagWithoutArgs = summon[Tag[Vec4[_]]].tag.withoutArgs - val Vec2Tag = summon[Tag[Vec2[_]]] - val Vec3Tag = summon[Tag[Vec3[_]]] - val Vec4Tag = summon[Tag[Vec4[_]]] - val VecTag = summon[Tag[Vec[_]]] + val Vec2TagWithoutArgs = summon[Tag[Vec2[?]]].tag.withoutArgs + val Vec3TagWithoutArgs = summon[Tag[Vec3[?]]].tag.withoutArgs + val Vec4TagWithoutArgs = summon[Tag[Vec4[?]]].tag.withoutArgs + val Vec2Tag = summon[Tag[Vec2[?]]] + val Vec3Tag = summon[Tag[Vec3[?]]] + val Vec4Tag = summon[Tag[Vec4[?]]] + val VecTag = summon[Tag[Vec[?]]] val LInt32Tag = Int32Tag.tag val LUInt32Tag = UInt32Tag.tag @@ -37,7 +37,7 @@ private[cyfra] object SpirvTypes: type Vec3C[T <: Value] = Vec3[T] type Vec4C[T <: Value] = Vec4[T] - def scalarTypeDefInsn(tag: Tag[_], typeDefIndex: Int) = tag match { + def scalarTypeDefInsn(tag: Tag[?], typeDefIndex: Int) = tag match { case Int32Tag => Instruction(Op.OpTypeInt, List(ResultRef(typeDefIndex), IntWord(32), IntWord(1))) case UInt32Tag => Instruction(Op.OpTypeInt, List(ResultRef(typeDefIndex), IntWord(32), IntWord(0))) case Float32Tag => Instruction(Op.OpTypeFloat, List(ResultRef(typeDefIndex), IntWord(32))) @@ -57,9 +57,9 @@ private[cyfra] object SpirvTypes: case v if v <:< LVecTag => vecSize(v) * typeStride(v.typeArgs.head) - def typeStride(tag: Tag[_]): Int = typeStride(tag.tag) + def typeStride(tag: Tag[?]): Int = typeStride(tag.tag) - def toWord(tpe: Tag[_], value: Any): Words = tpe match { + def toWord(tpe: Tag[?], value: Any): Words = tpe match { case t if t == Int32Tag => IntWord(value.asInstanceOf[Int]) case t if t == UInt32Tag => @@ -73,7 +73,7 @@ private[cyfra] object SpirvTypes: Word(intToBytes(java.lang.Float.floatToIntBits(fl)).reverse.toArray) } - def defineScalarTypes(types: List[Tag[_]], context: Context): (List[Words], Context) = + def defineScalarTypes(types: List[Tag[?]], context: Context): (List[Words], Context) = val basicTypes = List(Int32Tag, Float32Tag, UInt32Tag, GBooleanTag) (basicTypes ::: types).distinct.foldLeft((List[Words](), context)) { case ((words, ctx), valType) => val typeDefIndex = ctx.nextResultId diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala index e48a6b2d..c0a5d315 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala @@ -26,31 +26,29 @@ import scala.util.Random private[cyfra] object DSLCompiler: // TODO: Not traverse same fn scopes for each fn call - private def getAllExprsFlattened(root: E[_], visitDetached: Boolean): List[E[_]] = + private def getAllExprsFlattened(root: E[?], visitDetached: Boolean): List[E[?]] = var blockI = 0 - val allScopesCache = mutable.Map[Int, List[E[_]]]() + val allScopesCache = mutable.Map[Int, List[E[?]]]() val visited = mutable.Set[Int]() @tailrec - def getAllScopesExprsAcc(toVisit: List[E[_]], acc: List[E[_]] = Nil): List[E[_]] = toVisit match + def getAllScopesExprsAcc(toVisit: List[E[?]], acc: List[E[?]] = Nil): List[E[?]] = toVisit match case Nil => acc case e :: tail if visited.contains(e.treeid) => getAllScopesExprsAcc(tail, acc) case e :: tail => - if (allScopesCache.contains(root.treeid)) - return allScopesCache(root.treeid) + if allScopesCache.contains(root.treeid) then return allScopesCache(root.treeid) val eScopes = e.introducedScopes val filteredScopes = if visitDetached then eScopes else eScopes.filterNot(_.isDetached) val newToVisit = toVisit ::: e.exprDependencies ::: filteredScopes.map(_.expr) val result = e.exprDependencies ::: filteredScopes.map(_.expr) ::: acc visited += e.treeid blockI += 1 - if (blockI % 100 == 0) - allScopesCache.update(e.treeid, result) + if blockI % 100 == 0 then allScopesCache.update(e.treeid, result) getAllScopesExprsAcc(newToVisit, result) val result = root :: getAllScopesExprsAcc(root :: Nil) allScopesCache(root.treeid) = result result - def compile(tree: Value, inTypes: List[Tag[_]], outTypes: List[Tag[_]], uniformSchema: GStructSchema[_]): ByteBuffer = + def compile(tree: Value, inTypes: List[Tag[?]], outTypes: List[Tag[?]], uniformSchema: GStructSchema[?]): ByteBuffer = val treeExpr = tree.tree val allExprs = getAllExprsFlattened(treeExpr, visitDetached = true) val typesInCode = allExprs.map(_.tag).distinct @@ -59,8 +57,8 @@ private[cyfra] object DSLCompiler: val (typeDefs, typedContext) = defineScalarTypes(scalarTypes, Context.initialContext) val structsInCode = (allExprs.collect { - case cs: ComposeStruct[_] => cs.resultSchema - case gf: GetField[_, _] => gf.resultSchema + case cs: ComposeStruct[?] => cs.resultSchema + case gf: GetField[?, ?] => gf.resultSchema } :+ uniformSchema).distinct val (structDefs, structCtx) = defineStructTypes(structsInCode, typedContext) val structNames = getStructNames(structsInCode, structCtx) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala index 11a6ac3d..cf7bc758 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala @@ -25,22 +25,22 @@ private[cyfra] object ExpressionCompiler: val UniformStructRefTag = "uniform_struct" def UniformStructRef[G <: Value: Tag] = Dynamic(UniformStructRefTag) - private def binaryOpOpcode(expr: BinaryOpExpression[_]) = expr match - case _: Sum[_] => (Op.OpIAdd, Op.OpFAdd) - case _: Diff[_] => (Op.OpISub, Op.OpFSub) - case _: Mul[_] => (Op.OpIMul, Op.OpFMul) - case _: Div[_] => (Op.OpSDiv, Op.OpFDiv) - case _: Mod[_] => (Op.OpSMod, Op.OpFMod) - - private def compileBinaryOpExpression(bexpr: BinaryOpExpression[_], ctx: Context): (List[Instruction], Context) = + private def binaryOpOpcode(expr: BinaryOpExpression[?]) = expr match + case _: Sum[?] => (Op.OpIAdd, Op.OpFAdd) + case _: Diff[?] => (Op.OpISub, Op.OpFSub) + case _: Mul[?] => (Op.OpIMul, Op.OpFMul) + case _: Div[?] => (Op.OpSDiv, Op.OpFDiv) + case _: Mod[?] => (Op.OpSMod, Op.OpFMod) + + private def compileBinaryOpExpression(bexpr: BinaryOpExpression[?], ctx: Context): (List[Instruction], Context) = val tpe = bexpr.tag val typeRef = ctx.valueTypeMap(tpe.tag) val subOpcode = tpe match { case i if i.tag <:< summon[Tag[IntType]].tag || i.tag <:< summon[Tag[UIntType]].tag || - (i.tag <:< summon[Tag[Vec[_]]].tag && i.tag.typeArgs.head <:< summon[Tag[IntType]].tag) => + (i.tag <:< summon[Tag[Vec[?]]].tag && i.tag.typeArgs.head <:< summon[Tag[IntType]].tag) => binaryOpOpcode(bexpr)._1 - case f if f.tag <:< summon[Tag[FloatType]].tag || (f.tag <:< summon[Tag[Vec[_]]].tag && f.tag.typeArgs.head <:< summon[Tag[FloatType]].tag) => + case f if f.tag <:< summon[Tag[FloatType]].tag || (f.tag <:< summon[Tag[Vec[?]]].tag && f.tag.typeArgs.head <:< summon[Tag[FloatType]].tag) => binaryOpOpcode(bexpr)._2 } val instructions = List( @@ -52,39 +52,39 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (bexpr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - private def compileConvertExpression(cexpr: ConvertExpression[_, _], ctx: Context): (List[Instruction], Context) = + private def compileConvertExpression(cexpr: ConvertExpression[?, ?], ctx: Context): (List[Instruction], Context) = val tpe = cexpr.tag val typeRef = ctx.valueTypeMap(tpe.tag) val tfOpcode = (cexpr.fromTag, cexpr) match { - case (from, _: ToFloat32[_]) if from.tag =:= Int32Tag.tag => Op.OpConvertSToF - case (from, _: ToFloat32[_]) if from.tag =:= UInt32Tag.tag => Op.OpConvertUToF - case (from, _: ToInt32[_]) if from.tag =:= Float32Tag.tag => Op.OpConvertFToS - case (from, _: ToUInt32[_]) if from.tag =:= Float32Tag.tag => Op.OpConvertFToU - case (from, _: ToInt32[_]) if from.tag =:= UInt32Tag.tag => Op.OpBitcast - case (from, _: ToUInt32[_]) if from.tag =:= Int32Tag.tag => Op.OpBitcast + case (from, _: ToFloat32[?]) if from.tag =:= Int32Tag.tag => Op.OpConvertSToF + case (from, _: ToFloat32[?]) if from.tag =:= UInt32Tag.tag => Op.OpConvertUToF + case (from, _: ToInt32[?]) if from.tag =:= Float32Tag.tag => Op.OpConvertFToS + case (from, _: ToUInt32[?]) if from.tag =:= Float32Tag.tag => Op.OpConvertFToU + case (from, _: ToInt32[?]) if from.tag =:= UInt32Tag.tag => Op.OpBitcast + case (from, _: ToUInt32[?]) if from.tag =:= Int32Tag.tag => Op.OpBitcast } val instructions = List(Instruction(tfOpcode, List(ResultRef(typeRef), ResultRef(ctx.nextResultId), ResultRef(ctx.exprRefs(cexpr.a.treeid))))) val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (cexpr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - def comparisonOp(comparisonOpExpression: ComparisonOpExpression[_]) = + def comparisonOp(comparisonOpExpression: ComparisonOpExpression[?]) = comparisonOpExpression match - case _: GreaterThan[_] => (Op.OpSGreaterThan, Op.OpFOrdGreaterThan) - case _: LessThan[_] => (Op.OpSLessThan, Op.OpFOrdLessThan) - case _: GreaterThanEqual[_] => (Op.OpSGreaterThanEqual, Op.OpFOrdGreaterThanEqual) - case _: LessThanEqual[_] => (Op.OpSLessThanEqual, Op.OpFOrdLessThanEqual) - case _: Equal[_] => (Op.OpIEqual, Op.OpFOrdEqual) + case _: GreaterThan[?] => (Op.OpSGreaterThan, Op.OpFOrdGreaterThan) + case _: LessThan[?] => (Op.OpSLessThan, Op.OpFOrdLessThan) + case _: GreaterThanEqual[?] => (Op.OpSGreaterThanEqual, Op.OpFOrdGreaterThanEqual) + case _: LessThanEqual[?] => (Op.OpSLessThanEqual, Op.OpFOrdLessThanEqual) + case _: Equal[?] => (Op.OpIEqual, Op.OpFOrdEqual) - private def compileBitwiseExpression(bexpr: BitwiseOpExpression[_], ctx: Context): (List[Instruction], Context) = + private def compileBitwiseExpression(bexpr: BitwiseOpExpression[?], ctx: Context): (List[Instruction], Context) = val tpe = bexpr.tag val typeRef = ctx.valueTypeMap(tpe.tag) val subOpcode = bexpr match { - case _: BitwiseAnd[_] => Op.OpBitwiseAnd - case _: BitwiseOr[_] => Op.OpBitwiseOr - case _: BitwiseXor[_] => Op.OpBitwiseXor - case _: BitwiseNot[_] => Op.OpNot - case _: ShiftLeft[_] => Op.OpShiftLeftLogical - case _: ShiftRight[_] => Op.OpShiftRightLogical + case _: BitwiseAnd[?] => Op.OpBitwiseAnd + case _: BitwiseOr[?] => Op.OpBitwiseOr + case _: BitwiseXor[?] => Op.OpBitwiseXor + case _: BitwiseNot[?] => Op.OpNot + case _: ShiftLeft[?] => Op.OpShiftLeftLogical + case _: ShiftRight[?] => Op.OpShiftRightLogical } val instructions = List( Instruction(subOpcode, List(ResultRef(typeRef), ResultRef(ctx.nextResultId)) ::: bexpr.exprDependencies.map(d => ResultRef(ctx.exprRefs(d.treeid)))), @@ -92,15 +92,14 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (bexpr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - def compileBlock(tree: E[_], ctx: Context): (List[Words], Context) = { + def compileBlock(tree: E[?], ctx: Context): (List[Words], Context) = { @tailrec - def compileExpressions(exprs: List[E[_]], ctx: Context, acc: List[Words]): (List[Words], Context) = { - if (exprs.isEmpty) (acc, ctx) + def compileExpressions(exprs: List[E[?]], ctx: Context, acc: List[Words]): (List[Words], Context) = { + if exprs.isEmpty then (acc, ctx) else { val expr = exprs.head - if (ctx.exprRefs.contains(expr.treeid)) - compileExpressions(exprs.tail, ctx, acc) + if ctx.exprRefs.contains(expr.treeid) then compileExpressions(exprs.tail, ctx, acc) else { val name: Option[String] = expr.of match @@ -119,17 +118,16 @@ private[cyfra] object ExpressionCompiler: case d @ Dynamic(UniformStructRefTag) => (Nil, ctx.copy(exprRefs = ctx.exprRefs + (d.treeid -> ctx.uniformVarRef))) - case c: ConvertExpression[_, _] => + case c: ConvertExpression[?, ?] => compileConvertExpression(c, ctx) - case b: BinaryOpExpression[_] => + case b: BinaryOpExpression[?] => compileBinaryOpExpression(b, ctx) - case negate: Negate[_] => + case negate: Negate[?] => val op = - if (negate.tag.tag <:< summon[Tag[FloatType]].tag || - (negate.tag.tag <:< summon[Tag[Vec[_]]].tag && negate.tag.tag.typeArgs.head <:< summon[Tag[FloatType]].tag)) - Op.OpFNegate + if negate.tag.tag <:< summon[Tag[FloatType]].tag || + (negate.tag.tag <:< summon[Tag[Vec[?]]].tag && negate.tag.tag.typeArgs.head <:< summon[Tag[FloatType]].tag) then Op.OpFNegate else Op.OpSNegate val instructions = List( Instruction(op, List(ResultRef(ctx.valueTypeMap(negate.tag.tag)), ResultRef(ctx.nextResultId), ResultRef(ctx.exprRefs(negate.a.treeid)))), @@ -137,7 +135,7 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (negate.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - case bo: BitwiseOpExpression[_] => + case bo: BitwiseOpExpression[?] => compileBitwiseExpression(bo, ctx) case and: And => @@ -180,7 +178,7 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - case sp: ScalarProd[_, _] => + case sp: ScalarProd[?, ?] => val instructions = List( Instruction( Op.OpVectorTimesScalar, @@ -195,7 +193,7 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - case dp: DotProd[_, _] => + case dp: DotProd[?, ?] => val instructions = List( Instruction( Op.OpDot, @@ -210,9 +208,9 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (dp.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - case co: ComparisonOpExpression[_] => + case co: ComparisonOpExpression[?] => val (intOp, floatOp) = comparisonOp(co) - val op = if (co.operandTag.tag <:< summon[Tag[FloatType]].tag) floatOp else intOp + val op = if co.operandTag.tag <:< summon[Tag[FloatType]].tag then floatOp else intOp val instructions = List( Instruction( op, @@ -227,7 +225,7 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - case e: ExtractScalar[_, _] => + case e: ExtractScalar[?, ?] => val instructions = List( Instruction( Op.OpVectorExtractDynamic, @@ -243,7 +241,7 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - case composeVec2: ComposeVec2[_] => + case composeVec2: ComposeVec2[?] => val instructions = List( Instruction( Op.OpCompositeConstruct, @@ -258,7 +256,7 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - case composeVec3: ComposeVec3[_] => + case composeVec3: ComposeVec3[?] => val instructions = List( Instruction( Op.OpCompositeConstruct, @@ -274,7 +272,7 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - case composeVec4: ComposeVec4[_] => + case composeVec4: ComposeVec4[?] => val instructions = List( Instruction( Op.OpCompositeConstruct, @@ -291,10 +289,10 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - case fc: ExtFunctionCall[_] => + case fc: ExtFunctionCall[?] => compileExtFunctionCall(fc, ctx) - case fc: FunctionCall[_] => + case fc: FunctionCall[?] => compileFunctionCall(fc, ctx) case ga @ GArrayElem(index, i) => @@ -314,14 +312,14 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> (ctx.nextResultId + 1)), nextResultId = ctx.nextResultId + 2) (instructions, updatedContext) - case when: WhenExpr[_] => + case when: WhenExpr[?] => compileWhen(when, ctx) - case fd: GSeq.FoldSeq[_, _] => + case fd: GSeq.FoldSeq[?, ?] => GSeqCompiler.compileFold(fd, ctx) - case cs: ComposeStruct[_] => - val schema = cs.resultSchema.asInstanceOf[GStructSchema[_]] + case cs: ComposeStruct[?] => + val schema = cs.resultSchema.asInstanceOf[GStructSchema[?]] val fields = cs.fields val insns: List[Instruction] = List( Instruction( @@ -348,7 +346,7 @@ private[cyfra] object ExpressionCompiler: ) val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> (ctx.nextResultId + 1)), nextResultId = ctx.nextResultId + 2) (insns, updatedContext) - case gf: GetField[_, _] => + case gf: GetField[?, ?] => val insns: List[Instruction] = List( Instruction( Op.OpCompositeExtract, @@ -363,7 +361,7 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (insns, updatedContext) - case ph: PhantomExpression[_] => (List(), ctx) + case ph: PhantomExpression[?] => (List(), ctx) } val ctxWithName = updatedCtx.copy(exprNames = updatedCtx.exprNames ++ name.map(n => (updatedCtx.nextResultId - 1, n)).toMap) compileExpressions(exprs.tail, ctxWithName, acc ::: instructions) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala index 50c4f047..e5fbc7b1 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala @@ -35,7 +35,7 @@ private[cyfra] object ExtFunctionCompiler: Functions.Log -> GlslOp.Log, ) - def compileExtFunctionCall(call: Expression.ExtFunctionCall[_], ctx: Context): (List[Instruction], Context) = + def compileExtFunctionCall(call: Expression.ExtFunctionCall[?], ctx: Context): (List[Instruction], Context) = val fnOp = fnOpMap(call.fn) val tp = call.tag val typeRef = ctx.valueTypeMap(tp.tag) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala index e3714465..83e9cd6b 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala @@ -17,10 +17,10 @@ import izumi.reflect.macrortti.LightTypeTag private[cyfra] object FunctionCompiler: - case class SprivFunction(sourceFn: FnIdentifier, functionId: Int, body: Expression[_], inputArgs: List[Expression[_]]): + case class SprivFunction(sourceFn: FnIdentifier, functionId: Int, body: Expression[?], inputArgs: List[Expression[?]]): def returnType: LightTypeTag = body.tag.tag - def compileFunctionCall(call: Expression.FunctionCall[_], ctx: Context): (List[Instruction], Context) = + def compileFunctionCall(call: Expression.FunctionCall[?], ctx: Context): (List[Instruction], Context) = val (ctxWithFn, fn) = if ctx.functions.contains(call.fn) then val fn = ctx.functions(call.fn) (ctx, fn) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala index 0819a631..769893f2 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala @@ -10,7 +10,7 @@ import io.computenode.cyfra.spirv.SpirvTypes.* private[cyfra] object GSeqCompiler: - def compileFold(fold: FoldSeq[_, _], ctx: Context): (List[Words], Context) = + def compileFold(fold: FoldSeq[?, ?], ctx: Context): (List[Words], Context) = val loopBack = ctx.nextResultId val mergeBlock = ctx.nextResultId + 1 val continueTarget = ctx.nextResultId + 2 @@ -46,7 +46,7 @@ private[cyfra] object GSeqCompiler: val foldZeroPointerType = ctx.funPointerTypeMap(foldZeroType) val foldFnExpr = fold.fnExpr - def generateSeqOps(seqExprs: List[(ElemOp[_], E[_])], context: Context, elemRef: Int): (List[Words], Context) = + def generateSeqOps(seqExprs: List[(ElemOp[?], E[?])], context: Context, elemRef: Int): (List[Words], Context) = val withElemRefCtx = context.copy(exprRefs = context.exprRefs + (fold.seq.currentElemExprTreeId -> elemRef)) seqExprs match { case Nil => // No more transformations, so reduce ops now diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala index 693fa04a..8275708c 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala @@ -10,7 +10,7 @@ import scala.collection.mutable private[cyfra] object GStructCompiler: - def defineStructTypes(schemas: List[GStructSchema[_]], context: Context): (List[Words], Context) = + def defineStructTypes(schemas: List[GStructSchema[?]], context: Context): (List[Words], Context) = val sortedSchemas = sortSchemasDag(schemas.distinctBy(_.structTag)) sortedSchemas.foldLeft((List[Words](), context)) { case ((words, ctx), schema) => ( @@ -29,7 +29,7 @@ private[cyfra] object GStructCompiler: ) } - def getStructNames(schemas: List[GStructSchema[_]], context: Context): List[Words] = + def getStructNames(schemas: List[GStructSchema[?]], context: Context): List[Words] = schemas.flatMap { schema => val structName = schema.structTag.tag.shortName val structType = context.valueTypeMap(schema.structTag.tag) @@ -38,14 +38,14 @@ private[cyfra] object GStructCompiler: } } - private def sortSchemasDag(schemas: List[GStructSchema[_]]): List[GStructSchema[_]] = + private def sortSchemasDag(schemas: List[GStructSchema[?]]): List[GStructSchema[?]] = val schemaMap = schemas.map(s => s.structTag.tag -> s).toMap val visited = mutable.Set[LightTypeTag]() val stack = mutable.Stack[LightTypeTag]() - val sorted = mutable.ListBuffer[GStructSchema[_]]() + val sorted = mutable.ListBuffer[GStructSchema[?]]() def visit(tag: LightTypeTag): Unit = - if !visited.contains(tag) && tag <:< summon[Tag[GStruct[_]]].tag then + if !visited.contains(tag) && tag <:< summon[Tag[GStruct[?]]].tag then visited += tag stack.push(tag) schemaMap(tag).fields.map(_._3.tag).foreach(visit) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index 4fb533c3..a5798505 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -18,7 +18,7 @@ private[cyfra] object SpirvProgramCompiler: case _ => false } - def compileMain(tree: Value, resultType: Tag[_], ctx: Context): (List[Words], Context) = { + def compileMain(tree: Value, resultType: Tag[?], ctx: Context): (List[Words], Context) = { val init = List( Instruction(Op.OpFunction, List(ResultRef(ctx.voidTypeRef), ResultRef(MAIN_FUNC_REF), SamplerAddressingMode.None, ResultRef(VOID_FUNC_TYPE_REF))), @@ -104,7 +104,7 @@ private[cyfra] object SpirvProgramCompiler: (voidDef, ctxWithVoid) } - def initAndDecorateUniforms(ins: List[Tag[_]], outs: List[Tag[_]], context: Context): (List[Words], List[Words], Context) = { + def initAndDecorateUniforms(ins: List[Tag[?]], outs: List[Tag[?]], context: Context): (List[Words], List[Words], Context) = { val (inDecor, inDef, inCtx) = createAndInitBlocks(ins, in = true, context) val (outDecor, outDef, outCtx) = createAndInitBlocks(outs, in = false, inCtx) val (voidsDef, voidCtx) = defineVoids(outCtx) @@ -130,7 +130,7 @@ private[cyfra] object SpirvProgramCompiler: (definitionInstructions, context.copy(nextResultId = context.nextResultId + 3)) } - def createAndInitBlocks(blocks: List[Tag[_]], in: Boolean, context: Context): (List[Words], List[Words], Context) = { + def createAndInitBlocks(blocks: List[Tag[?]], in: Boolean, context: Context): (List[Words], List[Words], Context) = { val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { case ((decAcc, insnAcc, ctx), tpe) => val block = ArrayBufferBlock(ctx.nextResultId, ctx.nextResultId + 1, ctx.nextResultId + 2, ctx.nextResultId + 3, ctx.nextBinding) @@ -150,7 +150,7 @@ private[cyfra] object SpirvProgramCompiler: ) val contextWithBlock = - if (in) ctx.copy(inBufferBlocks = block :: ctx.inBufferBlocks) else ctx.copy(outBufferBlocks = block :: ctx.outBufferBlocks) + if in then ctx.copy(inBufferBlocks = block :: ctx.inBufferBlocks) else ctx.copy(outBufferBlocks = block :: ctx.outBufferBlocks) ( decAcc ::: decorationInstructions, insnAcc ::: definitionInstructions, @@ -160,18 +160,18 @@ private[cyfra] object SpirvProgramCompiler: (decoration, definition, newContext) } - def getBlockNames(context: Context, uniformSchema: GStructSchema[_]): List[Words] = + def getBlockNames(context: Context, uniformSchema: GStructSchema[?]): List[Words] = def namesForBlock(block: ArrayBufferBlock, tpe: String): List[Words] = Instruction(Op.OpName, List(ResultRef(block.structTypeRef), Text(s"Buffer$tpe"))) :: Instruction(Op.OpName, List(ResultRef(block.blockVarRef), Text(s"data$tpe"))) :: Nil // todo name uniform context.inBufferBlocks.flatMap(namesForBlock(_, "In")) ::: context.outBufferBlocks.flatMap(namesForBlock(_, "Out")) - def createAndInitUniformBlock(schema: GStructSchema[_], ctx: Context): (List[Words], List[Words], Context) = - def totalStride(gs: GStructSchema[_]): Int = gs.fields + def createAndInitUniformBlock(schema: GStructSchema[?], ctx: Context): (List[Words], List[Words], Context) = + def totalStride(gs: GStructSchema[?]): Int = gs.fields .map: case (_, fromExpr, t) if t <:< gs.gStructTag => - val constructor = fromExpr.asInstanceOf[GStructConstructor[_]] + val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] totalStride(constructor.schema) case (_, _, t) => typeStride(t) @@ -182,7 +182,7 @@ private[cyfra] object SpirvProgramCompiler: case ((acc, offset), ((name, fromExpr, tag), idx)) => val stride = if tag <:< schema.gStructTag then - val constructor = fromExpr.asInstanceOf[GStructConstructor[_]] + val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] totalStride(constructor.schema) else typeStride(tag) val offsetDecoration = Instruction(Op.OpMemberDecorate, List(ResultRef(uniformStructTypeRef), IntWord(idx), Decoration.Offset, IntWord(offset))) @@ -214,7 +214,7 @@ private[cyfra] object SpirvProgramCompiler: ) val predefinedConsts = List((Int32Tag, 0), (UInt32Tag, 0), (Int32Tag, 1)) - def defineConstants(exprs: List[E[_]], ctx: Context): (List[Words], Context) = { + def defineConstants(exprs: List[E[?]], ctx: Context): (List[Words], Context) = { val consts = (exprs.collect { case c @ Const(x) => (c.tag, x) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala index 8fe7eda7..1976788b 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala @@ -11,8 +11,8 @@ import io.computenode.cyfra.spirv.SpirvTypes.* private[cyfra] object WhenCompiler: - def compileWhen(when: WhenExpr[_], ctx: Context): (List[Words], Context) = { - def compileCases(ctx: Context, resultVar: Int, conditions: List[E[_]], thenCodes: List[E[_]], elseCode: E[_]): (List[Words], Context) = + def compileWhen(when: WhenExpr[?], ctx: Context): (List[Words], Context) = { + def compileCases(ctx: Context, resultVar: Int, conditions: List[E[?]], thenCodes: List[E[?]], elseCode: E[?]): (List[Words], Context) = (conditions, thenCodes) match { case (Nil, Nil) => val (elseInstructions, elseCtx) = compileBlock(elseCode, ctx) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Algebra.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Algebra.scala index 03be9714..ff863778 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Algebra.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Algebra.scala @@ -49,7 +49,7 @@ object Algebra: trait ScalarModable[T <: Scalar: FromExpr: Tag]: def mod(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Mod(a, b)) - extension [T <: Scalar: ScalarModable: Tag](a: T) inline def mod(b: T)(using Source): T = summon[ScalarModable[T]].mod(a, b) + extension [T <: Scalar: ScalarModable: Tag](a: T) inline infix def mod(b: T)(using Source): T = summon[ScalarModable[T]].mod(a, b) trait Comparable[T <: Scalar: FromExpr: Tag]: def greaterThan(a: T, b: T)(using Source): GBoolean = GBoolean(GreaterThan(a, b)) @@ -80,26 +80,26 @@ object Algebra: inline def asFloat(using Source): Float32 = Float32(ToFloat32(u32)) inline def signed(using Source): Int32 = Int32(ToInt32(u32)) - trait VectorSummable[V <: Vec[_]: FromExpr: Tag]: + trait VectorSummable[V <: Vec[?]: FromExpr: Tag]: def sum(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Sum(a, b)) - extension [V <: Vec[_]: VectorSummable: Tag](a: V) + extension [V <: Vec[?]: VectorSummable: Tag](a: V) @targetName("addVector") inline def +(b: V)(using Source): V = summon[VectorSummable[V]].sum(a, b) - trait VectorDiffable[V <: Vec[_]: FromExpr: Tag]: + trait VectorDiffable[V <: Vec[?]: FromExpr: Tag]: def diff(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Diff(a, b)) - extension [V <: Vec[_]: VectorDiffable: Tag](a: V) + extension [V <: Vec[?]: VectorDiffable: Tag](a: V) @targetName("subVector") inline def -(b: V)(using Source): V = summon[VectorDiffable[V]].diff(a, b) trait VectorDotable[S <: Scalar: FromExpr: Tag, V <: Vec[S]: Tag]: def dot(a: V, b: V)(using Source): S = summon[FromExpr[S]].fromExpr(DotProd[S, V](a, b)) extension [S <: Scalar: Tag, V <: Vec[S]: Tag](a: V)(using VectorDotable[S, V]) - def dot(b: V)(using Source): S = summon[VectorDotable[S, V]].dot(a, b) + infix def dot(b: V)(using Source): S = summon[VectorDotable[S, V]].dot(a, b) - trait VectorCrossable[V <: Vec[_]: FromExpr: Tag]: + trait VectorCrossable[V <: Vec[?]: FromExpr: Tag]: def cross(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Cross, List(a, b))) - extension [V <: Vec[_]: VectorCrossable: Tag](a: V) def cross(b: V)(using Source): V = summon[VectorCrossable[V]].cross(a, b) + extension [V <: Vec[?]: VectorCrossable: Tag](a: V) infix def cross(b: V)(using Source): V = summon[VectorCrossable[V]].cross(a, b) trait VectorScalarMulable[S <: Scalar: Tag, V <: Vec[S]: FromExpr: Tag]: def mul(a: V, b: S)(using Source): V = summon[FromExpr[V]].fromExpr(ScalarProd[S, V](a, b)) @@ -108,9 +108,9 @@ object Algebra: extension [S <: Scalar: Tag, V <: Vec[S]: Tag](s: S)(using VectorScalarMulable[S, V]) def *(v: V)(using Source): V = summon[VectorScalarMulable[S, V]].mul(v, s) - trait VectorNegatable[V <: Vec[_]: FromExpr: Tag]: + trait VectorNegatable[V <: Vec[?]: FromExpr: Tag]: def negate(a: V)(using Source): V = summon[FromExpr[V]].fromExpr(Negate(a)) - extension [V <: Vec[_]: VectorNegatable: Tag](a: V) + extension [V <: Vec[?]: VectorNegatable: Tag](a: V) @targetName("negateVector") def unary_-(using Source): V = summon[VectorNegatable[V]].negate(a) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Control.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Control.scala index 4ef7c37c..68a5c1b4 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Control.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Control.scala @@ -22,7 +22,7 @@ object Control: ): def elseWhen(cond: GBoolean)(t: T): When[T] = When(when, thenCode, otherConds :+ Scope(cond.tree), otherCases :+ Scope(t.tree.asInstanceOf[E[T]]), name) - def otherwise(t: T): T = + infix def otherwise(t: T): T = summon[FromExpr[T]] .fromExpr(WhenExpr(when, Scope(thenCode.tree.asInstanceOf[E[T]]), otherConds, otherCases, Scope(t.tree.asInstanceOf[E[T]])))(using name) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala index 5355a10f..4866d7c8 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala @@ -18,25 +18,25 @@ trait Expression[T <: Value: Tag] extends Product: .map(e => s"#${e.treeid}") .mkString("[", ", ", "]") override def toString: String = s"${this.productPrefix}(${of.fold("")(v => s"name = ${v.source}, ")}children=$childrenStrings, id=$treeid)" - private def exploreDeps(children: List[Any]): (List[Expression[_]], List[Scope[_]]) = (for (elem <- children) yield elem match { - case b: Scope[_] => + private def exploreDeps(children: List[Any]): (List[Expression[?]], List[Scope[?]]) = (for (elem <- children) yield elem match { + case b: Scope[?] => (None, Some(b)) - case x: Expression[_] => + case x: Expression[?] => (Some(x), None) case x: Value => (Some(x.tree), None) case list: List[Any] => - (exploreDeps(list.collect { case v: Value => v })._1, exploreDeps(list.collect { case s: Scope[_] => s })._2) + (exploreDeps(list.collect { case v: Value => v })._1, exploreDeps(list.collect { case s: Scope[?] => s })._2) case _ => (None, None) - }).foldLeft((List.empty[Expression[_]], List.empty[Scope[_]])) { case ((acc, blockAcc), (newExprs, newBlocks)) => + }).foldLeft((List.empty[Expression[?]], List.empty[Scope[?]])) { case ((acc, blockAcc), (newExprs, newBlocks)) => (acc ::: newExprs.iterator.toList, blockAcc ::: newBlocks.iterator.toList) } - def exprDependencies: List[Expression[_]] = exploreDeps(this.productIterator.toList)._1 - def introducedScopes: List[Scope[_]] = exploreDeps(this.productIterator.toList)._2 + def exprDependencies: List[Expression[?]] = exploreDeps(this.productIterator.toList)._1 + def introducedScopes: List[Scope[?]] = exploreDeps(this.productIterator.toList)._2 object Expression: trait CustomTreeId: - self: Expression[_] => + self: Expression[?] => override val treeid: Int trait PhantomExpression[T <: Value: Tag] extends Expression[T] @@ -85,7 +85,7 @@ object Expression: case class Or(a: GBoolean, b: GBoolean) extends Expression[GBoolean] case class Not(a: GBoolean) extends Expression[GBoolean] - case class ExtractScalar[V <: Vec[_]: Tag, S <: Scalar: Tag](a: V, i: Int32) extends Expression[S] + case class ExtractScalar[V <: Vec[?]: Tag, S <: Scalar: Tag](a: V, i: Int32) extends Expression[S] sealed trait ConvertExpression[F <: Scalar: Tag, T <: Scalar: Tag] extends Expression[T] { def fromTag: Tag[F] = summon[Tag[F]] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Functions.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Functions.scala index 8a5be4df..3d58bfd5 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Functions.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Functions.scala @@ -44,7 +44,7 @@ object Functions: case object Pow extends FunctionName def pow(v: Float32, p: Float32)(using Source): Float32 = Float32(ExtFunctionCall(Pow, List(v, p))) - def pow[V <: Vec[_]: Tag: FromExpr](v: V, p: V)(using Source): V = + def pow[V <: Vec[?]: Tag: FromExpr](v: V, p: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Pow, List(v, p))) case object Smoothstep extends FunctionName diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GSeq.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GSeq.scala index 1cdc0a7a..20987310 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GSeq.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GSeq.scala @@ -13,8 +13,8 @@ import java.util.Base64 import scala.util.Random class GSeq[T <: Value: Tag: FromExpr]( - val uninitSource: Expression[_] => GSeqStream[_], - val elemOps: List[GSeq.ElemOp[_]], + val uninitSource: Expression[?] => GSeqStream[?], + val elemOps: List[GSeq.ElemOp[?]], val limit: Option[Int], val name: Source, val currentElemExprTreeId: Int = treeidState.getAndIncrement(), @@ -22,7 +22,7 @@ class GSeq[T <: Value: Tag: FromExpr]( ): def copyWithDynamicTrees[R <: Value: Tag: FromExpr]( - elemOps: List[GSeq.ElemOp[_]] = elemOps, + elemOps: List[GSeq.ElemOp[?]] = elemOps, limit: Option[Int] = limit, currentElemExprTreeId: Int = currentElemExprTreeId, aggregateElemExprTreeId: Int = aggregateElemExprTreeId, @@ -67,14 +67,14 @@ object GSeq: val first = when(i === 0) { xs(0) } - (if (xs.length == 1) - first + (if xs.length == 1 then first else xs.init.zipWithIndex.tail.foldLeft(first) { case (acc, (x, j)) => acc.elseWhen(i === j) { x } - }).otherwise(xs.last) + } + ).otherwise(xs.last) } .limit(xs.length) @@ -86,16 +86,16 @@ object GSeq: sealed trait ElemOp[T <: Value: Tag]: def tag: Tag[T] = summon[Tag[T]] - def fn: Expression[_] + def fn: Expression[?] - case class MapOp[T <: Value: Tag, R <: Value: Tag](fn: Expression[_]) extends ElemOp[R] + case class MapOp[T <: Value: Tag, R <: Value: Tag](fn: Expression[?]) extends ElemOp[R] case class FilterOp[T <: Value: Tag](fn: Expression[GBoolean]) extends ElemOp[T] case class TakeUntilOp[T <: Value: Tag](fn: Expression[GBoolean]) extends ElemOp[T] sealed trait GSeqSource[T <: Value: Tag] - case class GSeqStream[T <: Value: Tag](init: T, next: Expression[_]) extends GSeqSource[T] + case class GSeqStream[T <: Value: Tag](init: T, next: Expression[?]) extends GSeqSource[T] - case class FoldSeq[R <: Value: Tag, T <: Value: Tag](zero: R, fn: Expression[_], seq: GSeq[T]) extends Expression[R]: + case class FoldSeq[R <: Value: Tag, T <: Value: Tag](zero: R, fn: Expression[?], seq: GSeq[T]) extends Expression[R]: val zeroExpr = zero.tree val fnExpr = fn val streamInitExpr = seq.source.init.tree @@ -104,6 +104,6 @@ object GSeq: val limitExpr = ConstInt32(seq.limit.getOrElse(throw new IllegalArgumentException("Reduce on infinite stream is not supported"))) - override val exprDependencies: List[E[_]] = List(zeroExpr, streamInitExpr, limitExpr) - override val introducedScopes: List[Scope[_]] = Scope(fnExpr)(using fnExpr.tag) :: Scope(streamNextExpr)(using streamNextExpr.tag) :: + override val exprDependencies: List[E[?]] = List(zeroExpr, streamInitExpr, limitExpr) + override val introducedScopes: List[Scope[?]] = Scope(fnExpr)(using fnExpr.tag) :: Scope(streamNextExpr)(using streamNextExpr.tag) :: seqExprs.map(e => Scope(e)(using e.tag)) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GStruct.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GStruct.scala index 9cd48151..101c5582 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GStruct.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GStruct.scala @@ -21,7 +21,7 @@ abstract class GStruct[T <: GStruct[T]: Tag: GStructSchema] extends Value with P private[dsl] var _name = Source("Unknown") override def source: Source = _name -case class GStructSchema[T <: GStruct[T]: Tag](fields: List[(String, FromExpr[_], Tag[_])], dependsOn: Option[E[T]], fromTuple: (Tuple, Source) => T): +case class GStructSchema[T <: GStruct[T]: Tag](fields: List[(String, FromExpr[?], Tag[?])], dependsOn: Option[E[T]], fromTuple: (Tuple, Source) => T): given GStructSchema[T] = this val structTag = summon[Tag[T]] @@ -48,7 +48,7 @@ case class GStructSchema[T <: GStruct[T]: Tag](fields: List[(String, FromExpr[_] this.copy(dependsOn = Some(e)), ) - val gStructTag = summon[Tag[GStruct[_]]] + val gStructTag = summon[Tag[GStruct[?]]] trait GStructConstructor[T <: GStruct[T]] extends FromExpr[T]: def schema: GStructSchema[T] @@ -81,8 +81,8 @@ object GStructSchema: // quick prove that all fields <:< value summonAll[Tuple.Map[m.MirroredElemTypes, [f] =>> f <:< Value]] // get (name, tag) pairs for all fields - val elemTags: List[Tag[_]] = summonAll[Tuple.Map[m.MirroredElemTypes, TagOf]].toList.asInstanceOf[List[Tag[_]]] - val elemFromExpr: List[FromExpr[_]] = summonAll[Tuple.Map[m.MirroredElemTypes, [f] =>> FromExprOf[f]]].toList.asInstanceOf[List[FromExpr[_]]] + val elemTags: List[Tag[?]] = summonAll[Tuple.Map[m.MirroredElemTypes, TagOf]].toList.asInstanceOf[List[Tag[?]]] + val elemFromExpr: List[FromExpr[?]] = summonAll[Tuple.Map[m.MirroredElemTypes, [f] =>> FromExprOf[f]]].toList.asInstanceOf[List[FromExpr[?]]] val elemNames: List[String] = constValueTuple[m.MirroredElemLabels].toList.asInstanceOf[List[String]] val elements = elemNames.lazyZip(elemFromExpr).lazyZip(elemTags).toList GStructSchema[T]( diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala index 8357f6ab..91b3a9f4 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala @@ -7,7 +7,7 @@ import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag trait Value: - def tree: E[_] + def tree: E[?] def source: Source private[cyfra] def treeid: Int = tree.treeid protected def init() = diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/FnCall.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/FnCall.scala index b6af5e2c..f5ad184c 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/FnCall.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/FnCall.scala @@ -45,7 +45,7 @@ object FnCall: case None => quotes.reflect.report.errorAndAbort(s"Expected pure function") def isPure(using Quotes)(defdef: quotes.reflect.DefDef): Boolean = - import quotes.reflect._ + import quotes.reflect.* val returnType = defdef.returnTpt.tpe val paramSets = defdef.termParamss if paramSets.length > 1 then return false diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Source.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Source.scala index 0ab74246..e6212397 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Source.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Source.scala @@ -20,7 +20,7 @@ object Source: } def valueName(using Quotes): Expr[String] = - import quotes.reflect._ + import quotes.reflect.* val ownerOpt = actualOwner(Symbol.spliceOwner) ownerOpt match case Some(owner) => @@ -32,7 +32,7 @@ object Source: def findOwner(using Quotes)(owner: quotes.reflect.Symbol, skipIf: quotes.reflect.Symbol => Boolean): Option[quotes.reflect.Symbol] = { import quotes.reflect.* var owner0 = owner - while (skipIf(owner0)) + while skipIf(owner0) do if owner0 == Symbol.noSymbol then return None owner0 = owner0.owner Some(owner0) @@ -46,10 +46,8 @@ object Source: private def adjustName(s: String): String = // Required to get the same name from dotty - if (s.startsWith("")) - s.stripSuffix("$>") + ">" - else - s + if s.startsWith("") then s.stripSuffix("$>") + ">" + else s sealed trait Chunk object Chunk: diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Util.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Util.scala index b3aba9d2..c06c2198 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Util.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Util.scala @@ -7,11 +7,11 @@ object Util: isSyntheticAlt(s) def isSyntheticAlt(using Quotes)(s: quotes.reflect.Symbol) = { - import quotes.reflect._ + import quotes.reflect.* s.flags.is(Flags.Synthetic) || s.isClassConstructor || s.isLocalDummy || isScala2Macro(s) || s.name.startsWith("x$proxy") } def isScala2Macro(using Quotes)(s: quotes.reflect.Symbol) = { - import quotes.reflect._ + import quotes.reflect.* (s.flags.is(Flags.Macro) && s.owner.flags.is(Flags.Scala2x)) || (s.flags.is(Flags.Macro) && !s.flags.is(Flags.Inline)) } def isSyntheticName(name: String) = diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/ArithmeticTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticTests.scala similarity index 100% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/ArithmeticTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticTests.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/FunctionsTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsTests.scala similarity index 100% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/FunctionsTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsTests.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/GSeqTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GSeqTests.scala similarity index 100% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/GSeqTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GSeqTests.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/GStructTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructTests.scala similarity index 100% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/GStructTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructTests.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/ImageTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ImageTests.scala similarity index 98% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/ImageTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ImageTests.scala index 7e1fc6e8..20aea0e4 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/ImageTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ImageTests.scala @@ -1,4 +1,4 @@ -package io.computenode.cyfra +package io.computenode.cyfra.e2e import com.diogonunes.jcolor.Ansi.colorize import com.diogonunes.jcolor.Attribute diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/WhenTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenTests.scala similarity index 100% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/WhenTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenTests.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/juliaset/JuliaSet.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala similarity index 96% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/juliaset/JuliaSet.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala index e049b165..30556b58 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/juliaset/JuliaSet.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala @@ -1,4 +1,4 @@ -package io.computenode.cyfra.juliaset +package io.computenode.cyfra.e2e.juliaset import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.* @@ -16,6 +16,7 @@ import java.nio.file.Files import scala.concurrent.ExecutionContext.Implicits import scala.concurrent.duration.DurationInt import scala.concurrent.{Await, ExecutionContext} +import io.computenode.cyfra.e2e.ImageTests class JuliaSet extends FunSuite: given GContext = new GContext() diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/vulkan/SequenceExecutorTest.scala similarity index 94% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/vulkan/SequenceExecutorTest.scala index 0762413c..87fa10cb 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/vulkan/SequenceExecutorTest.scala @@ -1,9 +1,10 @@ -package io.computenode.cyfra.vulkan +package io.computenode.cyfra.e2e.vulkan import io.computenode.cyfra.vulkan.compute.{Binding, ComputePipeline, InputBufferSize, LayoutInfo, LayoutSet, Shader} import io.computenode.cyfra.vulkan.executor.BufferAction.{LoadFrom, LoadTo} import io.computenode.cyfra.vulkan.executor.SequenceExecutor import io.computenode.cyfra.vulkan.executor.SequenceExecutor.{ComputationSequence, Compute, Dependency, LayoutLocation} +import io.computenode.cyfra.vulkan.VulkanContext import munit.FunSuite import org.lwjgl.BufferUtils diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala index 89b3d2d5..ff60b4b2 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala @@ -131,16 +131,14 @@ def main = val existingSpheres = mutable.Set.empty[((Float, Float, Float), Float)] def randomSphere(iter: Int = 0): Sphere = { - if (iter > 1000) - throw new Exception("Could not find a non-intersecting sphere") + if iter > 1000 then throw new Exception("Could not find a non-intersecting sphere") def nextFloatAny = rd.nextFloat() * 2f - 1f def nextFloatPos = rd.nextFloat() val center = (nextFloatAny * 10, nextFloatAny * 10, nextFloatPos * 10 + 8f) val radius = nextFloatPos + 1.5f - if (existingSpheres.exists(s => scalaTwoSpheresIntersect(s._1, s._2, center, radius))) - randomSphere(iter + 1) + if existingSpheres.exists(s => scalaTwoSpheresIntersect(s._1, s._2, center, radius)) then randomSphere(iter + 1) else { existingSpheres.add((center, radius)) def color = (nextFloatPos * 0.5f + 0.5f, nextFloatPos * 0.5f + 0.5f, nextFloatPos * 0.5f + 0.5f) diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala index e50cf55f..f46068dc 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala @@ -18,7 +18,7 @@ import java.nio.file.{Path, Paths} import scala.concurrent.Await import scala.concurrent.duration.DurationInt -trait AnimationRenderer[S <: AnimationRenderer.Scene, F <: GFunction[_, Vec4[Float32], Vec4[Float32]]](params: AnimationRenderer.Parameters): +trait AnimationRenderer[S <: AnimationRenderer.Scene, F <: GFunction[?, Vec4[Float32], Vec4[Float32]]](params: AnimationRenderer.Parameters): private val msPerFrame = 1000.0f / params.framesPerSecond diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala index 4f1a42a0..22ff6e0d 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala @@ -35,7 +35,7 @@ class ShapeCollection(val boxes: List[Box], val spheres: List[Sphere], val quads case _ => assert(false, "Unknown shape type: Broken sealed hierarchy") def testRay(rayPos: Vec3[Float32], rayDir: Vec3[Float32], noHit: RayHitInfo): RayHitInfo = - def testShapeType[T <: GStruct[T] with Shape: FromExpr: Tag: TestRay](shapes: List[T], currentHit: RayHitInfo): RayHitInfo = + def testShapeType[T <: GStruct[T] & Shape: FromExpr: Tag: TestRay](shapes: List[T], currentHit: RayHitInfo): RayHitInfo = val testRay = summon[TestRay[T]] if shapes.isEmpty then currentHit else GSeq.of(shapes).fold(currentHit, (currentHit, shape) => testRay.testRay(shape, rayPos, rayDir, currentHit)) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala index 3151cf17..164458bf 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala @@ -6,5 +6,5 @@ import io.computenode.cyfra.runtime.mem.{GMem, RamGMem} import scala.concurrent.Future trait Executable[H <: Value, R <: Value] { - def execute(input: GMem[H], output: RamGMem[R, _]): Future[Unit] + def execute(input: GMem[H], output: RamGMem[R, ?]): Future[Unit] } diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala index 8871460c..17ba5f79 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala @@ -8,8 +8,8 @@ import izumi.reflect.Tag case class GFunction[G <: GStruct[G]: GStructSchema: Tag, H <: Value: Tag: FromExpr, R <: Value: Tag: FromExpr](fn: (G, Int32, GArray[H]) => R)( implicit context: GContext, ) { - def arrayInputs: List[Tag[_]] = List(summon[Tag[H]]) - def arrayOutputs: List[Tag[_]] = List(summon[Tag[R]]) + def arrayInputs: List[Tag[?]] = List(summon[Tag[H]]) + def arrayOutputs: List[Tag[?]] = List(summon[Tag[R]]) val pipeline: ComputePipeline = context.compile(this) } diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala index 69b2c984..10cc0398 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala @@ -24,9 +24,9 @@ trait GMem[H <: Value]: object GMem: type fRGBA = (Float, Float, Float, Float) - def totalStride(gs: GStructSchema[_]): Int = gs.fields.map { + def totalStride(gs: GStructSchema[?]): Int = gs.fields.map { case (_, fromExpr, t) if t <:< gs.gStructTag => - val constructor = fromExpr.asInstanceOf[GStructConstructor[_]] + val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] totalStride(constructor.schema) case (_, _, t) => typeStride(t) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala index bd418ede..710781ea 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala @@ -11,8 +11,7 @@ class Vec4FloatMem(val size: Int, protected val data: ByteBuffer) extends RamGMe def toArray: Array[fRGBA] = { val res = data.asFloatBuffer() val result = new Array[fRGBA](size) - for (i <- 0 until size) - result(i) = (res.get(), res.get(), res.get(), res.get()) + for i <- 0 until size do result(i) = (res.get(), res.get(), res.get(), res.get()) result } diff --git a/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/ImageUtility.scala b/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/ImageUtility.scala index a1dfc18a..81478b63 100644 --- a/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/ImageUtility.scala +++ b/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/ImageUtility.scala @@ -9,8 +9,8 @@ object ImageUtility { def renderToImage(arr: Array[(Float, Float, Float, Float)], n: Int, location: Path): Unit = renderToImage(arr, n, n, location) def renderToImage(arr: Array[(Float, Float, Float, Float)], w: Int, h: Int, location: Path): Unit = { val image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB) - for (y <- 0 until h) - for (x <- 0 until w) { + for y <- 0 until h do + for x <- 0 until w do { val (r, g, b, _) = arr(y * w + x) def clip(f: Float) = Math.min(1.0f, Math.max(0.0f, f)) val (iR, iG, iB) = ((clip(r) * 255).toInt, (clip(g) * 255).toInt, (clip(b) * 255).toInt) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala index cfb5ea56..a12e1c7e 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala @@ -17,7 +17,7 @@ private[cyfra] object VulkanContext { private[cyfra] class VulkanContext { val instance: Instance = new Instance(ValidationLayers) - val debugCallback: Option[DebugCallback] = if (ValidationLayers) Some(new DebugCallback(instance)) else None + val debugCallback: Option[DebugCallback] = if ValidationLayers then Some(new DebugCallback(instance)) else None val device: Device = new Device(instance) val computeQueue: Queue = new Queue(device.computeQueueFamily, 0, device) val allocator: Allocator = new Allocator(instance, device) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala index ce46ac25..85c4ac96 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala @@ -34,8 +34,7 @@ private[cyfra] class Fence(device: Device, flags: Int = 0, onDestroy: () => Unit def isSignaled: Boolean = { val result = vkGetFenceStatus(device.get, handle) - if (!(result == VK_SUCCESS || result == VK_NOT_READY)) - throw new VulkanAssertionError("Failed to get fence status", result) + if !(result == VK_SUCCESS || result == VK_NOT_READY) then throw new VulkanAssertionError("Failed to get fence status", result) result == VK_SUCCESS } @@ -51,8 +50,7 @@ private[cyfra] class Fence(device: Device, flags: Int = 0, onDestroy: () => Unit def block(timeout: Long): Boolean = { val err = vkWaitForFences(device.get, handle, true, timeout); - if (err != VK_SUCCESS && err != VK_TIMEOUT) - throw new VulkanAssertionError("Failed to wait for fences", err); + if err != VK_SUCCESS && err != VK_TIMEOUT then throw new VulkanAssertionError("Failed to wait for fences", err); err == VK_SUCCESS; } } diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala index aeddd7f4..ca2456de 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala @@ -24,7 +24,7 @@ private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanC .sType$Default() .pNext(0) .flags(0) - .pSetLayouts(stack.longs(descriptorSetLayouts.map(_._1): _*)) + .pSetLayouts(stack.longs(descriptorSetLayouts.map(_._1)*)) .pPushConstantRanges(null) val pPipelineLayout = stack.callocLong(1) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala index c4d26edc..c09a1e7a 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala @@ -66,8 +66,7 @@ private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandl val pCallback = BufferUtils.createLongBuffer(1) val err = vkCreateDebugReportCallbackEXT(instance.get, dbgCreateInfo, null, pCallback) val callbackHandle = pCallback.get(0) - if (err != VK_SUCCESS) - throw new VulkanAssertionError("Failed to create DebugCallback", err) + if err != VK_SUCCESS then throw new VulkanAssertionError("Failed to create DebugCallback", err) callbackHandle } } diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala index 17744b7a..fe3e519c 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala @@ -29,8 +29,7 @@ private[cyfra] class Device(instance: Instance) extends VulkanObject { val pPhysicalDeviceCount = stack.callocInt(1) check(vkEnumeratePhysicalDevices(instance.get, pPhysicalDeviceCount, null), "Failed to get number of physical devices") val deviceCount = pPhysicalDeviceCount.get(0) - if (deviceCount == 0) - throw new AssertionError("Failed to find GPUs with Vulkan support") + if deviceCount == 0 then throw new AssertionError("Failed to find GPUs with Vulkan support") val pPhysicalDevices = stack.callocPointer(deviceCount) check(vkEnumeratePhysicalDevices(instance.get, pPhysicalDeviceCount, pPhysicalDevices), "Failed to get physical devices") @@ -132,7 +131,7 @@ private[cyfra] class Device(instance: Instance) extends VulkanObject { .pQueueCreateInfos(pQueueCreateInfo) .ppEnabledExtensionNames(ppExtensionNames) - if (instance.enabledLayers.contains(ValidationLayer)) { + if instance.enabledLayers.contains(ValidationLayer) then { val ppValidationLayers = stack.callocPointer(1).put(stack.ASCII(ValidationLayer)) pCreateInfo.ppEnabledLayerNames(ppValidationLayers.flip()) } diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala index 036edff0..3d1e8da4 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala @@ -82,8 +82,8 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj lazy val enabledLayers: Seq[String] = List .empty[String] .pipe { x => - if (Instance.layers.contains(ValidationLayer) && enableValidationLayers) ValidationLayer +: x - else if (enableValidationLayers) + if Instance.layers.contains(ValidationLayer) && enableValidationLayers then ValidationLayer +: x + else if enableValidationLayers then logger.error("Validation layers requested but not available") x else x @@ -109,13 +109,11 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj } val extensions = mutable.Buffer.from(Instance.MoltenVkExtensions) - if (enableValidationLayers) - extensions.addAll(Instance.ValidationLayersExtensions) + if enableValidationLayers then extensions.addAll(Instance.ValidationLayersExtensions) val filteredExtensions = extensions.filter(ext => availableExtensions.contains(ext).tap { x => - if (!x) - logger.warn(s"Requested Vulkan instance extension '$ext' is not available") + if !x then logger.warn(s"Requested Vulkan instance extension '$ext' is not available") }, ) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala index 332ec5fb..a55e4a36 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala @@ -46,7 +46,7 @@ private[cyfra] abstract class AbstractExecutor(dataLength: Int, val bufferAction VMA_MEMORY_USAGE_UNKNOWN, allocator, ) - for (i <- bufferActions.indices if bufferActions(i) == BufferAction.LoadTo) do { + for i <- bufferActions.indices if bufferActions(i) == BufferAction.LoadTo do { val buffer = input(i) Buffer.copyBuffer(buffer, stagingBuffer, buffer.remaining()) Buffer.copyBuffer(stagingBuffer, buffers(i), buffer.remaining(), commandPool).block().destroy() diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala index aedc82a4..0d88ff41 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala @@ -54,7 +54,7 @@ private[cyfra] class MapExecutor(dataLength: Int, bufferActions: Seq[BufferActio pushStack { stack => vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get) - val pDescriptorSets = stack.longs(descriptorSets.map(_.get): _*) + val pDescriptorSets = stack.longs(descriptorSets.map(_.get)*) vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.pipelineLayout, 0, pDescriptorSets, null) val workgroup = shader.workgroupDimensions diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala index 1c960d53..86126ebd 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala @@ -87,7 +87,7 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont check(vkBeginCommandBuffer(commandBuffer, commandBufferBeginInfo), "Failed to begin recording command buffer") computeSequence.sequence.foreach { case Compute(pipeline, _) => - if (pipelinesHasDependencies(pipeline)) + if pipelinesHasDependencies(pipeline) then val memoryBarrier = VkMemoryBarrier2 .calloc(1, stack) .sType$Default() @@ -105,7 +105,7 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get) - val pDescriptorSets = stack.longs(pipelineToDescriptorSets(pipeline).map(_.get): _*) + val pDescriptorSets = stack.longs(pipelineToDescriptorSets(pipeline).map(_.get)*) vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.pipelineLayout, 0, pDescriptorSets, null) val workgroup = pipeline.computeShader.workgroupDimensions diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/Util.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/Util.scala index 92a82681..9065f490 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/Util.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/Util.scala @@ -7,5 +7,5 @@ import scala.util.Using object Util { def pushStack[T](f: MemoryStack => T): T = Using(MemoryStack.stackPush())(f).get - def check(err: Int, message: String = ""): Unit = if (err != VK_SUCCESS) throw new VulkanAssertionError(message, err) + def check(err: Int, message: String = ""): Unit = if err != VK_SUCCESS then throw new VulkanAssertionError(message, err) } diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala index 76e66722..efecc480 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala @@ -7,8 +7,7 @@ private[cyfra] abstract class VulkanObject { protected var alive: Boolean = true def destroy(): Unit = { - if (!alive) - throw new IllegalStateException() + if !alive then throw new IllegalStateException() close() alive = false } diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala index e465f040..9ea98538 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala @@ -7,8 +7,6 @@ private[cyfra] abstract class VulkanObjectHandle extends VulkanObject { protected val handle: Long def get: Long = - if (!alive) - throw new IllegalStateException() - else - handle + if !alive then throw new IllegalStateException() + else handle } From 524557b584a84505137c55a3219cc39f4f16c76e Mon Sep 17 00:00:00 2001 From: spamegg Date: Mon, 16 Jun 2025 17:03:21 +0300 Subject: [PATCH 02/59] Github Actions should check if code compiles --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c6c78d3..f4ad9e51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,4 +19,4 @@ jobs: with: jvm: graalvm-java21 apps: sbt - - run: sbt "formatCheckAll" \ No newline at end of file + - run: sbt "formatCheckAll; compile" From 0096f76e967ebd79097776a6aba74938272f13ed Mon Sep 17 00:00:00 2001 From: spamegg Date: Mon, 16 Jun 2025 17:05:51 +0300 Subject: [PATCH 03/59] change job name --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4ad9e51..c47d94a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ on: pull_request: jobs: - format: + format_and_compile: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 From 903f62974afd928ca5a77b3a81f32114207d45ce Mon Sep 17 00:00:00 2001 From: Szymon Date: Mon, 16 Jun 2025 20:07:04 +0200 Subject: [PATCH 04/59] Refactor DSL --- .../cyfra/spirv/BlockBuilder.scala | 1 - .../cyfra/spirv/compilers/DSLCompiler.scala | 2 + .../spirv/compilers/ExpressionCompiler.scala | 5 +- .../spirv/compilers/ExtFunctionCompiler.scala | 5 +- .../spirv/compilers/FunctionCompiler.scala | 6 +- .../cyfra/spirv/compilers/GSeqCompiler.scala | 5 +- .../spirv/compilers/GStructCompiler.scala | 3 +- .../compilers/SpirvProgramCompiler.scala | 3 +- .../cyfra/spirv/compilers/WhenCompiler.scala | 4 +- .../io/computenode/cyfra/dsl/Algebra.scala | 251 ------------------ .../io/computenode/cyfra/dsl/Arrays.scala | 19 -- .../io/computenode/cyfra/dsl/Control.scala | 38 --- .../scala/io/computenode/cyfra/dsl/Dsl.scala | 9 +- .../io/computenode/cyfra/dsl/Expression.scala | 4 +- .../io/computenode/cyfra/dsl/Value.scala | 11 +- .../cyfra/dsl/algebra/ScalarAlgebra.scala | 140 ++++++++++ .../cyfra/dsl/algebra/VectorAlgebra.scala | 163 ++++++++++++ .../cyfra/dsl/collections/GArray.scala | 14 + .../cyfra/dsl/collections/GArray2D.scala | 13 + .../cyfra/dsl/{ => collections}/GSeq.scala | 13 +- .../cyfra/dsl/{ => control}/Pure.scala | 6 +- .../computenode/cyfra/dsl/control/Scope.scala | 7 + .../computenode/cyfra/dsl/control/When.scala | 35 +++ .../cyfra/dsl/{ => library}/Color.scala | 9 +- .../cyfra/dsl/{ => library}/Functions.scala | 5 +- .../cyfra/dsl/{ => library}/Math3D.scala | 9 +- .../cyfra/dsl/{ => library}/Random.scala | 11 +- .../cyfra/dsl/struct/GStruct.scala | 37 +++ .../cyfra/dsl/struct/GStructConstructor.scala | 9 + .../GStructSchema.scala} | 52 +--- .../cyfra/{ => e2e}/juliaset/julia.png | Bin .../cyfra/e2e/ArithmeticTests.scala | 12 +- .../cyfra/e2e/FunctionsTests.scala | 4 +- .../io/computenode/cyfra/e2e/GSeqTests.scala | 6 +- .../computenode/cyfra/e2e/GStructTests.scala | 6 +- .../io/computenode/cyfra/e2e/WhenTests.scala | 5 +- .../cyfra/e2e/juliaset/JuliaSet.scala | 5 +- .../src/main/resources/modelling.scala | 86 ++++++ .../samples/cyfra/foton/AnimatedJulia.scala | 7 +- .../cyfra/foton/AnimatedRaytrace.scala | 6 +- .../samples/cyfra/oldsamples/Raytracing.scala | 2 + .../samples/cyfra/slides/2simpleray.scala | 3 +- .../samples/cyfra/slides/3rays.scala | 4 +- .../samples/cyfra/slides/4random.scala | 4 +- cyfra-foton/src/main/scala/foton/Api.scala | 8 +- .../foton/animation/AnimatedFunction.scala | 2 +- .../animation/AnimatedFunctionRenderer.scala | 6 +- .../foton/animation/AnimationFunctions.scala | 3 +- .../foton/animation/AnimationRenderer.scala | 2 +- .../cyfra/foton/rt/ImageRtRenderer.scala | 6 +- .../computenode/cyfra/foton/rt/Material.scala | 5 +- .../cyfra/foton/rt/RtRenderer.scala | 14 +- .../rt/animation/AnimationRtRenderer.scala | 7 +- .../cyfra/foton/rt/shapes/Box.scala | 9 +- .../cyfra/foton/rt/shapes/Plane.scala | 9 +- .../cyfra/foton/rt/shapes/Quad.scala | 11 +- .../cyfra/foton/rt/shapes/Shape.scala | 4 +- .../foton/rt/shapes/ShapeCollection.scala | 7 +- .../cyfra/foton/rt/shapes/Sphere.scala | 9 +- .../computenode/cyfra/runtime/GContext.scala | 11 +- .../computenode/cyfra/runtime/GFunction.scala | 4 +- .../cyfra/runtime}/UniformContext.scala | 6 +- .../computenode/cyfra/runtime/mem/GMem.scala | 9 +- 63 files changed, 681 insertions(+), 490 deletions(-) delete mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Algebra.scala delete mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Arrays.scala delete mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Control.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala rename cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/{ => collections}/GSeq.scala (92%) rename cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/{ => control}/Pure.scala (73%) create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Scope.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala rename cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/{ => library}/Color.scala (90%) rename cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/{ => library}/Functions.scala (96%) rename cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/{ => library}/Math3D.scala (84%) rename cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/{ => library}/Random.scala (73%) create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructConstructor.scala rename cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/{GStruct.scala => struct/GStructSchema.scala} (58%) rename cyfra-e2e-test/src/test/resources/io/computenode/cyfra/{ => e2e}/juliaset/julia.png (100%) create mode 100644 cyfra-examples/src/main/resources/modelling.scala rename {cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl => cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime}/UniformContext.scala (71%) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala index 26086ae9..b4a6a302 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala @@ -1,6 +1,5 @@ package io.computenode.cyfra.spirv -import io.computenode.cyfra.dsl.Control.Scope import io.computenode.cyfra.dsl.Expression.{E, FunctionCall} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.macros.Source diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala index c0a5d315..4d58ae7f 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala @@ -9,6 +9,8 @@ import SpirvProgramCompiler.* import io.computenode.cyfra.dsl.Expression.E import io.computenode.cyfra.dsl.* import io.computenode.cyfra.dsl.Value.Scalar +import io.computenode.cyfra.dsl.struct.GStruct.* +import io.computenode.cyfra.dsl.struct.GStructSchema import io.computenode.cyfra.spirv.SpirvConstants.* import io.computenode.cyfra.spirv.SpirvTypes.* import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.compileBlock diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala index cf7bc758..8ef41c8d 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala @@ -4,12 +4,15 @@ import io.computenode.cyfra.spirv.Opcodes.* import ExtFunctionCompiler.compileExtFunctionCall import FunctionCompiler.compileFunctionCall import WhenCompiler.compileWhen -import io.computenode.cyfra.dsl.Control.WhenExpr import io.computenode.cyfra.dsl.Expression.* import io.computenode.cyfra.dsl.* import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.macros.Source +import io.computenode.cyfra.dsl.struct.GStruct.{ComposeStruct, GetField} +import io.computenode.cyfra.dsl.struct.GStructSchema import io.computenode.cyfra.spirv.{BlockBuilder, Context} +import io.computenode.cyfra.dsl.collections.GArray.GArrayElem import izumi.reflect.Tag import io.computenode.cyfra.spirv.SpirvConstants.* import io.computenode.cyfra.spirv.SpirvTypes.* diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala index e5fbc7b1..3d3f916f 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala @@ -1,9 +1,10 @@ package io.computenode.cyfra.spirv.compilers import io.computenode.cyfra.dsl.Expression.E -import io.computenode.cyfra.dsl.Functions.FunctionName +import io.computenode.cyfra.dsl.library.Functions.FunctionName import io.computenode.cyfra.spirv.Opcodes.* -import io.computenode.cyfra.dsl.{Expression, Functions} +import io.computenode.cyfra.dsl.Expression +import io.computenode.cyfra.dsl.library.Functions import io.computenode.cyfra.spirv.Context import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction import io.computenode.cyfra.spirv.SpirvConstants.GLSL_EXT_REF diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala index 83e9cd6b..e8910c71 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala @@ -3,13 +3,13 @@ package io.computenode.cyfra.spirv.compilers import io.computenode.cyfra.spirv.Context import io.computenode.cyfra.dsl.Expression.E import io.computenode.cyfra.spirv.Opcodes.* -import io.computenode.cyfra.dsl.{Expression, Functions} +import io.computenode.cyfra.dsl.Expression import io.computenode.cyfra.spirv.Context import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction import io.computenode.cyfra.spirv.SpirvConstants.GLSL_EXT_REF import io.computenode.cyfra.dsl.macros.Source -import io.computenode.cyfra.dsl.Control -import io.computenode.cyfra.dsl.Functions.FunctionName +import io.computenode.cyfra.dsl.library.Functions +import io.computenode.cyfra.dsl.library.Functions.FunctionName import io.computenode.cyfra.dsl.macros.FnCall.FnIdentifier import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.compileBlock import io.computenode.cyfra.spirv.compilers.SpirvProgramCompiler.bubbleUpVars diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala index 769893f2..3a44a2cf 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala @@ -1,9 +1,10 @@ package io.computenode.cyfra.spirv.compilers import io.computenode.cyfra.dsl.Expression.E -import io.computenode.cyfra.dsl.GSeq.* +import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.collections.GSeq.* import io.computenode.cyfra.spirv.Opcodes.* -import io.computenode.cyfra.spirv.{Context, BlockBuilder} +import io.computenode.cyfra.spirv.{BlockBuilder, Context} import izumi.reflect.Tag import io.computenode.cyfra.spirv.SpirvConstants.* import io.computenode.cyfra.spirv.SpirvTypes.* diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala index 8275708c..d495444d 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala @@ -1,7 +1,8 @@ package io.computenode.cyfra.spirv.compilers +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} +import io.computenode.cyfra.dsl.struct.GStructSchema.* import io.computenode.cyfra.spirv.Opcodes.* -import io.computenode.cyfra.dsl.{GStruct, GStructSchema} import io.computenode.cyfra.spirv.Context import izumi.reflect.Tag import izumi.reflect.macrortti.LightTypeTag diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index a5798505..32828fc2 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -2,8 +2,9 @@ package io.computenode.cyfra.spirv.compilers import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.dsl.Expression.{Const, E} +import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.{GStructSchema, Value, GStructConstructor} +import io.computenode.cyfra.dsl.struct.{GStructConstructor, GStructSchema} import io.computenode.cyfra.spirv.Context import io.computenode.cyfra.spirv.SpirvConstants.* import io.computenode.cyfra.spirv.SpirvTypes.* diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala index 1976788b..9a889b8f 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala @@ -2,9 +2,9 @@ package io.computenode.cyfra.spirv.compilers import ExpressionCompiler.compileBlock import io.computenode.cyfra.spirv.Opcodes.* -import io.computenode.cyfra.dsl.Control.WhenExpr import io.computenode.cyfra.dsl.Expression.E -import io.computenode.cyfra.spirv.{Context, BlockBuilder} +import io.computenode.cyfra.dsl.control.When.WhenExpr +import io.computenode.cyfra.spirv.{BlockBuilder, Context} import izumi.reflect.Tag import io.computenode.cyfra.spirv.SpirvConstants.* import io.computenode.cyfra.spirv.SpirvTypes.* diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Algebra.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Algebra.scala deleted file mode 100644 index ff863778..00000000 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Algebra.scala +++ /dev/null @@ -1,251 +0,0 @@ -package io.computenode.cyfra.dsl - -import Algebra.FromExpr -import io.computenode.cyfra.dsl.Control.when -import io.computenode.cyfra.dsl.Expression.* -import io.computenode.cyfra.dsl.Functions.* -import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.macros.Source -import izumi.reflect.Tag - -import scala.annotation.targetName -import scala.language.implicitConversions - -object Algebra: - - trait FromExpr[T <: Value]: - def fromExpr(expr: E[T])(using name: Source): T - - trait ScalarSummable[T <: Scalar: FromExpr: Tag]: - def sum(a: T, b: T)(using name: Source): T = summon[FromExpr[T]].fromExpr(Sum(a, b)) - extension [T <: Scalar: ScalarSummable: Tag](a: T) - @targetName("add") - inline def +(b: T)(using Source): T = summon[ScalarSummable[T]].sum(a, b) - - trait ScalarDiffable[T <: Scalar: FromExpr: Tag]: - def diff(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Diff(a, b)) - extension [T <: Scalar: ScalarDiffable: Tag](a: T) - @targetName("sub") - inline def -(b: T)(using Source): T = summon[ScalarDiffable[T]].diff(a, b) - - // T and S ??? so two - trait ScalarMulable[T <: Scalar: FromExpr: Tag]: - def mul(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Mul(a, b)) - extension [T <: Scalar: ScalarMulable: Tag](a: T) - @targetName("mul") - inline def *(b: T)(using Source): T = summon[ScalarMulable[T]].mul(a, b) - - trait ScalarDivable[T <: Scalar: FromExpr: Tag]: - def div(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Div(a, b)) - extension [T <: Scalar: ScalarDivable: Tag](a: T) - @targetName("div") - inline def /(b: T)(using Source): T = summon[ScalarDivable[T]].div(a, b) - - trait ScalarNegatable[T <: Scalar: FromExpr: Tag]: - def negate(a: T)(using Source): T = summon[FromExpr[T]].fromExpr(Negate(a)) - extension [T <: Scalar: ScalarNegatable: Tag](a: T) - @targetName("negate") - inline def unary_-(using Source): T = summon[ScalarNegatable[T]].negate(a) - - trait ScalarModable[T <: Scalar: FromExpr: Tag]: - def mod(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Mod(a, b)) - extension [T <: Scalar: ScalarModable: Tag](a: T) inline infix def mod(b: T)(using Source): T = summon[ScalarModable[T]].mod(a, b) - - trait Comparable[T <: Scalar: FromExpr: Tag]: - def greaterThan(a: T, b: T)(using Source): GBoolean = GBoolean(GreaterThan(a, b)) - def lessThan(a: T, b: T)(using Source): GBoolean = GBoolean(LessThan(a, b)) - def greaterThanEqual(a: T, b: T)(using Source): GBoolean = GBoolean(GreaterThanEqual(a, b)) - def lessThanEqual(a: T, b: T)(using Source): GBoolean = GBoolean(LessThanEqual(a, b)) - def equal(a: T, b: T)(using Source): GBoolean = GBoolean(Equal(a, b)) - extension [T <: Scalar: Comparable: Tag](a: T) - inline def >(b: T)(using Source): GBoolean = summon[Comparable[T]].greaterThan(a, b) - inline def <(b: T)(using Source): GBoolean = summon[Comparable[T]].lessThan(a, b) - inline def >=(b: T)(using Source): GBoolean = summon[Comparable[T]].greaterThanEqual(a, b) - inline def <=(b: T)(using Source): GBoolean = summon[Comparable[T]].lessThanEqual(a, b) - inline def ===(b: T)(using Source): GBoolean = summon[Comparable[T]].equal(a, b) - - case class Epsilon(eps: Float) - given Epsilon = Epsilon(0.00001f) - - extension (f32: Float32) - inline def asInt(using Source): Int32 = Int32(ToInt32(f32)) - inline def =~=(other: Float32)(using epsilon: Epsilon): GBoolean = - abs(f32 - other) < epsilon.eps - - extension (i32: Int32) - inline def asFloat(using Source): Float32 = Float32(ToFloat32(i32)) - inline def unsigned(using Source): UInt32 = UInt32(ToUInt32(i32)) - - extension (u32: UInt32) - inline def asFloat(using Source): Float32 = Float32(ToFloat32(u32)) - inline def signed(using Source): Int32 = Int32(ToInt32(u32)) - - trait VectorSummable[V <: Vec[?]: FromExpr: Tag]: - def sum(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Sum(a, b)) - extension [V <: Vec[?]: VectorSummable: Tag](a: V) - @targetName("addVector") - inline def +(b: V)(using Source): V = summon[VectorSummable[V]].sum(a, b) - - trait VectorDiffable[V <: Vec[?]: FromExpr: Tag]: - def diff(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Diff(a, b)) - extension [V <: Vec[?]: VectorDiffable: Tag](a: V) - @targetName("subVector") - inline def -(b: V)(using Source): V = summon[VectorDiffable[V]].diff(a, b) - - trait VectorDotable[S <: Scalar: FromExpr: Tag, V <: Vec[S]: Tag]: - def dot(a: V, b: V)(using Source): S = summon[FromExpr[S]].fromExpr(DotProd[S, V](a, b)) - extension [S <: Scalar: Tag, V <: Vec[S]: Tag](a: V)(using VectorDotable[S, V]) - infix def dot(b: V)(using Source): S = summon[VectorDotable[S, V]].dot(a, b) - - trait VectorCrossable[V <: Vec[?]: FromExpr: Tag]: - def cross(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Cross, List(a, b))) - extension [V <: Vec[?]: VectorCrossable: Tag](a: V) infix def cross(b: V)(using Source): V = summon[VectorCrossable[V]].cross(a, b) - - trait VectorScalarMulable[S <: Scalar: Tag, V <: Vec[S]: FromExpr: Tag]: - def mul(a: V, b: S)(using Source): V = summon[FromExpr[V]].fromExpr(ScalarProd[S, V](a, b)) - extension [S <: Scalar: Tag, V <: Vec[S]: Tag](a: V)(using VectorScalarMulable[S, V]) - def *(b: S)(using Source): V = summon[VectorScalarMulable[S, V]].mul(a, b) - extension [S <: Scalar: Tag, V <: Vec[S]: Tag](s: S)(using VectorScalarMulable[S, V]) - def *(v: V)(using Source): V = summon[VectorScalarMulable[S, V]].mul(v, s) - - trait VectorNegatable[V <: Vec[?]: FromExpr: Tag]: - def negate(a: V)(using Source): V = summon[FromExpr[V]].fromExpr(Negate(a)) - extension [V <: Vec[?]: VectorNegatable: Tag](a: V) - @targetName("negateVector") - def unary_-(using Source): V = summon[VectorNegatable[V]].negate(a) - - trait BitwiseOperable[T <: Scalar: FromExpr: Tag]: - def bitwiseAnd(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseAnd(a, b)) - def bitwiseOr(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseOr(a, b)) - def bitwiseXor(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseXor(a, b)) - def bitwiseNot(a: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseNot(a)) - def shiftLeft(a: T, by: UInt32)(using Source): T = summon[FromExpr[T]].fromExpr(ShiftLeft(a, by)) - def shiftRight(a: T, by: UInt32)(using Source): T = summon[FromExpr[T]].fromExpr(ShiftRight(a, by)) - - extension [T <: Scalar: BitwiseOperable: Tag](a: T) - inline def &(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseAnd(a, b) - inline def |(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseOr(a, b) - inline def ^(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseXor(a, b) - inline def unary_~(using Source): T = summon[BitwiseOperable[T]].bitwiseNot(a) - inline def <<(by: UInt32)(using Source): T = summon[BitwiseOperable[T]].shiftLeft(a, by) - inline def >>(by: UInt32)(using Source): T = summon[BitwiseOperable[T]].shiftRight(a, by) - - trait BasicScalarAlgebra[T <: Scalar: FromExpr: Tag] - extends ScalarSummable[T] - with ScalarDiffable[T] - with ScalarMulable[T] - with ScalarDivable[T] - with ScalarModable[T] - with Comparable[T] - with ScalarNegatable[T] - - trait BasicScalarIntAlgebra[T <: Scalar: FromExpr: Tag] extends BasicScalarAlgebra[T] with BitwiseOperable[T] - - trait BasicVectorAlgebra[S <: Scalar, V <: Vec[S]: FromExpr: Tag] - extends VectorSummable[V] - with VectorDiffable[V] - with VectorDotable[S, V] - with VectorCrossable[V] - with VectorScalarMulable[S, V] - with VectorNegatable[V] - - given BasicScalarAlgebra[Float32] = new BasicScalarAlgebra[Float32] {} - given BasicScalarIntAlgebra[Int32] = new BasicScalarIntAlgebra[Int32] {} - given BasicScalarIntAlgebra[UInt32] = new BasicScalarIntAlgebra[UInt32] {} - - given [T <: Scalar: FromExpr: Tag]: BasicVectorAlgebra[T, Vec2[T]] = new BasicVectorAlgebra[T, Vec2[T]] {} - given [T <: Scalar: FromExpr: Tag]: BasicVectorAlgebra[T, Vec3[T]] = new BasicVectorAlgebra[T, Vec3[T]] {} - given [T <: Scalar: FromExpr: Tag]: BasicVectorAlgebra[T, Vec4[T]] = new BasicVectorAlgebra[T, Vec4[T]] {} - - given (using Source): Conversion[Float, Float32] = f => Float32(ConstFloat32(f)) - given (using Source): Conversion[Int, Int32] = i => Int32(ConstInt32(i)) - given (using Source): Conversion[Int, UInt32] = i => UInt32(ConstUInt32(i)) - given (using Source): Conversion[Boolean, GBoolean] = b => GBoolean(ConstGB(b)) - - type FloatOrFloat32 = Float | Float32 - - inline def toFloat32(f: FloatOrFloat32)(using Source): Float32 = f match - case f: Float => Float32(ConstFloat32(f)) - case f: Float32 => f - given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32), Vec2[Float32]] = { case (x, y) => - Vec2(ComposeVec2(toFloat32(x), toFloat32(y))) - } - - given (using Source): Conversion[(Int, Int), Vec2[Int32]] = { case (x, y) => - Vec2(ComposeVec2(Int32(ConstInt32(x)), Int32(ConstInt32(y)))) - } - - given (using Source): Conversion[(Int32, Int32), Vec2[Int32]] = { case (x, y) => - Vec2(ComposeVec2(x, y)) - } - - given (using Source): Conversion[(Int32, Int32, Int32), Vec3[Int32]] = { case (x, y, z) => - Vec3(ComposeVec3(x, y, z)) - } - - given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32, FloatOrFloat32), Vec3[Float32]] = { case (x, y, z) => - Vec3(ComposeVec3(toFloat32(x), toFloat32(y), toFloat32(z))) - } - - given (using Source): Conversion[(Int, Int, Int), Vec3[Int32]] = { case (x, y, z) => - Vec3(ComposeVec3(Int32(ConstInt32(x)), Int32(ConstInt32(y)), Int32(ConstInt32(z)))) - } - - given (using Source): Conversion[(Int32, Int32, Int32, Int32), Vec4[Int32]] = { case (x, y, z, w) => - Vec4(ComposeVec4(x, y, z, w)) - } - given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32, FloatOrFloat32, FloatOrFloat32), Vec4[Float32]] = { case (x, y, z, w) => - Vec4(ComposeVec4(toFloat32(x), toFloat32(y), toFloat32(z), toFloat32(w))) - } - given (using Source): Conversion[(Vec3[Float32], FloatOrFloat32), Vec4[Float32]] = { case (v, w) => - Vec4(ComposeVec4(v.x, v.y, v.z, toFloat32(w))) - } - - extension [T <: Scalar: FromExpr: Tag](v2: Vec2[T]) - inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v2, Int32(ConstInt32(0)))) - inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v2, Int32(ConstInt32(1)))) - - extension [T <: Scalar: FromExpr: Tag](v3: Vec3[T]) - inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(0)))) - inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(1)))) - inline def z(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(2)))) - inline def r(using Source): T = x - inline def g(using Source): T = y - inline def b(using Source): T = z - - extension [T <: Scalar: FromExpr: Tag](v4: Vec4[T]) - inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(0)))) - inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(1)))) - inline def z(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(2)))) - inline def w(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(3)))) - inline def r(using Source): T = x - inline def g(using Source): T = y - inline def b(using Source): T = z - inline def a(using Source): T = w - inline def xyz(using Source): Vec3[T] = Vec3(ComposeVec3(x, y, z)) - inline def rgb(using Source): Vec3[T] = xyz - - extension (b: GBoolean) - def &&(other: GBoolean)(using Source): GBoolean = GBoolean(And(b, other)) - def ||(other: GBoolean)(using Source): GBoolean = GBoolean(Or(b, other)) - def unary_!(using Source): GBoolean = GBoolean(Not(b)) - - def vec4(x: FloatOrFloat32, y: FloatOrFloat32, z: FloatOrFloat32, w: FloatOrFloat32)(using Source): Vec4[Float32] = - Vec4(ComposeVec4(toFloat32(x), toFloat32(y), toFloat32(z), toFloat32(w))) - def vec3(x: FloatOrFloat32, y: FloatOrFloat32, z: FloatOrFloat32)(using Source): Vec3[Float32] = - Vec3(ComposeVec3(toFloat32(x), toFloat32(y), toFloat32(z))) - def vec2(x: FloatOrFloat32, y: FloatOrFloat32)(using Source): Vec2[Float32] = - Vec2(ComposeVec2(toFloat32(x), toFloat32(y))) - - def vec4(f: FloatOrFloat32)(using Source): Vec4[Float32] = (f, f, f, f) - def vec3(f: FloatOrFloat32)(using Source): Vec3[Float32] = (f, f, f) - def vec2(f: FloatOrFloat32)(using Source): Vec2[Float32] = (f, f) - - // todo below is temporary cache for functions not put as direct functions, replace below ones w/ ext functions - extension (v: Vec3[Float32]) - inline infix def mulV(v2: Vec3[Float32]): Vec3[Float32] = (v.x * v2.x, v.y * v2.y, v.z * v2.z) - inline infix def addV(v2: Vec3[Float32]): Vec3[Float32] = (v.x + v2.x, v.y + v2.y, v.z + v2.z) - inline infix def divV(v2: Vec3[Float32]): Vec3[Float32] = (v.x / v2.x, v.y / v2.y, v.z / v2.z) - - inline def vclamp(v: Vec3[Float32], min: Float32, max: Float32)(using Source): Vec3[Float32] = - (clamp(v.x, min, max), clamp(v.y, min, max), clamp(v.z, min, max)) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Arrays.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Arrays.scala deleted file mode 100644 index 94fb33a8..00000000 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Arrays.scala +++ /dev/null @@ -1,19 +0,0 @@ -package io.computenode.cyfra.dsl - -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.macros.Source -import io.computenode.cyfra.dsl.{GArray, GArrayElem} -import izumi.reflect.Tag - -case class GArray[T <: Value: Tag: FromExpr](index: Int) { - def at(i: Int32)(using Source): T = - summon[FromExpr[T]].fromExpr(GArrayElem(index, i.tree)) -} - -class GArray2D[T <: Value: Tag: FromExpr](width: Int, val arr: GArray[T]) { - def at(x: Int32, y: Int32)(using Source): T = - arr.at(y * width + x) -} - -case class GArrayElem[T <: Value: Tag](index: Int, i: Expression[Int32]) extends Expression[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Control.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Control.scala deleted file mode 100644 index 68a5c1b4..00000000 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Control.scala +++ /dev/null @@ -1,38 +0,0 @@ -package io.computenode.cyfra.dsl - -import io.computenode.cyfra.dsl.Algebra.FromExpr -import io.computenode.cyfra.dsl.Expression.E -import io.computenode.cyfra.dsl.Value.GBoolean -import io.computenode.cyfra.dsl.macros.Source -import izumi.reflect.Tag - -import java.util.UUID - -object Control: - - case class Scope[T <: Value: Tag](expr: Expression[T], isDetached: Boolean = false): - def rootTreeId: Int = expr.treeid - - case class When[T <: Value: Tag: FromExpr]( - when: GBoolean, - thenCode: T, - otherConds: List[Scope[GBoolean]], - otherCases: List[Scope[T]], - name: Source, - ): - def elseWhen(cond: GBoolean)(t: T): When[T] = - When(when, thenCode, otherConds :+ Scope(cond.tree), otherCases :+ Scope(t.tree.asInstanceOf[E[T]]), name) - infix def otherwise(t: T): T = - summon[FromExpr[T]] - .fromExpr(WhenExpr(when, Scope(thenCode.tree.asInstanceOf[E[T]]), otherConds, otherCases, Scope(t.tree.asInstanceOf[E[T]])))(using name) - - case class WhenExpr[T <: Value: Tag]( - when: GBoolean, - thenCode: Scope[T], - otherConds: List[Scope[GBoolean]], - otherCaseCodes: List[Scope[T]], - otherwise: Scope[T], - ) extends Expression[T] - - def when[T <: Value: Tag: FromExpr](cond: GBoolean)(fn: T)(using name: Source): When[T] = - When(cond, fn, Nil, Nil, name) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Dsl.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Dsl.scala index 2e73ff6e..3ad78773 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Dsl.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Dsl.scala @@ -4,8 +4,7 @@ package io.computenode.cyfra.dsl export io.computenode.cyfra.dsl.Value.* export io.computenode.cyfra.dsl.Expression.* -export io.computenode.cyfra.dsl.Algebra.* -export io.computenode.cyfra.dsl.Control.* -export io.computenode.cyfra.dsl.Functions.* - -export io.computenode.cyfra.dsl.Algebra.given +export io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} +export io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +export io.computenode.cyfra.dsl.control.When.* +export io.computenode.cyfra.dsl.library.Functions.* diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala index 4866d7c8..707b637b 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala @@ -1,9 +1,9 @@ package io.computenode.cyfra.dsl -import io.computenode.cyfra.dsl.Control.Scope import io.computenode.cyfra.dsl.Expression import Expression.{Const, treeidState} -import io.computenode.cyfra.dsl.Functions.* +import io.computenode.cyfra.dsl.library.Functions.* import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.control.Scope import io.computenode.cyfra.dsl.macros.FnCall.FnIdentifier import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala index 91b3a9f4..efc0cfe0 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala @@ -1,8 +1,7 @@ package io.computenode.cyfra.dsl import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Algebra.* -import io.computenode.cyfra.dsl.Expression.E +import io.computenode.cyfra.dsl.Expression.{E, E as T} import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag @@ -14,7 +13,11 @@ trait Value: tree.of = Some(this) init() -object Value { +object Value: + + trait FromExpr[T <: Value]: + def fromExpr(expr: E[T])(using name: Source): T + sealed trait Scalar extends Value trait FloatType extends Scalar @@ -49,5 +52,3 @@ object Value { case class Vec4[T <: Value](tree: E[Vec4[T]])(using val source: Source) extends Vec[T] given [T <: Scalar]: FromExpr[Vec4[T]] with def fromExpr(f: E[Vec4[T]])(using Source) = Vec4(f) - -} diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala new file mode 100644 index 00000000..f7acecd8 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala @@ -0,0 +1,140 @@ +package io.computenode.cyfra.dsl.algebra + +import io.computenode.cyfra.dsl.Expression.ConstFloat32 +import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.Expression.* +import io.computenode.cyfra.dsl.library.Functions.abs +import io.computenode.cyfra.dsl.macros.Source +import izumi.reflect.Tag + +import scala.annotation.targetName + +object ScalarAlgebra: + + trait BasicScalarAlgebra[T <: Scalar : FromExpr : Tag] + extends ScalarSummable[T] + with ScalarDiffable[T] + with ScalarMulable[T] + with ScalarDivable[T] + with ScalarModable[T] + with Comparable[T] + with ScalarNegatable[T] + + trait BasicScalarIntAlgebra[T <: Scalar : FromExpr : Tag] extends BasicScalarAlgebra[T] with BitwiseOperable[T] + + given BasicScalarAlgebra[Float32] = new BasicScalarAlgebra[Float32] {} + given BasicScalarIntAlgebra[Int32] = new BasicScalarIntAlgebra[Int32] {} + given BasicScalarIntAlgebra[UInt32] = new BasicScalarIntAlgebra[UInt32] {} + + trait ScalarSummable[T <: Scalar : FromExpr : Tag]: + def sum(a: T, b: T)(using name: Source): T = summon[FromExpr[T]].fromExpr(Sum(a, b)) + + extension [T <: Scalar : ScalarSummable : Tag](a: T) + @targetName("add") + inline def +(b: T)(using Source): T = summon[ScalarSummable[T]].sum(a, b) + + trait ScalarDiffable[T <: Scalar : FromExpr : Tag]: + def diff(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Diff(a, b)) + + extension [T <: Scalar : ScalarDiffable : Tag](a: T) + @targetName("sub") + inline def -(b: T)(using Source): T = summon[ScalarDiffable[T]].diff(a, b) + + // T and S ??? so two + trait ScalarMulable[T <: Scalar : FromExpr : Tag]: + def mul(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Mul(a, b)) + + extension [T <: Scalar : ScalarMulable : Tag](a: T) + @targetName("mul") + inline def *(b: T)(using Source): T = summon[ScalarMulable[T]].mul(a, b) + + trait ScalarDivable[T <: Scalar : FromExpr : Tag]: + def div(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Div(a, b)) + + extension [T <: Scalar : ScalarDivable : Tag](a: T) + @targetName("div") + inline def /(b: T)(using Source): T = summon[ScalarDivable[T]].div(a, b) + + trait ScalarNegatable[T <: Scalar : FromExpr : Tag]: + def negate(a: T)(using Source): T = summon[FromExpr[T]].fromExpr(Negate(a)) + + extension [T <: Scalar : ScalarNegatable : Tag](a: T) + @targetName("negate") + inline def unary_-(using Source): T = summon[ScalarNegatable[T]].negate(a) + + trait ScalarModable[T <: Scalar : FromExpr : Tag]: + def mod(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Mod(a, b)) + + extension [T <: Scalar : ScalarModable : Tag](a: T) inline infix def mod(b: T)(using Source): T = summon[ScalarModable[T]].mod(a, b) + + trait Comparable[T <: Scalar : FromExpr : Tag]: + def greaterThan(a: T, b: T)(using Source): GBoolean = GBoolean(GreaterThan(a, b)) + + def lessThan(a: T, b: T)(using Source): GBoolean = GBoolean(LessThan(a, b)) + + def greaterThanEqual(a: T, b: T)(using Source): GBoolean = GBoolean(GreaterThanEqual(a, b)) + + def lessThanEqual(a: T, b: T)(using Source): GBoolean = GBoolean(LessThanEqual(a, b)) + + def equal(a: T, b: T)(using Source): GBoolean = GBoolean(Equal(a, b)) + + extension [T <: Scalar : Comparable : Tag](a: T) + inline def >(b: T)(using Source): GBoolean = summon[Comparable[T]].greaterThan(a, b) + inline def <(b: T)(using Source): GBoolean = summon[Comparable[T]].lessThan(a, b) + inline def >=(b: T)(using Source): GBoolean = summon[Comparable[T]].greaterThanEqual(a, b) + inline def <=(b: T)(using Source): GBoolean = summon[Comparable[T]].lessThanEqual(a, b) + inline def ===(b: T)(using Source): GBoolean = summon[Comparable[T]].equal(a, b) + + case class Epsilon(eps: Float) + + given Epsilon = Epsilon(0.00001f) + + extension (f32: Float32) + inline def asInt(using Source): Int32 = Int32(ToInt32(f32)) + inline def =~=(other: Float32)(using epsilon: Epsilon): GBoolean = + abs(f32 - other) < epsilon.eps + + extension (i32: Int32) + inline def asFloat(using Source): Float32 = Float32(ToFloat32(i32)) + inline def unsigned(using Source): UInt32 = UInt32(ToUInt32(i32)) + + extension (u32: UInt32) + inline def asFloat(using Source): Float32 = Float32(ToFloat32(u32)) + inline def signed(using Source): Int32 = Int32(ToInt32(u32)) + + trait BitwiseOperable[T <: Scalar : FromExpr : Tag]: + def bitwiseAnd(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseAnd(a, b)) + + def bitwiseOr(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseOr(a, b)) + + def bitwiseXor(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseXor(a, b)) + + def bitwiseNot(a: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseNot(a)) + + def shiftLeft(a: T, by: UInt32)(using Source): T = summon[FromExpr[T]].fromExpr(ShiftLeft(a, by)) + + def shiftRight(a: T, by: UInt32)(using Source): T = summon[FromExpr[T]].fromExpr(ShiftRight(a, by)) + + extension [T <: Scalar : BitwiseOperable : Tag](a: T) + inline def &(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseAnd(a, b) + inline def |(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseOr(a, b) + inline def ^(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseXor(a, b) + inline def unary_~(using Source): T = summon[BitwiseOperable[T]].bitwiseNot(a) + inline def <<(by: UInt32)(using Source): T = summon[BitwiseOperable[T]].shiftLeft(a, by) + inline def >>(by: UInt32)(using Source): T = summon[BitwiseOperable[T]].shiftRight(a, by) + + given (using Source): Conversion[Float, Float32] = f => Float32(ConstFloat32(f)) + given (using Source): Conversion[Int, Int32] = i => Int32(ConstInt32(i)) + given (using Source): Conversion[Int, UInt32] = i => UInt32(ConstUInt32(i)) + given (using Source): Conversion[Boolean, GBoolean] = b => GBoolean(ConstGB(b)) + + type FloatOrFloat32 = Float | Float32 + + inline def toFloat32(f: FloatOrFloat32)(using Source): Float32 = f match + case f: Float => Float32(ConstFloat32(f)) + case f: Float32 => f + + extension (b: GBoolean) + def &&(other: GBoolean)(using Source): GBoolean = GBoolean(And(b, other)) + def ||(other: GBoolean)(using Source): GBoolean = GBoolean(Or(b, other)) + def unary_!(using Source): GBoolean = GBoolean(Not(b)) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala new file mode 100644 index 00000000..98f1dd67 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala @@ -0,0 +1,163 @@ +package io.computenode.cyfra.dsl.algebra + +import io.computenode.cyfra.dsl.Expression.* +import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +import io.computenode.cyfra.dsl.library.Functions.{Cross, clamp} +import io.computenode.cyfra.dsl.macros.Source +import izumi.reflect.Tag + +import scala.annotation.targetName + +object VectorAlgebra: + + trait BasicVectorAlgebra[S <: Scalar, V <: Vec[S] : FromExpr : Tag] + extends VectorSummable[V] + with VectorDiffable[V] + with VectorDotable[S, V] + with VectorCrossable[V] + with VectorScalarMulable[S, V] + with VectorNegatable[V] + + given [T <: Scalar : FromExpr : Tag]: BasicVectorAlgebra[T, Vec2[T]] = new BasicVectorAlgebra[T, Vec2[T]] {} + given [T <: Scalar : FromExpr : Tag]: BasicVectorAlgebra[T, Vec3[T]] = new BasicVectorAlgebra[T, Vec3[T]] {} + given [T <: Scalar : FromExpr : Tag]: BasicVectorAlgebra[T, Vec4[T]] = new BasicVectorAlgebra[T, Vec4[T]] {} + + trait VectorSummable[V <: Vec[?] : FromExpr : Tag]: + def sum(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Sum(a, b)) + + extension [V <: Vec[?] : VectorSummable : Tag](a: V) + @targetName("addVector") + inline def +(b: V)(using Source): V = summon[VectorSummable[V]].sum(a, b) + + trait VectorDiffable[V <: Vec[?] : FromExpr : Tag]: + def diff(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Diff(a, b)) + + extension [V <: Vec[?] : VectorDiffable : Tag](a: V) + @targetName("subVector") + inline def -(b: V)(using Source): V = summon[VectorDiffable[V]].diff(a, b) + + trait VectorDotable[S <: Scalar : FromExpr : Tag, V <: Vec[S] : Tag]: + def dot(a: V, b: V)(using Source): S = summon[FromExpr[S]].fromExpr(DotProd[S, V](a, b)) + + extension [S <: Scalar : Tag, V <: Vec[S] : Tag](a: V)(using VectorDotable[S, V]) + infix def dot(b: V)(using Source): S = summon[VectorDotable[S, V]].dot(a, b) + + trait VectorCrossable[V <: Vec[?] : FromExpr : Tag]: + def cross(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Cross, List(a, b))) + + extension [V <: Vec[?] : VectorCrossable : Tag](a: V) infix def cross(b: V)(using Source): V = summon[VectorCrossable[V]].cross(a, b) + + trait VectorScalarMulable[S <: Scalar : Tag, V <: Vec[S] : FromExpr : Tag]: + def mul(a: V, b: S)(using Source): V = summon[FromExpr[V]].fromExpr(ScalarProd[S, V](a, b)) + + extension [S <: Scalar : Tag, V <: Vec[S] : Tag](a: V)(using VectorScalarMulable[S, V]) + def *(b: S)(using Source): V = summon[VectorScalarMulable[S, V]].mul(a, b) + extension [S <: Scalar : Tag, V <: Vec[S] : Tag](s: S)(using VectorScalarMulable[S, V]) + def *(v: V)(using Source): V = summon[VectorScalarMulable[S, V]].mul(v, s) + + trait VectorNegatable[V <: Vec[?] : FromExpr : Tag]: + def negate(a: V)(using Source): V = summon[FromExpr[V]].fromExpr(Negate(a)) + + extension [V <: Vec[?] : VectorNegatable : Tag](a: V) + @targetName("negateVector") + def unary_-(using Source): V = summon[VectorNegatable[V]].negate(a) + + def vec4(x: FloatOrFloat32, y: FloatOrFloat32, z: FloatOrFloat32, w: FloatOrFloat32)(using Source): Vec4[Float32] = + Vec4(ComposeVec4(toFloat32(x), toFloat32(y), toFloat32(z), toFloat32(w))) + + def vec3(x: FloatOrFloat32, y: FloatOrFloat32, z: FloatOrFloat32)(using Source): Vec3[Float32] = + Vec3(ComposeVec3(toFloat32(x), toFloat32(y), toFloat32(z))) + + def vec2(x: FloatOrFloat32, y: FloatOrFloat32)(using Source): Vec2[Float32] = + Vec2(ComposeVec2(toFloat32(x), toFloat32(y))) + + def vec4(f: FloatOrFloat32)(using Source): Vec4[Float32] = (f, f, f, f) + + def vec3(f: FloatOrFloat32)(using Source): Vec3[Float32] = (f, f, f) + + def vec2(f: FloatOrFloat32)(using Source): Vec2[Float32] = (f, f) + + // todo below is temporary cache for functions not put as direct functions, replace below ones w/ ext functions + extension (v: Vec3[Float32]) + // Hadamard product + inline infix def mulV(v2: Vec3[Float32]): Vec3[Float32] = + val s = summon[ScalarMulable[Float32]] + (s.mul(v.x, v2.x), s.mul(v.y, v2.y), s.mul(v.z, v2.z)) + inline infix def addV(v2: Vec3[Float32]): Vec3[Float32] = + val s = summon[VectorSummable[Vec3[Float32]]] + s.sum(v, v2) + inline infix def divV(v2: Vec3[Float32]): Vec3[Float32] = (v.x / v2.x, v.y / v2.y, v.z / v2.z) + + inline def vclamp(v: Vec3[Float32], min: Float32, max: Float32)(using Source): Vec3[Float32] = + (clamp(v.x, min, max), clamp(v.y, min, max), clamp(v.z, min, max)) + + extension [T <: Scalar : FromExpr : Tag](v2: Vec2[T]) + inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v2, Int32(ConstInt32(0)))) + inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v2, Int32(ConstInt32(1)))) + + extension [T <: Scalar : FromExpr : Tag](v3: Vec3[T]) + inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(0)))) + inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(1)))) + inline def z(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(2)))) + inline def r(using Source): T = x + inline def g(using Source): T = y + inline def b(using Source): T = z + + extension [T <: Scalar : FromExpr : Tag](v4: Vec4[T]) + inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(0)))) + inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(1)))) + inline def z(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(2)))) + inline def w(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(3)))) + inline def r(using Source): T = x + inline def g(using Source): T = y + inline def b(using Source): T = z + inline def a(using Source): T = w + inline def xyz(using Source): Vec3[T] = Vec3(ComposeVec3(x, y, z)) + inline def rgb(using Source): Vec3[T] = xyz + + + given (using Source): Conversion[(Int, Int), Vec2[Int32]] = { + case (x, y) => + Vec2(ComposeVec2(Int32(ConstInt32(x)), Int32(ConstInt32(y)))) + } + + given (using Source): Conversion[(Int32, Int32), Vec2[Int32]] = { + case (x, y) => + Vec2(ComposeVec2(x, y)) + } + + given (using Source): Conversion[(Int32, Int32, Int32), Vec3[Int32]] = { + case (x, y, z) => + Vec3(ComposeVec3(x, y, z)) + } + + given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32, FloatOrFloat32), Vec3[Float32]] = { + case (x, y, z) => + Vec3(ComposeVec3(toFloat32(x), toFloat32(y), toFloat32(z))) + } + + given (using Source): Conversion[(Int, Int, Int), Vec3[Int32]] = { + case (x, y, z) => + Vec3(ComposeVec3(Int32(ConstInt32(x)), Int32(ConstInt32(y)), Int32(ConstInt32(z)))) + } + + given (using Source): Conversion[(Int32, Int32, Int32, Int32), Vec4[Int32]] = { + case (x, y, z, w) => + Vec4(ComposeVec4(x, y, z, w)) + } + + given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32, FloatOrFloat32, FloatOrFloat32), Vec4[Float32]] = { + case (x, y, z, w) => + Vec4(ComposeVec4(toFloat32(x), toFloat32(y), toFloat32(z), toFloat32(w))) + } + + given (using Source): Conversion[(Vec3[Float32], FloatOrFloat32), Vec4[Float32]] = { + case (v, w) => + Vec4(ComposeVec4(v.x, v.y, v.z, toFloat32(w))) + } + + given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32), Vec2[Float32]] = { + case (x, y) => + Vec2(ComposeVec2(toFloat32(x), toFloat32(y))) + } diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala new file mode 100644 index 00000000..f91383a0 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala @@ -0,0 +1,14 @@ +package io.computenode.cyfra.dsl.collections + +import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.collections.GArray.GArrayElem +import io.computenode.cyfra.dsl.macros.Source +import io.computenode.cyfra.dsl.{Expression, Value} +import izumi.reflect.Tag + +case class GArray[T <: Value: Tag: FromExpr](index: Int): + def at(i: Int32)(using Source): T = + summon[FromExpr[T]].fromExpr(GArrayElem(index, i.tree)) + +object GArray: + case class GArrayElem[T <: Value: Tag](index: Int, i: Expression[Int32]) extends Expression[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala new file mode 100644 index 00000000..46f60e9d --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala @@ -0,0 +1,13 @@ +package io.computenode.cyfra.dsl.collections + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.Int32 +import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +import io.computenode.cyfra.dsl.macros.Source +import izumi.reflect.Tag +import io.computenode.cyfra.dsl.Value.FromExpr + +class GArray2D[T <: Value: Tag: FromExpr](width: Int, val arr: GArray[T]) { + def at(x: Int32, y: Int32)(using Source): T = + arr.at(y * width + x) +} \ No newline at end of file diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GSeq.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala similarity index 92% rename from cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GSeq.scala rename to cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala index 20987310..cb380b30 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GSeq.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala @@ -1,12 +1,13 @@ -package io.computenode.cyfra.dsl +package io.computenode.cyfra.dsl.collections -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Control.{Scope, when} -import io.computenode.cyfra.dsl.Expression.{ConstInt32, CustomTreeId, E, PhantomExpression, treeidState} -import GSeq.* +import io.computenode.cyfra.dsl.Expression.* import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +import io.computenode.cyfra.dsl.collections.GSeq.* +import io.computenode.cyfra.dsl.control.Scope +import io.computenode.cyfra.dsl.control.When.* import io.computenode.cyfra.dsl.macros.Source -import io.computenode.cyfra.dsl.{Expression, GSeq} +import io.computenode.cyfra.dsl.{Expression, Value} import izumi.reflect.Tag import java.util.Base64 diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Pure.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Pure.scala similarity index 73% rename from cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Pure.scala rename to cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Pure.scala index b8d4d894..6f0bd5ff 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Pure.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Pure.scala @@ -1,9 +1,9 @@ -package io.computenode.cyfra.dsl +package io.computenode.cyfra.dsl.control -import io.computenode.cyfra.dsl.Algebra.FromExpr -import io.computenode.cyfra.dsl.Control.Scope import io.computenode.cyfra.dsl.Expression.FunctionCall +import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.macros.FnCall +import io.computenode.cyfra.dsl.{Expression, Value} import izumi.reflect.Tag object Pure: diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Scope.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Scope.scala new file mode 100644 index 00000000..3ad330ca --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Scope.scala @@ -0,0 +1,7 @@ +package io.computenode.cyfra.dsl.control + +import io.computenode.cyfra.dsl.{Expression, Value} +import izumi.reflect.Tag + +case class Scope[T <: Value: Tag](expr: Expression[T], isDetached: Boolean = false): + def rootTreeId: Int = expr.treeid \ No newline at end of file diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala new file mode 100644 index 00000000..3e92b8ed --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala @@ -0,0 +1,35 @@ +package io.computenode.cyfra.dsl.control + +import When.WhenExpr +import io.computenode.cyfra.dsl.Expression.E +import io.computenode.cyfra.dsl.{Expression, Value} +import io.computenode.cyfra.dsl.Value.{FromExpr, GBoolean} +import io.computenode.cyfra.dsl.macros.Source +import izumi.reflect.Tag + + +case class When[T <: Value: Tag: FromExpr]( + when: GBoolean, + thenCode: T, + otherConds: List[Scope[GBoolean]], + otherCases: List[Scope[T]], + name: Source, +): + def elseWhen(cond: GBoolean)(t: T): When[T] = + When(when, thenCode, otherConds :+ Scope(cond.tree), otherCases :+ Scope(t.tree.asInstanceOf[E[T]]), name) + infix def otherwise(t: T): T = + summon[FromExpr[T]] + .fromExpr(WhenExpr(when, Scope(thenCode.tree.asInstanceOf[E[T]]), otherConds, otherCases, Scope(t.tree.asInstanceOf[E[T]])))(using name) + +object When: + + case class WhenExpr[T <: Value: Tag]( + when: GBoolean, + thenCode: Scope[T], + otherConds: List[Scope[GBoolean]], + otherCaseCodes: List[Scope[T]], + otherwise: Scope[T], + ) extends Expression[T] + + def when[T <: Value: Tag: FromExpr](cond: GBoolean)(fn: T)(using name: Source): When[T] = + When(cond, fn, Nil, Nil, name) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Color.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Color.scala similarity index 90% rename from cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Color.scala rename to cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Color.scala index 48acc84e..0e34626c 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Color.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Color.scala @@ -1,9 +1,10 @@ -package io.computenode.cyfra.dsl +package io.computenode.cyfra.dsl.library -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Functions.{cos, mix, pow} +import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +import io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} +import Functions.{cos, mix, pow} import io.computenode.cyfra.dsl.Value.{Float32, Vec3} -import io.computenode.cyfra.dsl.Math3D.lessThan +import io.computenode.cyfra.dsl.library.Math3D.lessThan import scala.annotation.targetName diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Functions.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala similarity index 96% rename from cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Functions.scala rename to cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala index 3d58bfd5..0f2b3a4f 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Functions.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala @@ -1,8 +1,9 @@ -package io.computenode.cyfra.dsl +package io.computenode.cyfra.dsl.library -import io.computenode.cyfra.dsl.Algebra.{/, FromExpr, vec3} import io.computenode.cyfra.dsl.Expression.* import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} +import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Math3D.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Math3D.scala similarity index 84% rename from cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Math3D.scala rename to cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Math3D.scala index 96be5bb8..b8249e51 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Math3D.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Math3D.scala @@ -1,9 +1,10 @@ -package io.computenode.cyfra.dsl +package io.computenode.cyfra.dsl.library -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Control.* -import io.computenode.cyfra.dsl.Functions.* +import io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} +import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +import Functions.* import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.control.When.when import scala.concurrent.duration.DurationInt diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Random.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Random.scala similarity index 73% rename from cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Random.scala rename to cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Random.scala index 2d4c5127..c7e9ce4b 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Random.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Random.scala @@ -1,7 +1,12 @@ -package io.computenode.cyfra.dsl +package io.computenode.cyfra.dsl.library -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Pure.pure +import io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} +import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +import Functions.{cos, sin, sqrt} +import io.computenode.cyfra.dsl.control.Pure.pure +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.{Float32, UInt32, Vec3} +import io.computenode.cyfra.dsl.struct.GStruct case class Random(seed: UInt32) extends GStruct[Random]: diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala new file mode 100644 index 00000000..65e48285 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala @@ -0,0 +1,37 @@ +package io.computenode.cyfra.dsl.struct + +import io.computenode.cyfra.* +import io.computenode.cyfra.dsl.Expression.* +import io.computenode.cyfra.dsl.{Expression, Value} +import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.macros.Source +import izumi.reflect.Tag + +import scala.compiletime.* +import scala.deriving.Mirror + +abstract class GStruct[T <: GStruct[T]: Tag: GStructSchema] extends Value with Product: + self: T => + private[cyfra] var _schema: GStructSchema[T] = summon[GStructSchema[T]] // a nasty hack + def schema: GStructSchema[T] = _schema + lazy val tree: E[T] = + schema.tree(self) + override protected def init(): Unit = () + private[dsl] var _name = Source("Unknown") + override def source: Source = _name + +object GStruct: + case class Empty() extends GStruct[Empty] + + object Empty: + given GStructSchema[Empty] = GStructSchema.derived + + case class ComposeStruct[T <: GStruct[T] : Tag](fields: List[Value], resultSchema: GStructSchema[T]) extends Expression[T] + + case class GetField[S <: GStruct[S] : GStructSchema, T <: Value : Tag](struct: E[S], fieldIndex: Int) extends Expression[T]: + val resultSchema: GStructSchema[S] = summon[GStructSchema[S]] + + given [T <: GStruct[T] : GStructSchema]: GStructConstructor[T] with + def schema: GStructSchema[T] = summon[GStructSchema[T]] + + def fromExpr(expr: E[T])(using Source): T = schema.fromTree(expr) \ No newline at end of file diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructConstructor.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructConstructor.scala new file mode 100644 index 00000000..f41b192f --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructConstructor.scala @@ -0,0 +1,9 @@ +package io.computenode.cyfra.dsl.struct + +import io.computenode.cyfra.dsl.Expression.E +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.macros.Source + +trait GStructConstructor[T <: GStruct[T]] extends FromExpr[T]: + def schema: GStructSchema[T] + def fromExpr(expr: E[T])(using Source): T \ No newline at end of file diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GStruct.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala similarity index 58% rename from cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GStruct.scala rename to cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala index 101c5582..750e6563 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/GStruct.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala @@ -1,26 +1,15 @@ -package io.computenode.cyfra.dsl +package io.computenode.cyfra.dsl.struct -import io.computenode.cyfra.dsl.Algebra.{FromExpr, given_Conversion_Int_Int32} -import io.computenode.cyfra.dsl.Expression.* -import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.* +import io.computenode.cyfra.dsl.Expression.E +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.macros.Source +import io.computenode.cyfra.dsl.struct.GStruct.* import izumi.reflect.Tag -import scala.compiletime.* +import scala.compiletime.{constValue, erasedValue, error, summonAll} import scala.deriving.Mirror -type SomeGStruct[T <: GStruct[T]] = GStruct[T] -abstract class GStruct[T <: GStruct[T]: Tag: GStructSchema] extends Value with Product: - self: T => - private[cyfra] var _schema: GStructSchema[T] = summon[GStructSchema[T]] // a nasty hack - def schema: GStructSchema[T] = _schema - lazy val tree: E[T] = - schema.tree(self) - override protected def init(): Unit = () - private[dsl] var _name = Source("Unknown") - override def source: Source = _name - case class GStructSchema[T <: GStruct[T]: Tag](fields: List[(String, FromExpr[?], Tag[?])], dependsOn: Option[E[T]], fromTuple: (Tuple, Source) => T): given GStructSchema[T] = this val structTag = summon[Tag[T]] @@ -50,25 +39,6 @@ case class GStructSchema[T <: GStruct[T]: Tag](fields: List[(String, FromExpr[?] val gStructTag = summon[Tag[GStruct[?]]] -trait GStructConstructor[T <: GStruct[T]] extends FromExpr[T]: - def schema: GStructSchema[T] - def fromExpr(expr: E[T])(using Source): T - -given [T <: GStruct[T]: GStructSchema]: GStructConstructor[T] with - def schema: GStructSchema[T] = summon[GStructSchema[T]] - def fromExpr(expr: E[T])(using Source): T = schema.fromTree(expr) - -case class ComposeStruct[T <: GStruct[T]: Tag](fields: List[Value], resultSchema: GStructSchema[T]) extends Expression[T] - -case class GetField[S <: GStruct[S]: GStructSchema, T <: Value: Tag](struct: E[S], fieldIndex: Int) extends Expression[T]: - val resultSchema: GStructSchema[S] = summon[GStructSchema[S]] - -private inline def constValueTuple[T <: Tuple]: T = - (inline erasedValue[T] match - case _: EmptyTuple => EmptyTuple - case _: (t *: ts) => constValue[t] *: constValueTuple[ts] - ).asInstanceOf[T] - object GStructSchema: type TagOf[T] = Tag[T] type FromExprOf[T] = T match @@ -96,8 +66,8 @@ object GStructSchema: ) case _ => error("Only case classes are supported as GStructs") -object GStruct: - case class Empty() extends GStruct[Empty] - - object Empty: - given GStructSchema[Empty] = GStructSchema.derived + private inline def constValueTuple[T <: Tuple]: T = + (inline erasedValue[T] match + case _: EmptyTuple => EmptyTuple + case _: (t *: ts) => constValue[t] *: constValueTuple[ts] + ).asInstanceOf[T] \ No newline at end of file diff --git a/cyfra-e2e-test/src/test/resources/io/computenode/cyfra/juliaset/julia.png b/cyfra-e2e-test/src/test/resources/io/computenode/cyfra/e2e/juliaset/julia.png similarity index 100% rename from cyfra-e2e-test/src/test/resources/io/computenode/cyfra/juliaset/julia.png rename to cyfra-e2e-test/src/test/resources/io/computenode/cyfra/e2e/juliaset/julia.png diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticTests.scala index 677c1b90..3ffd6b71 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticTests.scala @@ -1,9 +1,11 @@ package io.computenode.cyfra.e2e -import io.computenode.cyfra.runtime.*, mem.* +import io.computenode.cyfra.runtime.* +import mem.* import GMem.fRGBA +import io.computenode.cyfra.dsl.algebra.VectorAlgebra +import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} -import GStruct.Empty.given class ArithmeticsE2eTest extends munit.FunSuite: given gc: GContext = GContext() @@ -47,9 +49,9 @@ class ArithmeticsE2eTest extends munit.FunSuite: val f3 = (-5.3f, 6.2f, -4.7f, 9.1f) val sc = -2.1f - val v1 = Algebra.vec4.tupled(f1) - val v2 = Algebra.vec4.tupled(f2) - val v3 = Algebra.vec4.tupled(f3) + val v1 = VectorAlgebra.vec4.tupled(f1) + val v2 = VectorAlgebra.vec4.tupled(f2) + val v3 = VectorAlgebra.vec4.tupled(f3) val gf: GFunction[GStruct.Empty, Vec4[Float32], Float32] = GFunction: v4 => (-v4).*(sc).+(v1).-(v2).dot(v3) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsTests.scala index be32d0fe..6a332ac8 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsTests.scala @@ -1,8 +1,8 @@ package io.computenode.cyfra.e2e import io.computenode.cyfra.runtime.*, mem.* +import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} -import GStruct.Empty.given import GMem.fRGBA class FunctionsE2eTest extends munit.FunSuite: @@ -26,7 +26,7 @@ class FunctionsE2eTest extends munit.FunSuite: result .zip(expected) .foreach: (res, exp) => - assert(Math.abs(res - exp) < 0.01f, s"Expected $exp but got $res") + assert(Math.abs(res - exp) < 0.05f, s"Expected $exp but got $res") test("smoothstep clamp mix reflect refract normalize"): val gf: GFunction[GStruct.Empty, Float32, Float32] = GFunction: f => diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GSeqTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GSeqTests.scala index 4d6730fb..8319614a 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GSeqTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GSeqTests.scala @@ -1,8 +1,10 @@ package io.computenode.cyfra.e2e -import io.computenode.cyfra.runtime.*, mem.* +import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.runtime.* +import mem.* import io.computenode.cyfra.dsl.{*, given} -import GStruct.Empty.given class GseqE2eTest extends munit.FunSuite: given gc: GContext = GContext() diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructTests.scala index 742947bf..61b4db15 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructTests.scala @@ -1,8 +1,10 @@ package io.computenode.cyfra.e2e -import io.computenode.cyfra.runtime.*, mem.* +import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.runtime.* +import mem.* import io.computenode.cyfra.dsl.{*, given} -import GStruct.Empty.given class GStructE2eTest extends munit.FunSuite: case class Custom(f: Float32, v: Vec4[Float32]) extends GStruct[Custom] diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenTests.scala index b59d939a..3a53669f 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenTests.scala @@ -1,8 +1,9 @@ package io.computenode.cyfra.e2e -import io.computenode.cyfra.runtime.*, mem.* +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.runtime.* +import mem.* import io.computenode.cyfra.dsl.{*, given} -import GStruct.Empty.given class WhenE2eTest extends munit.FunSuite: given gc: GContext = GContext() diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala index 30556b58..0726b3cb 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala @@ -2,8 +2,9 @@ package io.computenode.cyfra.e2e.juliaset import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.* -import io.computenode.cyfra.dsl.GStruct.Empty -import io.computenode.cyfra.dsl.Pure.pure +import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.control.Pure.pure +import io.computenode.cyfra.dsl.struct.GStruct.Empty import io.computenode.cyfra.runtime.{GContext, GFunction} import org.apache.commons.io.IOUtils import org.junit.runner.RunWith diff --git a/cyfra-examples/src/main/resources/modelling.scala b/cyfra-examples/src/main/resources/modelling.scala new file mode 100644 index 00000000..c1f6804d --- /dev/null +++ b/cyfra-examples/src/main/resources/modelling.scala @@ -0,0 +1,86 @@ +import io.computenode.cyfra.dsl.Value +import izumi.reflect.Tag + + + + + + +type Layout1 = ( + structValidityBitmap: GpBuf[Bit], + varBinaryValidityBitmap: GpBuf[Int32], + varBinaryOffsetsBuffer: GpBuf[Byte], + int32ValidityBitmap: GpBuf[Bit], + int32ValueBuffer: GpBuf[Int32], + ) + +val changeLongerStringToNull: Layout1 => GIO[Unit] = { + case (structValidityBitmap, varBinaryValidityBitmap, varBinaryOffsetsBuffer, int32ValidityBitmap, int32ValueBuffer) => + for { + index <- GIO.gl_GlobalInvocationID.x + isNotNull <- structValidityBitmap.getSafeOrDiscard(index) + _ <- GIO.If(isNotNull) { + for { + length <- GIO.If(varBinaryValidityBitmap.get(index))(for { + offset1 <- varBinaryOffsetsBuffer.get(index) + offset2 <- varBinaryOffsetsBuffer.get(index + 1) + } yield offset2 - offset1)(0) + targetLength <- GIO.If(int32ValidityBitmap.get(index))(int32ValueBuffer.get(index))(Int32.Inf) + _ <- GIO.If(length > targetLength) { + varBinaryValidityBitmap.set(index, 0) + } + } yield () + } + } yield () +} + +type Layout2 = (varBinaryValidityBitmap: GpBuf[Bit], varBinaryOffsetsBuffer: GpBuf[Int32], lengthsBuffer: GpBuf[Int32]) + +val prepareForScan: Layout2 => GIO[Unit] = { case (varBinaryValidityBitmap, varBinaryOffsetsBuffer, lengthsBuffer) => + for { + index <- GIO.gl_GlobalInvocationID.x + _ <- GIO.assertSize(lengthsBuffer, varBinaryOffsetsBuffer.length.map(identity)) + varBinaryIsPresent <- varBinaryValidityBitmap.getSafeOrDiscard(index) + length <- GIO.If(varBinaryIsPresent) { + for { + offset1 <- varBinaryOffsetsBuffer.get(index) + offset2 <- varBinaryOffsetsBuffer.get(index + 1) + } yield offset2 - offset1 + }(0) + _ <- lengthsBuffer.set(index, length) + } yield () +} + + +val afterScan: Layout3 => GIO[Unit] = { case (varBinaryValidityBitmap, varBinaryOffsetsBuffer, varBinaryValueBuffer, lengthsBuffer, nextBuffer) => + for { + index <- GIO.gl_GlobalInvocationID.x + _ <- GIO.assertSize(nextBuffer, varBinaryValueBuffer.length.map(identity)) + _ <- GIO.If(varBinaryValidityBitmap.getSafeOrDiscard(index)) { + for { + startRead <- varBinaryOffsetsBuffer.get(index) + startWrite <- scanResult.get(index) + endRead <- varBinaryOffsetsBuffer.get(index + 1) + length = endRead - startRead + _ <- GIO.Range(0, length)(i => + for { + byte <- varBinaryValueBuffer.get(startRead + i) + _ <- nextBuffer.set(startWrite + i, byte) + } yield (), + ) + } yield () + } + } yield () +} + +val changeLongerStringToNullProgram = GProgram.compile(groupSize = (1024, 1, 1), code = changeLongerStringToNull) +val prepareForScanProgram = GProgram.compile(groupSize = (1024, 1, 1), code = prepareForScan) +val afterScanProgram = GProgram.compile(groupSize = (1024, 1, 1), code = afterScan) + +val pipeline = + GPipeline[Metadata[(Layout1, Layout2, Layout3)]] + .invocations((metadata, shaderInfo) => (metadata.buffers("structValidityBitmap").length / shaderInfo.groupSize.x, 1, 1)) + .execute(changeLongerStringToNullProgram) + .execute(prepareForScanProgram) + .scan(metadata => metadata.buffers("lengthsBuffer")) + .execute(afterScanProgram) \ No newline at end of file diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala index 41e38938..7cc5dc1b 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala @@ -2,13 +2,14 @@ package io.computenode.samples.cyfra.foton import io.computenode.cyfra import io.computenode.cyfra.* +import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.foton.animation.AnimatedFunctionRenderer.Parameters import io.computenode.cyfra.foton.animation.{AnimatedFunction, AnimatedFunctionRenderer} import io.computenode.cyfra.given import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.dsl.* -import io.computenode.cyfra.dsl.Color.{InterpolationThemes, interpolate} -import io.computenode.cyfra.dsl.Math3D.* +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.dsl.library.Color.{InterpolationThemes, interpolate} +import io.computenode.cyfra.dsl.library.Math3D.* import io.computenode.cyfra.dsl.given import io.computenode.cyfra.foton.animation.AnimationFunctions.* diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala index a7007440..fa6393a1 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala @@ -9,7 +9,7 @@ import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra.given import io.computenode.cyfra.runtime.* import io.computenode.cyfra.dsl.* -import io.computenode.cyfra.dsl.Color.hex +import io.computenode.cyfra.dsl.library.Color.hex import io.computenode.cyfra.dsl.given import java.nio.file.Paths @@ -62,8 +62,8 @@ object AnimatedRaytrace: val parameters = AnimationRtRenderer.Parameters( - width = 1920, - height = 1080, + width = 512, + height = 512, superFar = 300f, pixelIterations = 10000, iterations = 2, diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala index ff60b4b2..e498ce3e 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala @@ -12,7 +12,9 @@ import scala.concurrent.{Await, ExecutionContext} import io.computenode.cyfra.given import io.computenode.cyfra.runtime.* import io.computenode.cyfra.dsl.* +import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.given +import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.runtime.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility import io.computenode.cyfra.runtime.mem.Vec4FloatMem diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala index 882c24be..c08855e9 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala @@ -12,8 +12,9 @@ import scala.concurrent.{Await, ExecutionContext} import io.computenode.cyfra.given import io.computenode.cyfra.runtime.* import io.computenode.cyfra.dsl.* -import io.computenode.cyfra.dsl.GStruct.Empty +import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.given +import io.computenode.cyfra.dsl.struct.GStruct.Empty import io.computenode.cyfra.runtime.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility import io.computenode.cyfra.runtime.mem.Vec4FloatMem diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala index 523e57b9..70fdd546 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala @@ -3,7 +3,9 @@ package io.computenode.samples.cyfra.slides import io.computenode.cyfra.* import io.computenode.cyfra.dsl.given import io.computenode.cyfra.dsl.* -import io.computenode.cyfra.dsl.GStruct.Empty +import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.GStruct.Empty import java.awt.image.BufferedImage import java.io.File diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala index e6269dee..226ffab1 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala @@ -2,9 +2,11 @@ package io.computenode.samples.cyfra.slides import java.nio.file.Paths import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.dsl.GStruct.Empty import io.computenode.cyfra.dsl.given import io.computenode.cyfra.dsl.* +import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.GStruct.Empty import io.computenode.cyfra.runtime.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility diff --git a/cyfra-foton/src/main/scala/foton/Api.scala b/cyfra-foton/src/main/scala/foton/Api.scala index 3adb6dcb..36d5bf50 100644 --- a/cyfra-foton/src/main/scala/foton/Api.scala +++ b/cyfra-foton/src/main/scala/foton/Api.scala @@ -1,8 +1,8 @@ package foton import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.library.{Color, Math3D} import io.computenode.cyfra.utility.ImageUtility -import io.computenode.cyfra.dsl.{Algebra, Color} import io.computenode.cyfra.foton.animation.AnimationRenderer import io.computenode.cyfra.foton.animation.AnimationRenderer.{Parameters, Scene} import io.computenode.cyfra.utility.Units.Milliseconds @@ -11,10 +11,10 @@ import java.nio.file.{Path, Paths} import scala.concurrent.duration.DurationInt import scala.concurrent.Await -export Algebra.given +export io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +export io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} export Color.* -export io.computenode.cyfra.dsl.{GSeq, GStruct} -export io.computenode.cyfra.dsl.Math3D.{rotate, lessThan} +export Math3D.{rotate, lessThan} /** Define function to be drawn */ diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunction.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunction.scala index 1d6fcb1f..2212e11b 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunction.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunction.scala @@ -2,8 +2,8 @@ package io.computenode.cyfra.foton.animation import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra -import io.computenode.cyfra.dsl.GArray2D import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.collections.GArray2D import io.computenode.cyfra.foton.animation.AnimatedFunction.FunctionArguments import io.computenode.cyfra.foton.animation.AnimationFunctions.AnimationInstant import io.computenode.cyfra.foton.animation.AnimationRenderer diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala index d4e9597e..61b05aee 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala @@ -2,7 +2,8 @@ package io.computenode.cyfra.foton.animation import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra -import io.computenode.cyfra.dsl.{GStruct, UniformContext, given} +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.foton.animation.AnimatedFunctionRenderer.{AnimationIteration, RenderFn} import io.computenode.cyfra.foton.animation.AnimationFunctions.AnimationInstant @@ -10,10 +11,9 @@ import io.computenode.cyfra.foton.animation.AnimationRenderer import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration import io.computenode.cyfra.foton.rt.RtRenderer -import io.computenode.cyfra.runtime.{GFunction, GContext} +import io.computenode.cyfra.runtime.{GContext, GFunction, UniformContext} import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra.utility.Utility.timed -import io.computenode.cyfra.dsl.Algebra.{*, given} import io.computenode.cyfra.runtime.mem.GMem.fRGBA import io.computenode.cyfra.runtime.mem.Vec4FloatMem diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationFunctions.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationFunctions.scala index 6ac1c996..28c92809 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationFunctions.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationFunctions.scala @@ -2,10 +2,9 @@ package io.computenode.cyfra.foton.animation import io.computenode.cyfra.given import io.computenode.cyfra -import io.computenode.cyfra.dsl.Algebra.{*, given} +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration import io.computenode.cyfra.* -import io.computenode.cyfra.dsl.Control.when import io.computenode.cyfra.dsl.Value.Float32 import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration import io.computenode.cyfra.utility.Units.Milliseconds diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala index f46068dc..72d0f032 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala @@ -11,7 +11,7 @@ import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra.utility.Utility.timed import io.computenode.cyfra.{*, given} import io.computenode.cyfra.utility.ImageUtility -import io.computenode.cyfra.dsl.Algebra.{*, given} +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.runtime.mem.GMem.fRGBA import java.nio.file.{Path, Paths} diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala index 2b25d194..e65f94f1 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala @@ -8,12 +8,12 @@ import io.computenode.cyfra.foton.rt.ImageRtRenderer import io.computenode.cyfra.* import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.foton.rt.shapes.{Box, Sphere} -import io.computenode.cyfra.dsl.{GStruct, UniformContext, given} -import io.computenode.cyfra.runtime.GFunction +import io.computenode.cyfra.runtime.{GFunction, UniformContext} import io.computenode.cyfra.runtime.mem.GMem.fRGBA import io.computenode.cyfra.utility.ImageUtility import io.computenode.cyfra.runtime.mem.Vec4FloatMem -import io.computenode.cyfra.dsl.Algebra.{*, given} +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.{*, given} import java.nio.file.{Path, Paths} import scala.collection.mutable diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/Material.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/Material.scala index 57a7fbc7..3b9bc3f6 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/Material.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/Material.scala @@ -1,8 +1,7 @@ package io.computenode.cyfra.foton.rt -import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.{GStruct, given} -import io.computenode.cyfra.dsl.Algebra.{*, given} +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.{*, given} case class Material( color: Vec3[Float32], diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala index 98861721..b35b37b2 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala @@ -4,15 +4,12 @@ import io.computenode.cyfra import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo import io.computenode.cyfra.utility.Utility.timed import io.computenode.cyfra.foton.rt.RtRenderer -import io.computenode.cyfra.dsl.{GArray2D, GSeq, GStruct, Random, given} +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.rt.shapes.{Box, Sphere} -import io.computenode.cyfra.dsl.Color.* -import io.computenode.cyfra.dsl.Control.when -import io.computenode.cyfra.dsl.Math3D.* +import io.computenode.cyfra.dsl.library.Color.* +import io.computenode.cyfra.dsl.library.Math3D.* import io.computenode.cyfra.runtime.GContext -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Functions.* -import io.computenode.cyfra.dsl.Pure.pure +import io.computenode.cyfra.dsl.control.Pure.pure import java.nio.file.{Path, Paths} import scala.collection.mutable @@ -20,6 +17,9 @@ import scala.concurrent.ExecutionContext.Implicits import scala.concurrent.duration.DurationInt import scala.concurrent.{Await, ExecutionContext} import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.collections.{GArray2D, GSeq} +import io.computenode.cyfra.dsl.library.Random +import io.computenode.cyfra.dsl.struct.GStruct class RtRenderer(params: RtRenderer.Parameters): diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala index a9cc908e..5367f800 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala @@ -1,19 +1,18 @@ package io.computenode.cyfra.foton.rt.animation import io.computenode.cyfra -import io.computenode.cyfra.dsl.{GStruct, UniformContext} import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.foton.animation.AnimationRenderer import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration import io.computenode.cyfra.foton.rt.RtRenderer -import io.computenode.cyfra.runtime.GFunction +import io.computenode.cyfra.runtime.{GFunction, UniformContext} import io.computenode.cyfra.runtime.mem.GMem.fRGBA import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra.utility.Utility.timed import io.computenode.cyfra.runtime.mem.Vec4FloatMem -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.GStruct.{*, given} +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.given import java.nio.file.{Path, Paths} diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Box.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Box.scala index 535aa9f1..58ca8bf5 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Box.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Box.scala @@ -1,14 +1,11 @@ package io.computenode.cyfra.foton.rt.shapes -import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.{GStruct, given} +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.rt.Material import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo -import io.computenode.cyfra.dsl.Functions.* -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Control.when import io.computenode.cyfra.foton.rt.shapes.Shape.TestRay -import io.computenode.cyfra.dsl.Pure.pure +import io.computenode.cyfra.dsl.control.Pure.pure +import io.computenode.cyfra.dsl.struct.GStruct case class Box(minV: Vec3[Float32], maxV: Vec3[Float32], material: Material) extends GStruct[Box] with Shape diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Plane.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Plane.scala index bd097169..b0188750 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Plane.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Plane.scala @@ -1,14 +1,13 @@ package io.computenode.cyfra.foton.rt.shapes -import io.computenode.cyfra.dsl.{GStruct, given} import io.computenode.cyfra.foton.rt.Material import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo -import io.computenode.cyfra.dsl.Functions.* -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Control.when +import io.computenode.cyfra.dsl.library.Functions.* +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.foton.rt.shapes.Shape.TestRay -import io.computenode.cyfra.dsl.Pure.pure +import io.computenode.cyfra.dsl.control.Pure.pure +import io.computenode.cyfra.dsl.struct.GStruct case class Plane(point: Vec3[Float32], normal: Vec3[Float32], material: Material) extends GStruct[Plane] with Shape diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Quad.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Quad.scala index 241c693e..fbdcc1b7 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Quad.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Quad.scala @@ -1,13 +1,9 @@ package io.computenode.cyfra.foton.rt.shapes import io.computenode.cyfra.foton.rt.Material -import io.computenode.cyfra.dsl.Functions.* -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Control.when -import io.computenode.cyfra.dsl.GStruct -import io.computenode.cyfra.dsl.Math3D.scalarTriple +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.dsl.library.Math3D.scalarTriple import io.computenode.cyfra.foton.rt.RtRenderer.{MinRayHitTime, RayHitInfo} -import io.computenode.cyfra.dsl.Value.* import java.nio.file.Paths import scala.collection.mutable @@ -16,7 +12,8 @@ import scala.concurrent.duration.DurationInt import scala.concurrent.{Await, ExecutionContext} import io.computenode.cyfra.dsl.given import io.computenode.cyfra.foton.rt.shapes.Shape.TestRay -import io.computenode.cyfra.dsl.Pure.pure +import io.computenode.cyfra.dsl.control.Pure.pure +import io.computenode.cyfra.dsl.struct.GStruct case class Quad(a: Vec3[Float32], b: Vec3[Float32], c: Vec3[Float32], d: Vec3[Float32], material: Material) extends GStruct[Quad] with Shape diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Shape.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Shape.scala index a22de43a..9fb3f891 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Shape.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Shape.scala @@ -1,9 +1,9 @@ package io.computenode.cyfra.foton.rt.shapes import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo -import io.computenode.cyfra.dsl.Functions.* -import io.computenode.cyfra.dsl.Algebra.{*, given} +import io.computenode.cyfra.dsl.library.Functions.* import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.{*, given} trait Shape diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala index 22ff6e0d..e80ca655 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala @@ -2,12 +2,13 @@ package io.computenode.cyfra.foton.rt.shapes import io.computenode.cyfra.foton.rt.shapes.* import io.computenode.cyfra.foton.rt.Material -import io.computenode.cyfra.dsl.{GSeq, GStruct, given} import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo import izumi.reflect.Tag -import io.computenode.cyfra.dsl.Functions.* -import io.computenode.cyfra.dsl.Algebra.{*, given} +import io.computenode.cyfra.dsl.library.Functions.* +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.foton.rt.shapes.Shape.TestRay import scala.util.chaining.* diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Sphere.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Sphere.scala index 5e8e82ee..0328780b 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Sphere.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Sphere.scala @@ -9,12 +9,9 @@ import scala.concurrent.ExecutionContext.Implicits import scala.concurrent.duration.DurationInt import scala.concurrent.{Await, ExecutionContext} import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.Algebra.{*, given} -import io.computenode.cyfra.dsl.Control.when -import io.computenode.cyfra.dsl.Functions.* -import io.computenode.cyfra.dsl.GStruct -import io.computenode.cyfra.dsl.Pure.pure -import io.computenode.cyfra.dsl.given +import io.computenode.cyfra.dsl.control.Pure.pure +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.foton.rt.shapes.Shape.TestRay case class Sphere(center: Vec3[Float32], radius: Float32, material: Material) extends GStruct[Sphere] with Shape diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala index 0270d16a..422370ee 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala @@ -1,18 +1,19 @@ package io.computenode.cyfra.runtime -import io.computenode.cyfra.dsl.Algebra.FromExpr -import io.computenode.cyfra.dsl.{GArray, GStruct, GStructSchema, UniformContext, Value} -import GStruct.Empty -import Value.{Float32, Vec4, Int32} +import io.computenode.cyfra.dsl.{*, given} +import Value.{Float32, Int32, Vec4} import io.computenode.cyfra.vulkan.VulkanContext import io.computenode.cyfra.vulkan.compute.{Binding, ComputePipeline, InputBufferSize, LayoutInfo, LayoutSet, Shader, UniformSize} import io.computenode.cyfra.vulkan.executor.{BufferAction, SequenceExecutor} import SequenceExecutor.* +import io.computenode.cyfra.dsl.collections.GArray +import io.computenode.cyfra.dsl.struct.* +import io.computenode.cyfra.dsl.struct.GStruct.* import io.computenode.cyfra.runtime.mem.GMem.totalStride import io.computenode.cyfra.spirv.SpirvTypes.typeStride import io.computenode.cyfra.spirv.compilers.DSLCompiler import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.{UniformStructRef, WorkerIndex} -import mem.{FloatMem, GMem, Vec4FloatMem, IntMem} +import mem.{FloatMem, GMem, IntMem, Vec4FloatMem} import org.lwjgl.system.{Configuration, MemoryUtil} import izumi.reflect.Tag diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala index 17ba5f79..02a9e094 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala @@ -1,7 +1,9 @@ package io.computenode.cyfra.runtime import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.dsl.Value.Int32 +import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.struct.* +import io.computenode.cyfra.dsl.collections.{GArray, GArray2D} import io.computenode.cyfra.vulkan.compute.ComputePipeline import izumi.reflect.Tag diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/UniformContext.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/UniformContext.scala similarity index 71% rename from cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/UniformContext.scala rename to cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/UniformContext.scala index e3bcb4ae..04df0996 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/UniformContext.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/UniformContext.scala @@ -1,9 +1,11 @@ -package io.computenode.cyfra.dsl +package io.computenode.cyfra.runtime -import io.computenode.cyfra.dsl.GStruct.Empty +import io.computenode.cyfra.dsl.struct.* +import io.computenode.cyfra.dsl.struct.GStruct.Empty import izumi.reflect.Tag class UniformContext[G <: GStruct[G]: Tag: GStructSchema](val uniform: G) + object UniformContext: def withUniform[G <: GStruct[G]: Tag: GStructSchema, T](uniform: G)(fn: UniformContext[G] ?=> T): T = fn(using UniformContext(uniform)) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala index 10cc0398..42246671 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala @@ -1,15 +1,14 @@ package io.computenode.cyfra.runtime.mem -import io.computenode.cyfra.dsl.{UniformContext, GStruct, GStructConstructor, GStructSchema, Value} -import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.Expression.* -import GStruct.Empty -import io.computenode.cyfra.dsl.Algebra.FromExpr +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.spirv.SpirvTypes.typeStride import io.computenode.cyfra.runtime.{GContext, GFunction} +import io.computenode.cyfra.dsl.struct.* import izumi.reflect.Tag import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil +import io.computenode.cyfra.runtime.UniformContext import java.nio.ByteBuffer From 7ddd1120e20cdcbf387ef44bfc540b70b2af45dc Mon Sep 17 00:00:00 2001 From: Szymon Date: Mon, 16 Jun 2025 20:12:41 +0200 Subject: [PATCH 05/59] Formatting of refactor --- .../io/computenode/cyfra/dsl/Value.scala | 2 +- .../cyfra/dsl/algebra/ScalarAlgebra.scala | 44 +++++----- .../cyfra/dsl/algebra/VectorAlgebra.scala | 88 ++++++++----------- .../cyfra/dsl/collections/GArray2D.scala | 2 +- .../computenode/cyfra/dsl/control/Scope.scala | 2 +- .../computenode/cyfra/dsl/control/When.scala | 11 +-- .../cyfra/dsl/struct/GStruct.scala | 8 +- .../cyfra/dsl/struct/GStructConstructor.scala | 2 +- .../cyfra/dsl/struct/GStructSchema.scala | 4 +- 9 files changed, 73 insertions(+), 90 deletions(-) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala index efc0cfe0..03754998 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala @@ -14,7 +14,7 @@ trait Value: init() object Value: - + trait FromExpr[T <: Value]: def fromExpr(expr: E[T])(using name: Source): T diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala index f7acecd8..4684c61d 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala @@ -11,8 +11,8 @@ import scala.annotation.targetName object ScalarAlgebra: - trait BasicScalarAlgebra[T <: Scalar : FromExpr : Tag] - extends ScalarSummable[T] + trait BasicScalarAlgebra[T <: Scalar: FromExpr: Tag] + extends ScalarSummable[T] with ScalarDiffable[T] with ScalarMulable[T] with ScalarDivable[T] @@ -20,54 +20,54 @@ object ScalarAlgebra: with Comparable[T] with ScalarNegatable[T] - trait BasicScalarIntAlgebra[T <: Scalar : FromExpr : Tag] extends BasicScalarAlgebra[T] with BitwiseOperable[T] - + trait BasicScalarIntAlgebra[T <: Scalar: FromExpr: Tag] extends BasicScalarAlgebra[T] with BitwiseOperable[T] + given BasicScalarAlgebra[Float32] = new BasicScalarAlgebra[Float32] {} given BasicScalarIntAlgebra[Int32] = new BasicScalarIntAlgebra[Int32] {} given BasicScalarIntAlgebra[UInt32] = new BasicScalarIntAlgebra[UInt32] {} - - trait ScalarSummable[T <: Scalar : FromExpr : Tag]: + + trait ScalarSummable[T <: Scalar: FromExpr: Tag]: def sum(a: T, b: T)(using name: Source): T = summon[FromExpr[T]].fromExpr(Sum(a, b)) - extension [T <: Scalar : ScalarSummable : Tag](a: T) + extension [T <: Scalar: ScalarSummable: Tag](a: T) @targetName("add") inline def +(b: T)(using Source): T = summon[ScalarSummable[T]].sum(a, b) - trait ScalarDiffable[T <: Scalar : FromExpr : Tag]: + trait ScalarDiffable[T <: Scalar: FromExpr: Tag]: def diff(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Diff(a, b)) - extension [T <: Scalar : ScalarDiffable : Tag](a: T) + extension [T <: Scalar: ScalarDiffable: Tag](a: T) @targetName("sub") inline def -(b: T)(using Source): T = summon[ScalarDiffable[T]].diff(a, b) // T and S ??? so two - trait ScalarMulable[T <: Scalar : FromExpr : Tag]: + trait ScalarMulable[T <: Scalar: FromExpr: Tag]: def mul(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Mul(a, b)) - extension [T <: Scalar : ScalarMulable : Tag](a: T) + extension [T <: Scalar: ScalarMulable: Tag](a: T) @targetName("mul") inline def *(b: T)(using Source): T = summon[ScalarMulable[T]].mul(a, b) - trait ScalarDivable[T <: Scalar : FromExpr : Tag]: + trait ScalarDivable[T <: Scalar: FromExpr: Tag]: def div(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Div(a, b)) - extension [T <: Scalar : ScalarDivable : Tag](a: T) + extension [T <: Scalar: ScalarDivable: Tag](a: T) @targetName("div") inline def /(b: T)(using Source): T = summon[ScalarDivable[T]].div(a, b) - trait ScalarNegatable[T <: Scalar : FromExpr : Tag]: + trait ScalarNegatable[T <: Scalar: FromExpr: Tag]: def negate(a: T)(using Source): T = summon[FromExpr[T]].fromExpr(Negate(a)) - extension [T <: Scalar : ScalarNegatable : Tag](a: T) + extension [T <: Scalar: ScalarNegatable: Tag](a: T) @targetName("negate") inline def unary_-(using Source): T = summon[ScalarNegatable[T]].negate(a) - trait ScalarModable[T <: Scalar : FromExpr : Tag]: + trait ScalarModable[T <: Scalar: FromExpr: Tag]: def mod(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Mod(a, b)) - extension [T <: Scalar : ScalarModable : Tag](a: T) inline infix def mod(b: T)(using Source): T = summon[ScalarModable[T]].mod(a, b) + extension [T <: Scalar: ScalarModable: Tag](a: T) inline infix def mod(b: T)(using Source): T = summon[ScalarModable[T]].mod(a, b) - trait Comparable[T <: Scalar : FromExpr : Tag]: + trait Comparable[T <: Scalar: FromExpr: Tag]: def greaterThan(a: T, b: T)(using Source): GBoolean = GBoolean(GreaterThan(a, b)) def lessThan(a: T, b: T)(using Source): GBoolean = GBoolean(LessThan(a, b)) @@ -78,7 +78,7 @@ object ScalarAlgebra: def equal(a: T, b: T)(using Source): GBoolean = GBoolean(Equal(a, b)) - extension [T <: Scalar : Comparable : Tag](a: T) + extension [T <: Scalar: Comparable: Tag](a: T) inline def >(b: T)(using Source): GBoolean = summon[Comparable[T]].greaterThan(a, b) inline def <(b: T)(using Source): GBoolean = summon[Comparable[T]].lessThan(a, b) inline def >=(b: T)(using Source): GBoolean = summon[Comparable[T]].greaterThanEqual(a, b) @@ -102,7 +102,7 @@ object ScalarAlgebra: inline def asFloat(using Source): Float32 = Float32(ToFloat32(u32)) inline def signed(using Source): Int32 = Int32(ToInt32(u32)) - trait BitwiseOperable[T <: Scalar : FromExpr : Tag]: + trait BitwiseOperable[T <: Scalar: FromExpr: Tag]: def bitwiseAnd(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseAnd(a, b)) def bitwiseOr(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseOr(a, b)) @@ -115,7 +115,7 @@ object ScalarAlgebra: def shiftRight(a: T, by: UInt32)(using Source): T = summon[FromExpr[T]].fromExpr(ShiftRight(a, by)) - extension [T <: Scalar : BitwiseOperable : Tag](a: T) + extension [T <: Scalar: BitwiseOperable: Tag](a: T) inline def &(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseAnd(a, b) inline def |(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseOr(a, b) inline def ^(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseXor(a, b) @@ -131,7 +131,7 @@ object ScalarAlgebra: type FloatOrFloat32 = Float | Float32 inline def toFloat32(f: FloatOrFloat32)(using Source): Float32 = f match - case f: Float => Float32(ConstFloat32(f)) + case f: Float => Float32(ConstFloat32(f)) case f: Float32 => f extension (b: GBoolean) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala index 98f1dd67..f307f9b5 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala @@ -11,55 +11,55 @@ import scala.annotation.targetName object VectorAlgebra: - trait BasicVectorAlgebra[S <: Scalar, V <: Vec[S] : FromExpr : Tag] - extends VectorSummable[V] + trait BasicVectorAlgebra[S <: Scalar, V <: Vec[S]: FromExpr: Tag] + extends VectorSummable[V] with VectorDiffable[V] with VectorDotable[S, V] with VectorCrossable[V] with VectorScalarMulable[S, V] with VectorNegatable[V] - given [T <: Scalar : FromExpr : Tag]: BasicVectorAlgebra[T, Vec2[T]] = new BasicVectorAlgebra[T, Vec2[T]] {} - given [T <: Scalar : FromExpr : Tag]: BasicVectorAlgebra[T, Vec3[T]] = new BasicVectorAlgebra[T, Vec3[T]] {} - given [T <: Scalar : FromExpr : Tag]: BasicVectorAlgebra[T, Vec4[T]] = new BasicVectorAlgebra[T, Vec4[T]] {} + given [T <: Scalar: FromExpr: Tag]: BasicVectorAlgebra[T, Vec2[T]] = new BasicVectorAlgebra[T, Vec2[T]] {} + given [T <: Scalar: FromExpr: Tag]: BasicVectorAlgebra[T, Vec3[T]] = new BasicVectorAlgebra[T, Vec3[T]] {} + given [T <: Scalar: FromExpr: Tag]: BasicVectorAlgebra[T, Vec4[T]] = new BasicVectorAlgebra[T, Vec4[T]] {} - trait VectorSummable[V <: Vec[?] : FromExpr : Tag]: + trait VectorSummable[V <: Vec[?]: FromExpr: Tag]: def sum(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Sum(a, b)) - extension [V <: Vec[?] : VectorSummable : Tag](a: V) + extension [V <: Vec[?]: VectorSummable: Tag](a: V) @targetName("addVector") inline def +(b: V)(using Source): V = summon[VectorSummable[V]].sum(a, b) - trait VectorDiffable[V <: Vec[?] : FromExpr : Tag]: + trait VectorDiffable[V <: Vec[?]: FromExpr: Tag]: def diff(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Diff(a, b)) - extension [V <: Vec[?] : VectorDiffable : Tag](a: V) + extension [V <: Vec[?]: VectorDiffable: Tag](a: V) @targetName("subVector") inline def -(b: V)(using Source): V = summon[VectorDiffable[V]].diff(a, b) - trait VectorDotable[S <: Scalar : FromExpr : Tag, V <: Vec[S] : Tag]: + trait VectorDotable[S <: Scalar: FromExpr: Tag, V <: Vec[S]: Tag]: def dot(a: V, b: V)(using Source): S = summon[FromExpr[S]].fromExpr(DotProd[S, V](a, b)) - extension [S <: Scalar : Tag, V <: Vec[S] : Tag](a: V)(using VectorDotable[S, V]) + extension [S <: Scalar: Tag, V <: Vec[S]: Tag](a: V)(using VectorDotable[S, V]) infix def dot(b: V)(using Source): S = summon[VectorDotable[S, V]].dot(a, b) - trait VectorCrossable[V <: Vec[?] : FromExpr : Tag]: + trait VectorCrossable[V <: Vec[?]: FromExpr: Tag]: def cross(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Cross, List(a, b))) - extension [V <: Vec[?] : VectorCrossable : Tag](a: V) infix def cross(b: V)(using Source): V = summon[VectorCrossable[V]].cross(a, b) + extension [V <: Vec[?]: VectorCrossable: Tag](a: V) infix def cross(b: V)(using Source): V = summon[VectorCrossable[V]].cross(a, b) - trait VectorScalarMulable[S <: Scalar : Tag, V <: Vec[S] : FromExpr : Tag]: + trait VectorScalarMulable[S <: Scalar: Tag, V <: Vec[S]: FromExpr: Tag]: def mul(a: V, b: S)(using Source): V = summon[FromExpr[V]].fromExpr(ScalarProd[S, V](a, b)) - extension [S <: Scalar : Tag, V <: Vec[S] : Tag](a: V)(using VectorScalarMulable[S, V]) + extension [S <: Scalar: Tag, V <: Vec[S]: Tag](a: V)(using VectorScalarMulable[S, V]) def *(b: S)(using Source): V = summon[VectorScalarMulable[S, V]].mul(a, b) - extension [S <: Scalar : Tag, V <: Vec[S] : Tag](s: S)(using VectorScalarMulable[S, V]) + extension [S <: Scalar: Tag, V <: Vec[S]: Tag](s: S)(using VectorScalarMulable[S, V]) def *(v: V)(using Source): V = summon[VectorScalarMulable[S, V]].mul(v, s) - trait VectorNegatable[V <: Vec[?] : FromExpr : Tag]: + trait VectorNegatable[V <: Vec[?]: FromExpr: Tag]: def negate(a: V)(using Source): V = summon[FromExpr[V]].fromExpr(Negate(a)) - extension [V <: Vec[?] : VectorNegatable : Tag](a: V) + extension [V <: Vec[?]: VectorNegatable: Tag](a: V) @targetName("negateVector") def unary_-(using Source): V = summon[VectorNegatable[V]].negate(a) @@ -92,11 +92,11 @@ object VectorAlgebra: inline def vclamp(v: Vec3[Float32], min: Float32, max: Float32)(using Source): Vec3[Float32] = (clamp(v.x, min, max), clamp(v.y, min, max), clamp(v.z, min, max)) - extension [T <: Scalar : FromExpr : Tag](v2: Vec2[T]) + extension [T <: Scalar: FromExpr: Tag](v2: Vec2[T]) inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v2, Int32(ConstInt32(0)))) inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v2, Int32(ConstInt32(1)))) - extension [T <: Scalar : FromExpr : Tag](v3: Vec3[T]) + extension [T <: Scalar: FromExpr: Tag](v3: Vec3[T]) inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(0)))) inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(1)))) inline def z(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(2)))) @@ -104,7 +104,7 @@ object VectorAlgebra: inline def g(using Source): T = y inline def b(using Source): T = z - extension [T <: Scalar : FromExpr : Tag](v4: Vec4[T]) + extension [T <: Scalar: FromExpr: Tag](v4: Vec4[T]) inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(0)))) inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(1)))) inline def z(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(2)))) @@ -116,48 +116,38 @@ object VectorAlgebra: inline def xyz(using Source): Vec3[T] = Vec3(ComposeVec3(x, y, z)) inline def rgb(using Source): Vec3[T] = xyz - - given (using Source): Conversion[(Int, Int), Vec2[Int32]] = { - case (x, y) => - Vec2(ComposeVec2(Int32(ConstInt32(x)), Int32(ConstInt32(y)))) + given (using Source): Conversion[(Int, Int), Vec2[Int32]] = { case (x, y) => + Vec2(ComposeVec2(Int32(ConstInt32(x)), Int32(ConstInt32(y)))) } - given (using Source): Conversion[(Int32, Int32), Vec2[Int32]] = { - case (x, y) => - Vec2(ComposeVec2(x, y)) + given (using Source): Conversion[(Int32, Int32), Vec2[Int32]] = { case (x, y) => + Vec2(ComposeVec2(x, y)) } - given (using Source): Conversion[(Int32, Int32, Int32), Vec3[Int32]] = { - case (x, y, z) => - Vec3(ComposeVec3(x, y, z)) + given (using Source): Conversion[(Int32, Int32, Int32), Vec3[Int32]] = { case (x, y, z) => + Vec3(ComposeVec3(x, y, z)) } - given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32, FloatOrFloat32), Vec3[Float32]] = { - case (x, y, z) => - Vec3(ComposeVec3(toFloat32(x), toFloat32(y), toFloat32(z))) + given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32, FloatOrFloat32), Vec3[Float32]] = { case (x, y, z) => + Vec3(ComposeVec3(toFloat32(x), toFloat32(y), toFloat32(z))) } - given (using Source): Conversion[(Int, Int, Int), Vec3[Int32]] = { - case (x, y, z) => - Vec3(ComposeVec3(Int32(ConstInt32(x)), Int32(ConstInt32(y)), Int32(ConstInt32(z)))) + given (using Source): Conversion[(Int, Int, Int), Vec3[Int32]] = { case (x, y, z) => + Vec3(ComposeVec3(Int32(ConstInt32(x)), Int32(ConstInt32(y)), Int32(ConstInt32(z)))) } - given (using Source): Conversion[(Int32, Int32, Int32, Int32), Vec4[Int32]] = { - case (x, y, z, w) => - Vec4(ComposeVec4(x, y, z, w)) + given (using Source): Conversion[(Int32, Int32, Int32, Int32), Vec4[Int32]] = { case (x, y, z, w) => + Vec4(ComposeVec4(x, y, z, w)) } - given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32, FloatOrFloat32, FloatOrFloat32), Vec4[Float32]] = { - case (x, y, z, w) => - Vec4(ComposeVec4(toFloat32(x), toFloat32(y), toFloat32(z), toFloat32(w))) + given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32, FloatOrFloat32, FloatOrFloat32), Vec4[Float32]] = { case (x, y, z, w) => + Vec4(ComposeVec4(toFloat32(x), toFloat32(y), toFloat32(z), toFloat32(w))) } - given (using Source): Conversion[(Vec3[Float32], FloatOrFloat32), Vec4[Float32]] = { - case (v, w) => - Vec4(ComposeVec4(v.x, v.y, v.z, toFloat32(w))) + given (using Source): Conversion[(Vec3[Float32], FloatOrFloat32), Vec4[Float32]] = { case (v, w) => + Vec4(ComposeVec4(v.x, v.y, v.z, toFloat32(w))) } - given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32), Vec2[Float32]] = { - case (x, y) => - Vec2(ComposeVec2(toFloat32(x), toFloat32(y))) + given (using Source): Conversion[(FloatOrFloat32, FloatOrFloat32), Vec2[Float32]] = { case (x, y) => + Vec2(ComposeVec2(toFloat32(x), toFloat32(y))) } diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala index 46f60e9d..a1963157 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala @@ -10,4 +10,4 @@ import io.computenode.cyfra.dsl.Value.FromExpr class GArray2D[T <: Value: Tag: FromExpr](width: Int, val arr: GArray[T]) { def at(x: Int32, y: Int32)(using Source): T = arr.at(y * width + x) -} \ No newline at end of file +} diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Scope.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Scope.scala index 3ad330ca..811247de 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Scope.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Scope.scala @@ -4,4 +4,4 @@ import io.computenode.cyfra.dsl.{Expression, Value} import izumi.reflect.Tag case class Scope[T <: Value: Tag](expr: Expression[T], isDetached: Boolean = false): - def rootTreeId: Int = expr.treeid \ No newline at end of file + def rootTreeId: Int = expr.treeid diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala index 3e92b8ed..33df3207 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala @@ -7,14 +7,7 @@ import io.computenode.cyfra.dsl.Value.{FromExpr, GBoolean} import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag - -case class When[T <: Value: Tag: FromExpr]( - when: GBoolean, - thenCode: T, - otherConds: List[Scope[GBoolean]], - otherCases: List[Scope[T]], - name: Source, -): +case class When[T <: Value: Tag: FromExpr](when: GBoolean, thenCode: T, otherConds: List[Scope[GBoolean]], otherCases: List[Scope[T]], name: Source): def elseWhen(cond: GBoolean)(t: T): When[T] = When(when, thenCode, otherConds :+ Scope(cond.tree), otherCases :+ Scope(t.tree.asInstanceOf[E[T]]), name) infix def otherwise(t: T): T = @@ -30,6 +23,6 @@ object When: otherCaseCodes: List[Scope[T]], otherwise: Scope[T], ) extends Expression[T] - + def when[T <: Value: Tag: FromExpr](cond: GBoolean)(fn: T)(using name: Source): When[T] = When(cond, fn, Nil, Nil, name) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala index 65e48285..6ed56ab0 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala @@ -26,12 +26,12 @@ object GStruct: object Empty: given GStructSchema[Empty] = GStructSchema.derived - case class ComposeStruct[T <: GStruct[T] : Tag](fields: List[Value], resultSchema: GStructSchema[T]) extends Expression[T] + case class ComposeStruct[T <: GStruct[T]: Tag](fields: List[Value], resultSchema: GStructSchema[T]) extends Expression[T] - case class GetField[S <: GStruct[S] : GStructSchema, T <: Value : Tag](struct: E[S], fieldIndex: Int) extends Expression[T]: + case class GetField[S <: GStruct[S]: GStructSchema, T <: Value: Tag](struct: E[S], fieldIndex: Int) extends Expression[T]: val resultSchema: GStructSchema[S] = summon[GStructSchema[S]] - given [T <: GStruct[T] : GStructSchema]: GStructConstructor[T] with + given [T <: GStruct[T]: GStructSchema]: GStructConstructor[T] with def schema: GStructSchema[T] = summon[GStructSchema[T]] - def fromExpr(expr: E[T])(using Source): T = schema.fromTree(expr) \ No newline at end of file + def fromExpr(expr: E[T])(using Source): T = schema.fromTree(expr) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructConstructor.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructConstructor.scala index f41b192f..f32fed00 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructConstructor.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructConstructor.scala @@ -6,4 +6,4 @@ import io.computenode.cyfra.dsl.macros.Source trait GStructConstructor[T <: GStruct[T]] extends FromExpr[T]: def schema: GStructSchema[T] - def fromExpr(expr: E[T])(using Source): T \ No newline at end of file + def fromExpr(expr: E[T])(using Source): T diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala index 750e6563..e0cd5d8f 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala @@ -69,5 +69,5 @@ object GStructSchema: private inline def constValueTuple[T <: Tuple]: T = (inline erasedValue[T] match case _: EmptyTuple => EmptyTuple - case _: (t *: ts) => constValue[t] *: constValueTuple[ts] - ).asInstanceOf[T] \ No newline at end of file + case _: (t *: ts) => constValue[t] *: constValueTuple[ts] + ).asInstanceOf[T] From 41267ce74d803ca199677e994912edbc7c3f78e7 Mon Sep 17 00:00:00 2001 From: Soleod Date: Mon, 16 Jun 2025 21:14:28 +0200 Subject: [PATCH 06/59] SpirvTools integration (#39) SpirvTools are now integrated into the flow. --- build.sbt | 9 +- .../cyfra/e2e/juliaset => }/julia.png | Bin .../src/test/resources/julia_O_optimized.png | Bin 0 -> 2429319 bytes .../cyfra/e2e/juliaset/JuliaSet.scala | 35 +++- .../computenode/cyfra/runtime/GContext.scala | 41 ++-- .../cyfra/spirvtools/SpirvCross.scala | 56 ++++++ .../cyfra/spirvtools/SpirvDisassembler.scala | 57 ++++++ .../cyfra/spirvtools/SpirvOptimizer.scala | 61 ++++++ .../cyfra/spirvtools/SpirvTool.scala | 119 ++++++++++++ .../cyfra/spirvtools/SpirvToolsRunner.scala | 35 ++++ .../cyfra/spirvtools/SpirvValidator.scala | 38 ++++ .../src/test/resources/optimized.glsl | 53 ++++++ .../src/test/resources/optimized.spv | Bin 0 -> 2948 bytes .../src/test/resources/optimized.spvasm | 179 ++++++++++++++++++ .../src/test/resources/original.spv | Bin 0 -> 6396 bytes .../cyfra/spirvtools/SpirvCrossTest.scala | 19 ++ .../spirvtools/SpirvDisassemblerTest.scala | 19 ++ .../cyfra/spirvtools/SpirvOptimizerTest.scala | 24 +++ .../cyfra/spirvtools/SpirvTestUtils.scala | 31 +++ .../cyfra/spirvtools/SpirvToolTest.scala | 71 +++++++ .../cyfra/spirvtools/SpirvValidatorTest.scala | 33 ++++ .../io/computenode/cyfra/utility/Logger.scala | 4 +- 22 files changed, 845 insertions(+), 39 deletions(-) rename cyfra-e2e-test/src/test/resources/{io/computenode/cyfra/e2e/juliaset => }/julia.png (100%) create mode 100644 cyfra-e2e-test/src/test/resources/julia_O_optimized.png create mode 100644 cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala create mode 100644 cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala create mode 100644 cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala create mode 100644 cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvTool.scala create mode 100644 cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvToolsRunner.scala create mode 100644 cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvValidator.scala create mode 100644 cyfra-spirv-tools/src/test/resources/optimized.glsl create mode 100644 cyfra-spirv-tools/src/test/resources/optimized.spv create mode 100644 cyfra-spirv-tools/src/test/resources/optimized.spvasm create mode 100644 cyfra-spirv-tools/src/test/resources/original.spv create mode 100644 cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvCrossTest.scala create mode 100644 cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvDisassemblerTest.scala create mode 100644 cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvOptimizerTest.scala create mode 100644 cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvTestUtils.scala create mode 100644 cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvToolTest.scala create mode 100644 cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvValidatorTest.scala diff --git a/build.sbt b/build.sbt index c369050c..2fef2351 100644 --- a/build.sbt +++ b/build.sbt @@ -47,11 +47,10 @@ lazy val commonSettings = Seq( "org.lwjgl" % "lwjgl-vma" % lwjglVersion classifier lwjglNatives, "org.joml" % "joml" % jomlVersion, "commons-io" % "commons-io" % "2.16.1", - "org.slf4j" % "slf4j-api" % "1.7.30", - "org.slf4j" % "slf4j-simple" % "1.7.30" % Test, "org.scalameta" % "munit_3" % "1.0.0" % Test, "com.lihaoyi" %% "sourcecode" % "0.4.3-M5", "org.slf4j" % "slf4j-api" % "2.0.17", + "org.apache.logging.log4j" % "log4j-slf4j2-impl" % "2.24.3" % Test, ) ++ vulkanNatives, ) @@ -60,6 +59,10 @@ lazy val runnerSettings = Seq(libraryDependencies += "org.apache.logging.log4j" lazy val utility = (project in file("cyfra-utility")) .settings(commonSettings) +lazy val spirvTools = (project in file("cyfra-spirv-tools")) + .settings(commonSettings) + .dependsOn(utility) + lazy val vulkan = (project in file("cyfra-vulkan")) .settings(commonSettings) .dependsOn(utility) @@ -74,7 +77,7 @@ lazy val compiler = (project in file("cyfra-compiler")) lazy val runtime = (project in file("cyfra-runtime")) .settings(commonSettings) - .dependsOn(compiler, dsl, vulkan, utility) + .dependsOn(compiler, dsl, vulkan, utility, spirvTools) lazy val foton = (project in file("cyfra-foton")) .settings(commonSettings) diff --git a/cyfra-e2e-test/src/test/resources/io/computenode/cyfra/e2e/juliaset/julia.png b/cyfra-e2e-test/src/test/resources/julia.png similarity index 100% rename from cyfra-e2e-test/src/test/resources/io/computenode/cyfra/e2e/juliaset/julia.png rename to cyfra-e2e-test/src/test/resources/julia.png diff --git a/cyfra-e2e-test/src/test/resources/julia_O_optimized.png b/cyfra-e2e-test/src/test/resources/julia_O_optimized.png new file mode 100644 index 0000000000000000000000000000000000000000..a1549b0aee25dfc983922cf5cea09cf482d3f01f GIT binary patch literal 2429319 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 z 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

s)PMry2?8ZvDwO`2J0g`{`(XEtO7yEQLzv`C z`ujUk_mrIJ`iFlMe`%3%4a=+*5~NH-#Jm#+vM<^ObQ$xU~v+F&jqbyH>#rCg63T zYP|xeG=L>qUEiq~7-v$A<2+f;d3s_l4XhRGxbM97JYpaCO$CgZcho$VYX6?mqY6B^ z%tKYrYElWlfN^RXE?>3h^|vV*$-65~+6(QU$BB9=zHn&aKgtLjvHEdc+ihIS`rHM= zqcu}|Px@{wbv!uPm;GUCpjIy?$(xz+G*HO}BfuYeOd}0lzdcLwjbX<25(DC^dHsB2 zqvD(MZ^T=v`oCFs#^W!R@})?Cl{Nz1fq{(u;A-RMR#et%*@EPU+P|Ltb5Czy8-a3U zv=|S(50ozIaa4xGaFD}++>_^8Y=Ht>s&?SS7n=~*pLNMwJA@BWJ|>!IJGxn^z3K>F zcl^(z3*=C$c})vWCLRZs41LW9>;n~3(&1tgvEMTTqivvaFO)FZQj;F4=@{w;7Oebq zO!22#St4vOLoP(t3WJ7|$@46FHZEd=gm*%0!Bi`T!-dC}pO0$vEk_TP7g-~vo!?{# zS7cZ06zehGt}BU-ru=ms_qdnD=4n5apYH7og@S?m8}I@WviA2<*p{fMZ83UsBOczA zx65QD^3!hVI%sVkA+vx9ADA&w>m_1MiEnYtHd?v8DjfT4tT@(i&LSs4w&YaO?d4d- z&;V|lzAE?=Ul|%ah0mCV6%w#6RvY&3q8!D~ZlRTMbMk*!tnh&A!GC;VPI7P79h^$= zh0u8Le7m1Im(y!S$^b=EPx&G3lHJv!>+mm(H7_Mi#s66~_zDcWV?YnB|1Qf5fTEHg zbOX6|AHTC5kqUglOaa#q4;#|FrWz>p2pW^Ve+Jn6co#`VwTVFy^`$S7f0XH5T zC-ky*`T3<9v93ks^-4KN5g{21l#nk7#&(Ea2G}&~awY^ALL;)@7f&xvb$?Y?VIL3` zNV~lZtP0I&cHGgbPO&THbmtu?sH8lD0ML&+fQP&;*|R191q>crP39U#Mz=^lfAweo z6}ePd?SLn70c7Ewd*HRcPZ1c)ac(315Ch26r8=tc{*%~&ssVoARECvjz>%>e*4%OC zS4^&RL=gU7s6o-)S|*Rb=XGPN$YxBam~ZsvJ?|S&%u0!$tVHcupaJ~7>0l7SK7WTRfNI7MO5dM#Gl@wnVQ|jlIQiXDH*-! z!1J$n-v>Sa2jKw9SN(njW^XWWv0Nlp1FGGOI`1n`Ink9QLCWv3Se@pBc>TrkVwOc| z4DetY2zs2*t+T%jS}tikX-F`+p{X;#b`w```RaYC0mjYlxsxBCeS!nQ#W!2ttZ1!> z->BY57`WJW^zz462)NlaJn=$37w?f5AYlRdI|YOwE_XQko=6DSNl3r~P|rxVn}8Ny zkYcm6gadpZ8mU@sKJX!lx4S6kDGLo#DhSveZtUswo1wh zJFu337WlA}+$EB_?Z%E5yX#viAS~G~ch~5P;E&pXYpeLUZGI*CSXx3VsBV6Fn&K!L zMhL|RRiMI1O9mN(FyEb z;6Q=lbjR^ELxqANl`$e@`h&Tn-=i=88Q$RB2v^YYa~O;m`^IAgbeudc3o%1EVjF|!_%Xg zfw+#KUjz)!@sgsDiblQulthBi1J~5L$C)!@SZf(g2GnWcS6<)fJ-Be^{3gR5tTW+H1q=axSKlm-gfJ^UK(! z#io5C7ko{9L_k-zxT{fbGl(_XBLS@7Z&MZAcZjK^XMGlDqr!Q>dJD3;^f^p!#FzdFs<*E|mUo59qMKzx{MU!%V*B zKD*4;SF~3FAe02aH73ru&D>2%!MHE6Umt+GIWBcu9?rg^e;4lypv7CnT|X`W+u$9! z%SN=r#A+clacBeZXF%9L0S9V^7@Sc8mM5&bBm|z#M0vFsr`_!nvSH!-?kbD*lItzT z+Z*}~vNW?hNTuG=l8jET?T1X9`VqXEZ166i|@~@%r4%Wlo)WZTZFE3#yt~hUJk)LqYvIGfc*K`dfx^ZSU{|ky4lw}0=;Z?k#!fO++tLkR!XHl zcSbXF)r;(SeMK|2^G!IPlLAK4)ID9MMYgl>y@4N;7PS~J!W%d*%EWT~u26}86c|uk zCHmgX#eueR{ZHaG+@Dv!`R@^?d;f5>3UcjTYoGv|bLUGP_)f{Dssg+fZ4X^9*+kUd z8<5OO1OW&6R;|&MY}=J<2VQz# zYODpKVnAXb%uXLXvLju{5*x@##FRHX6SBUf!=bUI35;zqbIRw)IXI5|fzG1(tS@AJ zwv_hD3J(*`ee8;_b9kG*FD?4=4u(z&QSdk*b6ZiSR6lYLjlPOPim%3hVt)qK2Gt|r z;@e4_4b|2VWhT9x13LO^cbIwGNt$B)ZB)DXp|Umw_AIQ;_3X6(Vfh?THB?TUbOp)w z7qVF!n>M7MUEKLv5Zsn2?mENz;@MkZhH=!HzvKt7G<;sM`>r)9M(RzMy4*T8Z<{4Y zoU4`39*&t`^cPnVe+VIa7NLofOk;j6M#DD$k-gag8Y=&#sGjNqq92;JT*Pl9}DgzgcSUseyMsBSBI?6-9uR11Dsyv+(%ijE9$FYQX^kN zO^}su{D)1&wAmif4p1?#7gg7{>JC$z&{i(?3UZe;J|a}N)Ond?pTm(a%y;h^->vf@ z&H1OoNQ}(GluYk?rcC{qql*w&VIqPiiG`InlW?K(ukOOV!mdjK`{H)&W-28`zZ={& zE^K4durDVC*;3Oqf?3?Zgb>(vmIz0N7@xCj5U8wu{3BmaD<{0JP`e5<_px<_Juq!b z`>z-OBO>8Rvk;50z96sFo8ldUtb8d5bUZWUDbT$^pIW=~D|gq_{TzUYXv?mGx|C7% zE!RJi+%2a7Po_}1Ex65OxTVgZPagqrOH=G`0GCQ}`&4;^IxrZ`0;j|!y(+f|i)Gu% zGFKRUX6xhFz zJ~|ssKIig^=zrW#4Lbw~lI^h|f`CYONVk+I(jlDpI`e z0}W_3hgH>2#d#zHIlzxGS`1q}U5-=bS0>eAW(@rS7H25Jl^HWk_AzXOE~}qs7Lw~n zD8Q$8Hyz-`=DC<(X`Mce?-0Wb{0fK^8w0m>bJ7F?*Qsyss+kRs(wrI(AOeZ(sB;Y2 zPOCj$N(0=CTA>W+Uxh|I8ast6`Z=ws4@^iRUp3pUPoDlZ_0DRT=N!5 zK5wmoz4w0Jgb8xG1OwkUTdHCG5IvFc@*+%53$1t=c=`V z9LjHFfC#jB4@{At11DAIJtVfg+4`8J!?Y~NM`D{20V6jAR;+2xb1 zC97A&=Dm8`cKbg)DPi8?cx_)gng{16C3n2YG}=3W4T#rQ3^5RCWVc;>R<+b}m>|H` z7Bxj_#jLD&ESCeb9YR-rhtq}L6Cj3!+ymkrodI*jF?b{F4R>K@iasPqIhbiP_A3vo zLBHuPP18ud0JWwnw?DLJ5iXmjG}2_D%OB@aAl;m;C=8!Tb`b6(wr7&Ldx~I*z<{c$B#zFGH{)mjoV89+ zA3_1POJBtjRP?)dTWw;e=VmYl~=o-dExWbVOSXC%QW=`#W*+-)Gnz)XtQS2b|RyG7RNbn8jYcfAY=W?GWs zDWjk3zc%na=^h7m<%ui-J7q^JSmi%&ksEzJ!!xN7N^?jX`H3>tZMOl?fcrF3L#1|p zQ_OK5UuY$q=J5MSxF@n(P-n}S1$}P;?nfZFeeh&e@Ey7LlWQ0{+S3QFx!T3?*)Of( z0r6!uq)>61YhS*zCyd4^xe@If$8S>IR|c=9#bxcPj3B^l3Xsx;QV%!4uVhza3T_FJ zO7+z@*HWYpFufDYSex=ejQ8eJw?0BsmFGiIxnR=wH#%KEbvx`YlaJ02L=7DH?TM%BZc>s-}7g`;LHHuu#Ly^v-pucx&-MAv1 z(u}J=J>29AH}GpA5k=e3rwh$@QR=lF7^EpjsH@&E4?$bq5-Q~=FNtVr8PxKyO4zUi zJqhIe8H!BH1RGrff9Vm~r_Yy=nVa;VSKh6o+nDyOF{LB{aelife}8vYydL2gh2kE` z?vmf8>oFS;Q#nT7Ie>nZb8G>;p z`}FV^5Rgg&s{(j&**T7ZQ2qm;MnN~x2#~$~ykzC1>3^G+R7Vz;PF)2c<^XHJm8Kkd zNZa?y&YXv|Zgh&0-ZrYoKxrN^cmN=#Jt_i2<;Eyb5~?c&_5i~}A1V^s1Nfgj=Uxg@ zoJ_4mOK|v!26;kd65E^!HB`i0C!!hulB)O@XA6SRHIEWtDEj$A;YeG`2aN>2IY*ZKp6M(A7jg%2OD#ZFaXFliHsW3ZDjE7a0^M-3_9 z@U}0m1EqGL*XEw3xFpIVef~E<8KoM-EK3&VHaZ&c>Mp#E#!cD_lqnXT1rzh1c$-14 z08kH+3?+&&jVl(PT$F$0AIw>*18h&a>W_dL?To6m@1%2r$c!b_97!>RZYc)-zBs`#BwVRE!y zsr}{;aC*Jk=_WL@mnl0DrA?vx;|YYU z;ox6f!>mj-McUoxG;|oP4_Lr56uz&-%WZNB;ab~=&i2c8cHoUGs=a%}FL%PnlAav; zD7nA29lZ3E-fRDnWYKL8wiOUpuzw(Ujg%DuPM>{OtGqr%WgAp<4bU`!4fGKp)WJS| zoC><)9FUoSVpWtuYE$|HR!*V`xY8b`C>?hLR2wNiY3&GdT{m4sa&SOQ2s=7M3g^B* zzXEcT0Gs1)09Q-TIs$skqy&5CzfsVYi=30O+OGAukT*$aahf)L)0_bt2?hm5Cn$sWx7JJG2O=7weq7vz6 zj59n9TfGRTlXF43?^MS8PJcNAcfpK|6k-a1fv){~a^|wKmBILq`CfMlY6i`mN`d78 z;#JJ0Q^+#o3t%z5viV?EW=Y#6*P?Zab%*l|NNL9AHWL`P?H-l!5db~^-1W#*Vds8M zpHqZj1;Y0Z2&q0D9X69QjBft4226ohR{JP)vFM>QkSA+s;z1sZvL|Br^#NoZ_BlTE)$qic~WTB|>DisU^lDJbb4F)hdMn~!HR z;3-D{>Na>mUK)fW&k@N9LSAh}AFf*mYN_Dm=j&!HyC$u=9c9fWg7{A>i>xov_gK5vXvI=-pjFo`& z1+>QZYYqR{xPjyF{heNoQ0G8&(sw0%yBmXM^^GVFBJ_zU`6h?2%UWhTTpghg(k~1Z zPinCrleTA2Odflx*r3MZUfPvq5Pi`6U`6=1z*;<~K079P1Sc%-+Z~k{cXloh;wIA? z*u(KZ+*H=^0(8QI!9&KT@7Ep0K1BVGyFKn_MPf3T3_2cemW8f(#iX6zeWn$at-3Eq z+s;DRxu;Fv&oE&6H}Y43g9>6?z{N_&T}inTA8?!4e-r^g4RK!wgzBXp@uQO=fW&Q5 zb~n3jM`MnfQ7yIU9RbS=c6$9gfwfoA-0HSeC#`R;f0diqKMW1le=sz2NcTP1ra9HM z%cqi6R9_6q9!({C;rgkUXbd;{SmW=))an%or;>t%d*o73`XPq63GnDjwO=i91gy*e z6-(mqE`UPZ%VWVA?ghI2ej?hMC`9mkAZ9Gzf&EB-ThW#g-dWg(4-?v`dF+jXJ@f84G zaQv*M)1&$7(g|x(aQaH8ZyRZ%e0WErf86LXLmDYRTdu6%1w52pcGtMcxtp)${RG+xEL2ssy4X9sP)4XsY%Z6kB5nFfyN~gm}jK zJbLb<8Bl#I$Rx4SHx>8+`or|y`*1Ev+f5Mj5FLO8bw{?wf9aZ!TNx-R3(e0|>D737 z2T-F%3(KWHv6xyK)vC<9;iMjHCLcLo{%C^9Zs=>0$pFza>I@wC3t_*l zH1ivN2Q!98P^=o#+rM>^}E!TL=6~L38p2%Bmp?iHU0zi7hrAzaOdhsn>t@GtGzRd+KX?`2Eu2NvM)X! zI?a#iTPv#szLoA#k5B-MN2(I8%qfpP>rwenAu3HwQ2sb#=r<{T&p`;;#9Q;AbE9Z; z20f`?_ZU!p*(Z>8gv}NiMI<_VXQ$v~j9Awomzc?vrH8#R+XwN6Wl+2kn8&cS1#Prb zlU<-XNq-RYa!$X80BiZBap^2Vd*|tVY^4$2K{KxAc}*YT zk$!%Ht*;u2QN`~gmyzV3lkUxN!<#w0h7xP9``4sQe=6Tj%T{EjC7xM`%9bxWxA9v4 z@0uZnS&Um+E;D*j%|r>qbWY=_;)@gs&9lS{&M3(QYu!3KIZiGN5$g5 zD5XZ_(|c(GmO$1Q6Tz{!moN+cqLKrgeBg}fLwT#3HpR=CqPT&c7G{G)CuLJ;gP$Wd|v0aRHpfYTD`-v*2B5p;;ODrl%1`a{$}dUyCB@(~GY zlMuA?xyKS-!@qTq3V-~dg@Ud;As;r5 zA76oR#|$JK)w400FP18H0a*MDcx4tAE4VzdVRvo>$x zLQHV@OaCSzKaRl-CP7D!23PYWOy;+#ADOmv2GNZ<+n?g$L}SBKFLd8LwtP%z0MH<{ zp>!0R_z&`U*y{ZEC7OrWA~~_ViQk?a^R0zLHSdSe9cK)7&jcKXQzAL~W8o{V`Ptzu zL}TEH^)!N88d@A*)VLbD&lxMC!Pe70kDv<66rGuX{c#?xM!a?Sbbb{=Ek(Qo&e8$I zWtupZxMSKyb5LMwTrgV*M0Jsy2V6D$5MZ@xPyAYNGUu8B>!?GKd&Z;Bqfz{&@7YKH zF@plBDn(1$0p(<~Kt~ppn?nnYZ^C&8qbREu(-uYC4y=|_0Br;Q@dwLvbqdOQxIDBc zegZC0BDVnE4iJ;`*A%}Rka~w6_(|`vKDP}8H!bUM4%&a@~IHxfn*JbV& zC_)m_J6a8^$eT1a2}Y4?g#IPhWgmvsS4aJ=7W1FGZ-$Nw|JTU8|Fgna?X$;07zE>B zMyLvP5lCGL0xmyb=(0tw%HuA;WKnPv2(}6U?WjdqjOt|nA%qj*ypP_iB=d?w$v=aH z?BqzGC7FibyKOH#9SWFjTx^j^bCGU?M~)D;_)C04)d7G-{t`PJ){8`uo2WDh{px%9 zOq1QZ`kEK}>%)rXAz2`RIBn1KY5{cO^#T8*c-TJh zB;pV3+ix(oMS^?GX;?q*i--Gv0FqcVdi00G1&&KJ+ATiI9}WQhpS$3(&@SlYGdCciBBz?H zp*REW0U{(Nj$2uSVvJE>d-q;TV4-C`{uI6|NuZLHmWN|EPF_kB ziTod1y&4JnMf4{OT?92|5AHUtvZlZ_>!rZLlcmGQQBoM>Bt`D=;_U8oocQJ-B8 zk_hvgn{|o_EP52=rTubDLUdagMso_Y-J-YA76}~*GD)d;u;ojZV1Q{CqUk!8=8O7R zz<-A7^4Z1I%0DvG=imMv7OSEqag&Ff!T*fDg?Hx)Y|tAbu5__)6{y*lUfGS2Bx8bx zb_0Ibe@b7WJp*^5_Yeh1c(KKO=_Bl*?d;YE-I4og^QZ!8>Q@sW7xt)_(77Dw$DjK7ksI-0)dMXM>GnHKN2}+LQ$z6m4&1@R^1n>g0 zMFq2m05YN`XB_U4QqN|eoJt3DTvxw3+9?!NI66TE8O;JpWD6wC9?V}8M1jwOQzdiQ(zf;`xa~!G&FK=bAl&f zc}7IDaLAe6h;T~o;$C9zU$ajphITlXKZ3y1=`b+%o?r#idwJ^&md}9$M8L*W$8G8l zpiE>`$CIC99obleDYm5O-Jaz42wuPG({&1@L?CQ_qOAn(>c4HR4)tnMEH>Vl_oTcujY z|D#38w)ykQDxfV-nd{1&`)ySC|FlU7vn1h%G6;ThcBfKg$`C1ZILM)iAM4|69Pzhi zE2x(`U>+N134Gzd?NklZ)s6s4d5Zk7N*s@dal| z{V;6;u?h%whhs9>FMyk-I((-MkstoHy8YMz@}tG=u(TXm=Dq0C6q%SCZ)Uu7Zg%kkp>S0HM0j@>8m@ z%B0Old0Fj~9(ICBzWshldBORN=s*6$|9S_XbpzJJ{pv=tSP_WGM)ac9KM4X{*&qT8 z2XkPgK>};iG%`t2Z*colK!O#?OllVp{e8#+%?rucRn!`^84un#D_|%w0ath%P~LI8 z#5JVoJouko-f}TmiuqN6UKJ8pQ9c5{8d-S?b30fnUko|Mzi z$6!oxPBSGE>T&1ruio{I;lg~0>8A_LHPwQVvRguhPao}9y-AYY3xJM*@iaBpGUW=q z6906=DRV@D0}uo&BxY)0m(nIGc2Oz>joVN1A?_?R~d6))#LxU$7Oeav0)z6A0X!AyPEkP6aScjZ@gb z(*}3|+o{CZZfM%~IH?P6-+q{Xmc~Pb+}r+G@fyGklOgIT;_Y)wOn0vhEv?{R;KY6Q zrM6BE>wxpCGnhDvW9z0=|Mt{Zp2^3T3YtpQ#D89NK7%yxdNDYx@};?r#$cuQC@}ra z^K_dATO5~v7b?U4{p@FY&fJWrK&THiZe%!FV`h#$G`?w=mvLL#w4@3*qYDAT;*3A^ zDkZ`S#{D!Kt~x%65veaAaBD{A^TiAr+1I`2R(DliKkMep1 zUN&Gq9!Q&gKrdP8umx<}$u`g;6kOqKnN*+Fa@boUf1gtAqCT<;lDS?5+|!>j?h!0? z92r(36i-+QLzR{Ru2x$0nDnZFWx?`#7BDLy>}lL!M2-9O_e}+;uCcMJ{ihq1<~Q_7 zX^p>y2fY7s@LN^iX5tpIN%25ttW?!aAdnY RaFM$GLfFp%tbp+ntL?P@!- z!1M9jFqgH}R5V4>03ML}F0-t&X1UA)>unDRf0Yr;j|G;rM}7 z*d94T;;pGQghqC?TJuw>V(S)|P6VKyD#i_Zl!QK3{#Hw3$z(96X*;=!REu`Yvo_|3 z|!GsLb8%;U%-{CMheXEk)FavSXvW3wsl;L0nBG zFr~(O1k_?}qWE+q@b$y;bSF+91RiE@6Gf}Ux}2WDM>(pt9u(Fc@IgI5mYfDnXw7B( zGyjzBrtg#>>H_YfDwE6*c`GbIql6g&@>^dYQHU5-!@|AHYH)kW?rZLhxGTbJV&S-7 z>r>?zy@>}K4kap{>$liI`CdxZx1|a@QrxHvqeL#)A0>GHQC`8M{(U6msTwen{sh96 zo;+Xy^L8AKL*{XT_e zei}R9I8#&Cf>=cjadSC>^Lv-S02MLxxG|6E@L3jGBZs3lB?OG4-gr-H&%c{C$peEn z(4yfLItT;A38I4@V|JfIeSAc+i(nHPn9hplcKN7Bs)oN}d16)M_u8d$0?7gfgRIbn z?`WcU5RfI|LqI8W7XVVjo&lNzH=JAA0g4W4pSWnHwnFcvOaqS*E&AG1kaiphoos{T zQSiu4fOivYa>}$R^+Oo)%*r{()o0>#6|%3=CKME#kz}!JrK~;g00f0X>PqrPW*@Ds z&BvY&MWLd4gRzm7H;3FCq@rS>0}f4HEi7y^jJ331{mXVmv`9cE&dh$}iVQ^I( z@LKqRxoFrwhSKdGs)*GqC5?w1kg+j$F^;-!pkVF7ToAlBLUBoNTuj}AFK`8k-KUm; zllY~KLBKs1|04f~J>Wg_4pNF5iQQRUj1CJNc7HknRt-Z+_A@vA$A;L+IKIDN4j zPAXVZZ)V((=>P;FVgXf;AQCiIN-o5M|sNkhpW7{U#OnXKBtt1JK z-ea;g`dJipCHn;T`6d@!*@3~l+6LHAfUkw)Tq49+r7P6ET*X&5ce`K0hX$!lE$sdG z8W3#<-W=qrIrrwg@%b)jy`TcJ{C>-U?V!?a@8e~2!uiljcMB2+A1PyxPdLnbblIFX zhtyLwZF*cz0}cR0x-`vnlu-C11HrKeto4}EX;^T4-w3IL*E&{u!@1f5>5q{U2|a|= zGIB6l#L^3O3O&X&HBsJ0UIX2)-U0*$XJ8v5^d0H~$ZH?ToHP672N{q%nqM9CF=^%) zz}AK_CzuBjNG$=NMuhnRbs*zR*a>tWZo}Y8g#J32Ua78!ymzYTp1d&EmV=!olb|bt zH|K$|5NLQn`Dca!{_|)jL3@H%arw#v!7vtga-&by41E!viAgZ?W>I>2d1TSCU8Cd$ zNj7`u$k-a%*beSY@@P`I2 z<^=pRoMz2;WXTu|!+w275h7G@@C80YCOSi^7b> z1-}=cX-U7%A?*Rt2ZANwuQ{R^(2R~T@yHiD4;!d?$V$7fR<;@d+$l#Y7!}Phu z=(yolrTCqGz-FmI(6mhnP=~^z!U^9i{`uj z=o5F&TrL>ET2U-}2sBpn-%fy+0%YR_K3P6J{?TBJQ2h4T0+?#wg1WuHF_;kp7TEap zp3l`2`!C1p@K=x@SQ~)Lb~|iBxdGsGm3-k* zic+1N9JALML2q)TmhzIvfH<>9R9MDV*z*(b(#$<9>T1iLZkZG^~7ImlcNB9!9@%=nOJ-Gx>>shK5|ZFNzs z7X)A=`0>(!dtV4AA z1BR_sCZF#Fc~$2QN;5Gxmz(gb>F|->^5Vb@H7$uDtCCz(Ng;Cb12x>n)60 zOiAc{!a-3<#)k)WMyY7OBb39z^8jgtgmT}ZbzSjrWQe^@m~w2$2)pga58U)`<(O?8 zO#`717=@~j6F@kQB#t-*a8W70{!$e*BVpYNSt9H$y}}HTiH{(V zu@5b-G4O*=oIepR)9WuadD3WGb$l8`+y2j%q5mJW!GW4t=M6w;nfvzNHESPL0l{dV z*r~f~dLRf+QyiYea18Zn2cjrP$X_52n-9RetV`{WpVXS~TTL1)u{_SSTZiAqIjbXs zQN0H{w}GU&wEYrT)>#u4k>OKzs7a)9PeZ?x$hbgWcd)1+z>Q2`=uty`cA9>)SIvyo zlX)cYaxpOF;0Gh9l25efWhA-*$E1ky?O9t6<_-os^@H?v~M?G}4~hV3D{2pHO#yQavxr z6yS(f!^4ls)60j-f@2(`saP$J#7TTe_EJSPM7fk1?w;5UDCF8ZsEgAy5-ip8$M>`4 z0Z5^cZnZbdJCc#Z)?#3Lq4=H!R-i#`;=!YD3|ryiFD0dy_&5H*B9)+oJUr0fX9K9I^20jE z3`5FLs?|WSBu@xHz>-ZVOv;RWPO z**aB~5pm{yF1Qs0A@Tcc?E?SXQ3p_oBAdBzgn=fx91#I@Ssd0o(^uyqJTyzr^-}x>oS!79ajm}0g{{rP#4enpZ3%#_qBe*^w*baddnKJ$4Bf)Mi zn0*$@FG_3&#z2xVA^Y}P7paL;CoWL}Qd^Zr8@Je>*6%#|Q}pbjp-$(1p@GCD%fsOEEYI&# zn?DbVZ3l5^-oL96_H@|M`Uch?o z2cvSsnN}YNzAu6C+^0>E+t#(njyC?nX6K1|_UAx=o=#=?ZT#@vOlrHU~FRIZ0%$c(!_B5hn= zLf`D?@0Y&(?lYffkEH}{o#=S{`K3m07Gr#CPc45pVbnNtKY9Ji6cL!5R4*ITVfVUE z|CJK+z0aJ+PRB$lg%hX@G(aZGjwJT1A38QfT*=1Y?H81S(&Rs~P*C%pE6g?jR#ll8 zQH%>=nd~*@#wN5-1W_2WJw#8VHDhnf7016ooy?JpB?YNZdtU915lthujBG-dXW}%4 zTpagEKFOvZrlOq(Whm=~NpqpfNz1y3>bL#rIFDPG?~(1U^dn{ZK{def+9^U~@{d<= zp!Lq?YSlMC&DdITzH_aB=&JK4Jo;{T#^m;3B}9(~-^rhL8d84iCuBB&W7)?YLRbfX zixLV9a#!_78;xvrIfvC~J~7`k-IEFwz=Qs7rITm$kZ9|@c~C|*))u81t5O&qXZBH> z)G?!ZgHxP8E6PC72Evj|oydHuv6y#FT zUAfvupt}|`6xd1HN>M()rv6Oh=|#mx3t8nX#@0@Zic_&*(erIe?u*d^im7I6X9J zJKj--V-Sg_utw}e z37r^|rhJcxou3p@g`dc};BAxn9DeWA_#)?cS((FBX15FyC=UIMScjFC20$>KHt!w! z*oRAD6;Oq;4(C`RjuD4yneMM5D%xqy_%l`rS%>J+|51nGjglLP-wB|^+J0nA8~!@T zl=8e%wAhwua-VZnUFaX9`FXQC`#Fb=ndMO%r{@9qo?g!B{!GST-)b_lO*jKl#!0Xy zBSa>+>U)o+94}!5RIqkCtl<$R>}J(16M+JEGf8u5dELD+Gcv)c}MJ|kA_Mtd0)i0?< z2leI5is!in$aFR-xmDK)tHOhXhQnQi3;66E(vknp!?1|I56md`zrog0$PLM@S=hBT@PmPiJyhC(q29ijYO!cn#vh3F` zZ0)mmE&a!q${zUYw%S#7a+}hm%aJE@!hKm^q^c6{gwR4;Z2|<*6~4dK{%9+O2vb8EGIuq(}~c`&@*=Y<5rb zW2dif5(B@GFBD21D^~b~J&tz&n;$rrh9V0Ot46(J#!>)MOFDJm zF{m;fhXo+M)2DOQS`R5~L~j!aKzs%8JH|1|&}FF{1~gnN^fg|b&6frPGUkF^4m_xw zb|~VLn|SlCcEOAF?!-E?gn5U~JTgN=eC0nfG}id{>y{?OmPL+NBnkdbHC=5y6!g_= ztOy?H;^+?s$(v7w?9Ddu1H`BEg&;ir8~QuEakS3=6xtsg%-6YTJRMwX^|OgG?LULd zDGe#c_AgqOH$Y=uoApCRR?c%HtlaM~oWi)T+=&bttYKH$bdXGAgXPJA)R%}{i(8uk zi3W5;dpt~U|4brZVqDsArW1v5zWMjJ3=_2Kh!>y?delEY3XU~%ws+DTcAQ3@9H|fUIIQQrk)Td5u4yukBA%W)?4AnNyhN87A5-S+&}k#|)PDzW8zQ z?rfEUI!#7Lah7)FkrBIEEL>BCw+1$ijYb&E%#;x+va#lxdUR*VC%`dLz4YW;+9&nk zR9w922n^N0!k)X$Bem__{9n48v9VI>uJV@F*}-!Sbe^L(I@6L^3EL{Z1W@;F(d6Zg^z z8jyK%0mMynYFfno+-V{u`P=y@q2G(fh25DCH_<0_gTM~%lA%?1@hq(WwHFz$4m`aX zC+=Dpa&!|sPCoD=^Qe#Jz7=3jo^!A_aL%dwXGQ+}A1iYAefy>DlbGh^kY_86m@Sb( zr5V>ktM|D5Yrk$Z^}eUze|-4&%WX@?%7@FhG>FeS11^lHaC(@otuyH${uUQp4 zfnfY-CfjP`+is>`_jBm&^?ZrdK!@o@&AUY_z6b9qeFfAHcEno5|E@e=p_N{hAB z+VS=!Q50r*G*8v&sW?c^WSL-gB~&9WHo408$rhwr_M48(#O4l9x_|QWO6D#}=Hmt7 z>o{rVcc6reMb+o3-Y^O}ta+z&+lDX;8SHfy|w$m<)^J&GgRhw(JZZ%ysv%Pdu% z^(sYI_+3wXP_LP{9D%_xJ|-%FhQ*aofzM}KI!(w-LtMNEO<*f0+>Vkm9tdB~3DF-* zGF~S~3Y|DIXmlstFJl?dom~~Q8Lbqa$O->wgs}3Qd}#pmQTb$5xH{JL$@Tl8jh)O% zcT07$6!4U9bahI6vtH=+zoGXc6@Rc}m27b_pZ7f6X|@MOUaxU91FQ=K{rljuk5HfF z0IFP0Ql`-X8eWrzcFNN*LLqwXeC>qB+VEKEXFOExAA)@TAJtgeO-H*@H4vKSySGxtnT*y0adgSuNgjUg>7(^BPO_43BB74{1@%ty+ncB@L z=4Y?NKW!&2I~?Q-FaxjB)3>MDJ1JLI)bd$i(&Q$pDa+^&o5YgUkUTFBeplriYiLP& zUh`2Bi+oOm+TjISD>HeQqiLd**}0FmrxzH6z(-3zuDs3itoKh^!wkaCm1W#Gnl!og zR;P5syvwV%dqFIrwl#yOn%?J2=UYoZ*SqcR^AQ#o4+>2@>yX8Hv0)=IfBZJfs1K?rV$q$IPC;u zIkDYi`D%f;#@y5WW{jrvqW`QliT@ra-!Xx<(C+njz>&}``+Dkg??Aac*2R@y?pSN_ zprz!%<@wM8M;xIR%wa$6#dRi#_iv3uv^jMRhDkx9T9%cPkz7@R+$^ubT*G6By|r0e zyv*U8?(^uyUA;bF)36V?gz1d+I|qJF^XMqJy-V_RcgXcRWHYXg&dCu2>+#+6-eDH& zb+d`WKgQ1cUOFG~5MPSeSUzn24o5jfw84H7Mn8ereM7*dX*7B@rH8He=jGM?(Jhb9 zB(E`qp{Z(dB_|8DUA#5VHgr`tc5rbDUrtp_^}v5&2xiz{K~#<)ClB+3zDvF@`RoT_ zp+Z)gExqrPECuaiQxLB!FgEcsSFh8NuNVp zFF2=w2SR-&qXkIF@LI*q!qrlbl|n@1AL_6_y#rA3rYhKnJ`Cst{p0Bg7oB!r@|KW3 zm!<%tJG+u&zl+Z_WpcK-PzD0{6b?|vZC8wpwn8g%w0wqhX)I+UiGaCX|(;P(rH~`g$9cfk|KQGI#ACTPE|r zRSJSGB5t=TSN?IYe!uy&(a-YRi4o>FXPD6pz^lm@dAFZI^E2H-e=Uy-a*_BhU&XXI z26)kqhgYQ-gyBKp=IHhZ#A8{|T3(vMlN5B`%n15u+i?eMdT|Ra7`*PQ{8MH2`XI#m zi{u2GBY((lrDfp8@gWo$L^{xv5RmNK{;eBT54YjTC4!^|2cX;H8A;n(zdARb>~0C= z_owcz_tnXYWe1kHv_@{c=9MtgL@dlf^Vk>E0-p^=Tdxm!%_~0sp%6~X9)xd9g|Bnd z@Ywlv7gF4`D6wgZi9MZo6OEZ4Nh)^S|I;sDrrf*Y4d=vsBQWLSL0f|peimnc^V8E= zYNgOo9yC?#B}BbYba-1YrGr^?SEw-OJiSgnI91KE@#sF2coi3Z>;YKgcH*RJOs2A5 z0*RAOQExTF!cHG|fCcvL1Z^x!x%vIWzPw^FFAmvp`96{X&7KJ`1RdG*WWhN!Z6~AL zAT_fR-E-!TjQ_1g-Lk4>H7x_W-2sTPdme(yLB|wMu^oj2H;I^Z0;h~3F?Xi z`}c#bTo=yoqknS#m3U3Jq}y(F4{H<|iv7sAC50ckg^2^XZ*$KT=l9H@n+p z2WEl~?{H1+pQBCF;dG>!&#h#eudieq2!96{-5<|6SCTEl7)4iT^#LZht8w%d{W)b# zG>D}No{=GB{A~0W*NsNlY(}fC+)Y{BaX$@T{ItO!aWm~Xc@|h^IOQ?-dE9xdv6!2# zs|5r5pB7uOJaj!!ScSLk$@ZIA=&Bv*tP(%{JKe;LrUMC-x-G~j27Ccgi;rIs_;@eB zanje$xM@V4Usp^C+%3Mly#!Ix!@Fkj_ant04S2riC!5$erc~+Xei355djD~crSuWx z@G2FA0Hfry6x_~^jV_rJd;tFt238sjDo6r!PO0g;8DrtNm?ifV^%0qdvA`${Hrsm? zPZzX6=riRMb;LzJK*Ij4gk2r^9qQpIVh3;x=a3C)8ODGo1>A%1f8^fRtoYF&Ox3}v z3d7FY+JO366@BkLpi-|oWDedbfZfHO<}F;vGOu=%z9PpYe*z1G^Y97fBV=g_lKltl z{e4l;eH;AV--!99`k2E8E00RKNVLsv*>BeWJ|k31ztvj4XRU~sT{ycDyD6wP{Jp~E z6EbkM0l-AO%PFu!CEmNR^R~2+!*m z#OuFFs;4TaPguHAJ@RTl5h7CR9k|eL82{vfmp?xT4A}=!fwe$7-_1r_8n1+kUorA? zA>hf3?I*(;U70aUU)$-cTY{w|76&kV0xss6P3#-> zkL``0>rEQy8VlDsnQR7g=|gKHwHrUIn$^XNe4`Z!0dd38d}w%G_Kr*HKqq!<+aba}pY8Wj`oNkUHV z^H>|n7OPH2$PmtNspDP|Jqe_OLK#y6f0RmC5M=f;e5b_R{Vf$+l34|lKjU`zM1vu7 zhXD^_PV%}$$m2td*Ctq=qS-sZdW&3^OKJC9^-epYOEV%AI7{x~;(`>X^IAv1?)XQp z7r2-VGcQm<1M(eo!!%PQh{6**NKG-M_p zz%O{G5%VaaW*gZK zY9mdyl-_m!aqvRX{>w4u>wDL>;CGT|ak~aE)X|V9ugT0)OHMn%hw0wYpj&?nn#@;6 zurB0j=I+XLS;f6IoVn@-<6GFVdv^UFFu>gtcKg~_x0GpxxTD7U^-FH`3J;}TD=tTj z<hE)vod&v{2`a zPDpc1bJjtv)!geiN*R9{U`3s1$t(RN2Y)CEP5tdoN{BRmWP5m|)~Ax~!Cy^z>>b3M zAl0hAQfRCA6F?Sc&O6>0m{T?wiJx3e;7*b3He7aQ`^d2@j13%{DO%jOAb1&w<|2w! z^7D?y$LfA=4P5GGHHIS)1P%h*K=%RVHa{uH$2D_0HUi~uC=R_V3G2-t0T-4_n~tF! z8C>0dC_iatRRPP9G)_5yjXiEQ>eVwaw~Z zX`IU5bxM6;8Dk+WZQY@cDq>m^&b&4T*u|x(ES>zy35j~+GL3FGPGnM)n3%Pw#B=tW zx**nrGL7HaErNKE4S96hb0tP;PBy;NdiinWto9!-rQ#M?QLp`SFBWLsGbC~)e}(M- zQI26|c^8QIVe#x_B+y0F3akWGWC-WT-wA(})18K`UjyeV7Bij!v11ep@=*P^o*(jnY5YSCWD*umhQ5 z?EYHr+z&vz(p@!|df69?xrQ58l*Bk~a+=(sW0Jq*Hh1GV`eX3Nu`LSJ;Y)uX~F#51tY4Ew1-W@x& zqKe^O4D#IeZ*9H1M-O4}{O~;5x&w41f@|<2TQ1LhSVflqza{=?9E>di* zO$B$X&G4Ya`#e#>xs|@#kM%Xt78-bTvGNQnA{(}qHk;w%>}=F4^7LbpOSw-kA_3U^Uv_3=-BsS7dmo$xdj^`rkA<6rn|)bn5*(4m)Q zYnl;R(@U?se<>I163#_tCLBKIreuiZH23fqkiWNqqoq_;qeCNUSN``A;4rDbHy=&P z<1x#UlWht&=utGW`L)Mr7pqPry9p^E zd@>?JQ~5k|!W*3$G*SITE+K4%+$>%r&K&<_0fnLli+FrG_A1^iPI>9c!VnsLRZpO?X)}0YYWHx z7yz(D?z;RIrF+q*2>m>kck>2{H)3Cq=CStiWmXc5s}*5COC$F!P^b1#Z3ak)uv<4* zS8jq0&1Web`;&O{!x#6m11*Lc;(uE|Jo{(X^mn9Fh%P<8rGWMkqob=JL$%7 zyel858t|Def6K&QY+Jnsm*&wkb(gZauM5p5_v$)fVCi`RL{$EHALH;Z=+Y{4Zz^~@ ztB)91iM9cI(vJ~2AQ=&ZJ^*Pfgg97pB^)Fo-GK39S9(--s#dEy2ORxC^BN$G3(L>ZH%0mq&)nWr2 zlH+2wq}1)$cRY)SlpPd|!0k-jrvO9oQmMG?^huXJFV)>-?_D454sSEUQVr8ziZtb} zE_zDJl}+znlmtA8ZN2=|XI^d7?z$YE%K9vIy*9y*n(HS&OpH4NT>M>KZq(+yQG$CGCbqVIx%HPdXlAHg1QW?(u|LZv6-wY{GNy z50yIX#)~_7b;vqfiQdARCXTH##0yJ4P5TImc%u!`ZI*Ph6>VFqXgcr(kT7MS*GRL? zkvcYxtdG4Szl=BReC)C#Plz#7=3d(pq_9fd>(xh3Uqlspe&VmDLw4_3YV^PPPqk7? zRUrM=X~om(i4*_sR1>c6rSDReMwozac-z6y08|+T8rZW=ShC!wCShHcz-^>hR$wLA zA9yw&hslMM`?1nPcvk!dmcn?RP(3byBYJPx|NjmpKMcQ|zNtUUJ^t|Lq#WAlk$?aT zs5sCGUSEl!DtB*(Bid*6s0)rTrbXJ@vVI2BfM&gwH#|kyUWpIzbmkOi#t$d0k<3TI zzT;Qs(njb*0buC`h%bYyV6bSHGqXbqm_lkNn4SZ2 z?>q^y+C5XaIOn}&R2%#p??HYkJsSFn%e7~)#3eEZNkq39s{X!!`J}#*1X1`GGv{bx zO}+cH@Bt%-g?(ezl~lC$cYb+k|F91f9GGjCKwR&^|CaW42(g=4fu>7+lcA=rGc$2v z%#@e0N#kWxya=zTd|ajrV`kNRk-G+Zm(uYFWiy?nc@iGtk+kKNwAeTDH0e(r>kaR1 z8xoc(n_kz+bqV(?_`Y7MA0oBwB%e}J*a7OALL!4#uazZyWf>ZGHh$bz5{@5G1(*MGwE9BTt@U32YX?KWhiGaiTrZ?_} z_h+gB$^^yQzT!F_oYp&*?c%Q{%~l`g7&SA($N@>opKO6827k z#gesBqezNse>Rk36$^Y%1otg_e2za}xc$Adj0*0h0>)1+{pfr>^mIEqWBuc2@$Ru1 zfNk1R^ape*M1KXoKc3m(Jd|r|g1F6f&SAqb(`QEvwtpsD_AmHa(IL!dbw?;f>S1qQ zpAPa7Kt~#wNW|OkDy})lu=znv5q7cneyj7yp2upeTO!TObJA%|fdkCImLdgHdD;#KL$~t$ zqbclt=6w>-DM*8ig!#ln9qg!1I0ctlZH{Zaza81vGu&y~D~`sOkCXJTKaaGwhK9{b zd5YlTfQhW>POdynS12Fo}6vG(wU3}#*p8LfKZhcMzb0mxU;BEiK?ag8LVJ^GW zTg@Kp06>&DeYkOW+#A6$g(53pt0Z^JYE}lK`)0Uf$FI+KB#YSV-rqLA0avZQRch9S zVZt0^x!>5)+7EzA{Ge6HsO-V6uCbMadPwnrRxdX z^`0;Op?Vm<#hAY+Oa2#2>1hiAR*EW0c72pk~p-^$x zcgsSpT!teO`82EEob?a&f15ZUFdkA`vJxl99~*fvrmdXA9f*M#f3SXSw#LerPz?Xd zA2QdnA1NF8)*|&Bgg$fmAzvHT@FlR6;o_FaKT6*T9lkq;PL1B_E&&uZ$%T&?_-0tn zc40Gsz`{wPa>@_|ckhsd`AKHB;o)B3^4%fybOVZ6-{t(PUK~o3$b_A-tG#I zsq=3+%oF_|9zH5dP*WB;0@+6sfsG&3#x2cg-0Nu#qm~yI5m}LZAh$E;?eL6Yu+GZ!#q@fx^+=AN+-sRaM1z$6+#R&6uPcnv)ZiaICr&oSHXTMDL zt-BOmj+@2Hc2b`ASm;@EBtclAX5Z%sujkkV=)u=0^*l(1TcN z``@;DyGWI_`lDd>rPou9n5w?EHd$$qapVMRKu@SR7<)TA74jG_NSA-^gL&58 zQjErN^}g+Cr%q`7>skq_(Six-Psj$k*fK-AG5H3)$xPxa*kOP5#)`jE7V$S44+h5M zH$~yLY16fpgd3r^q^w=Js(DwPd&b_0HtxF%HK^!y3ZvEbGzCgsGG+6TQMDSz4M)lm z`rAuQ4;DfskADb=)PnQ8b*e<&o8xDP z0B!CP78m|W*ek%g!m}IXl;u9pfmQ@a=~;vb2TxszfeG)HyD~N*TbbXiUCa!rjM_ea z1m|iNS<0l2xb-5MT7MHAR_}xN=K{2`vf7It>woFm(c`u_Pqh$$hBknLw^+xK?q%laW+92vPAAm5eHc9(+Oiw=eFEMvXIU=D7@CP^RwW z;}buyeVd9{eCl_lQt+yPvdZ9d-_aWGI6!$}&liNRk?xxgbejG6gk_pbAEyL01;}i8Msr()I zI$F4LY66m*?&aT-5e=e|7<9WxO(;JQBXUvjQw!y{f-$r%n)fs+y8}zyBR=Ve2#de% zQC*ul|Wp_7OQpOB6LMsIv%O?92B5&M&az8^W@nZfr(wwTliE=5sQ>P+ti zLU%`57umu=ym~Wa5T5PALU{B68mgf=N^TVwb&oDGjP*ct*4B95vNQwr-xg9~ytEdE z{&!jtbBceSHls^{3=eanOULkX_Sevw1qeMn7OinjinVpzOP5wEp6$EL)@OB7(lRUC z2|r)%Z;N%bNxZ}9@L$W>^N*I(={tz`EG0r#K`n;VOsLzE8BPK8cRi;~XM2l@rW1N3 z3_0jLL2_IR&3qY`W*5IZz^EEI>{Je{aExN3g`9%h$QwLE+Q|LIcFJ-A>zYW4(ZGs5;<0z1lpGA!W!1d+#Na&Qn2+P}Tjq_cJ|Q!{A6M;n0it!c-0xu580yA8L7AJp_v|gczSiHF3;t>4 zYLuRet8E?Qq=o%DbK%(J8Q^O63Bw%e^@UX6Ps7bmtm!b2`vdGu-M7dieF77sK~i2x z*$)g=+@)uwBpcoLu?N4fQ8nLDeulZ|e%rb6Hx%Xf{<*oh%;@yVSq8iq5e$I*8OUnQ zjZn?&$s&o(2ccZBn)iGGay%X)+(aOtMQ?|1QAt^I!+-kCI5!lwZFC!cD1qRb9-bhKaUko`lIQM2Vd!*ce~!T zjyjS(zf-**eKYBVn6O|u{2hr8E(u#3bEwgXwC#?;DOZ@Wu6E#QRKw#6m)-Cp?`ju! zvrnHk?Cr~610og_hnyVnvNYeno;Kx)B1xO}&TsF{9@idp>3lypqo}D&g#f6D_{qB$ zYPG2^{siit=np!tE87Rh_|B>04o0$JDe`9c)ctyNoz+@vFh-FzapDiH0?kd^XQLT6 zOPF}XF1(+%Ba?SERMcmo^Q>mT4_RLEo}fe0?9txK$CDalrKq)QwQIwCy?6-O8NkG~j53L5VmB!SxKhFr&#E?ixf?+n8j}u z;v_evcC$;@3fW4~-X^I^e|2|c74jx>x{cAiF-{@cjKw^y7QKi9HYM5`gQox5N#cLB zlMjRgPrCm~!DLvnqha>8)IMn|&BA+keZVv>2$)<9zym#_ex{&|?lx8hZ1aU?1Z&3Z zJk$lYH(~s;vl3Wu@p@is{{92a;}6;9`i#?-dt72+swJ;RP{jzND#REJ&x2Vrp{w zscYw=VtQJ+=M#9X9Y0x9wf7Q1#F0%Th;gX+b{Cti$vq5vG9^cdE${s6gwrQT-7KY^ zeTgpFbmbj0Vv|UU>9K0?8I%n*35^;`9N`>tZ)Fb8n9D(#-BB;tHa^eXJ0iQt>g5o; z7MBB6!{AO+al1{W(PRiM<=?TviG4W68Me!x14GFuQ-sGr6jIuO8##wf!t4q%cg}M` zfX)4#dh*Mnz6=~U1Ug=$VPU@TensXj)3WYWLF8-E!mWf)I>?h&Il`(3$gCTEbxLwA zX(&zVI^X51zny|nQ*nd%%69|iK^&oUv~bsb-sTow*u%Z}r`@#QRtQtJl}Bum%wM=x z08raaixwksekk`heYEpsI#xl(X}-i^C|LS?@kZB&=h6~y*Rzqy3B8y}JlJ_aQbx|^ zr^TR73z1e5%<*jtIX_<+`KCCp_k+vkeR%$$aRyew!PPu1E}Or7%C4unoXOtL`6wDc zNhWc}IH9htsp4^1swQr8xb0OZ?uNhD3-@jR&t?@E`wu-LMagU^=pKfqL*GrqXg$5w zbZ?^dQcftagV6eQ0!rCxq7t$>y8p=f4;5GSG6O z0N;F;EAI2LM~qgr8$P{o!al}P#+PB#`CHkT|@Ju&0b^T5AcA0Etkwv4O z_0`nhioL3Xo5wRaViLD1g#N%f#Z@+?h)D_PZz9CT=7|hnyIXA8N>No>d}r`aYmAFm zWl3FAj!Su>YY|P(@B}_SF8e;D#;wW>%!m?+4@)OAeq8nmidjW}t;B4cJX~d`B_F`E zLC_Q(SdSAcs@=$VHqe(Fbg@H_>2Z$f%IIQ8@N7 ze0DU1w&Tk8%F7+o$kdQets^>zbM-kWr-sbEXLWoGROuKQK`;11607%x&mCKM&>Kddn}?5duGNd$^P<%p%Y8VRnm=2iPRk>=h8Zw?>F<+xmite z>;5BgP`3X!mbW|~aF}tP=kTPB(2~>wok8k=^gw^}5-ux{B(*xs4<|1^IeP$oEGQOc z0LcJ~+0>Vjb_kvMR#gIDQVoqSiXfiG5mM&tc_ED`uR$eMYnU-!s~7`mMcu}6s;Y}m zm;}+$UW7g#j?wkDPtG-lSFUs&ZTzCzPu(X0xZpQHkDug-khma3-rK*0IZnq*c;<}2 zoOdCQW-rS>=ZvKPleNRD|F?gv1DK@{0OD6Sr!C)tu|=_znDM-HuTtlt1YFyI;-@lR z_jYZOMwn;?90P^l+`9KMJXowr{`KO1%DqreGzOSQ&)|Tn=Jw-_ekmrSpy0WjTLjYH zMBH)mv3G6)!}s=zq&N8b5ky?1VTW1OykhG7ur@Bt z+`=}2zE0|mZ=NhvtY-K8v_bf^D?C_DM0&&P!ZTxXGUocop)oh!jpoSwK`n$WewgX+ zZ#jOXj51e2Z8&i*zGy;Xv%M%A?+7O~_M|({qpu_C`T8s3P`ldU6ei}@Gc{!jd)Gt{#+fScE;AW9x$p3NYOX_y{E)lc zc+h|%y9=_b5L^knyq%`GN4HtU6$>7Vh^rSgX~0g9m8_az$iA{Qey;$* z)O75aH)>z$f2W(X+oTqYv}w)Eze_HszEkdwX%2Jz|Ir*u41&75ZMp0UyG%X^^J;UY z0b|6B%nGtXD)+)pFM#yI)gVF$ct$N4Q?PN zHqil7P*?l)4{~~R%stJW_n^ThxNdxt_pP-8ztifhfdMcBXN|WogHPCe#Z*%al(t{8 zXK_4Q*3$=%+CYN_G~z5+!1}8xuK|^_4rkP`vM&&03&fFMe}yv;;nI{N$LSbsy&1al zWk+7}8}f=CDO#Qe(dzmAhev>=<5P(Q>$Z|r4usMY@?84o=V^%UcUi$HZ(#*479C3^DO?qypTKiN5J@7V0nwm@FFH|4~w z=^L25@&hAp;7W2;#0Z@j!cTXPk;PjP3chM_6;(zF_c&^qXR3P3_#E>ZJ?qb;v88nL?8ItuUK?^=w|Bwmsh#=oS*WppQN;;*4^FFN%Qgd+?~|A@ z8K7vSIEh-I{n5#tj~j|ZXfmGjD>-Hhg;>X`g{4&2Qy!rf*s=SruSuOOm{r7cc6?brAPHaL!zcyy95VTrGxg1B(g5-mX`l|HI{ZawB0p)iSVrbqJ`TrLwqaQ!Lq zsAE0@HRQefR&9V0ypVu|1T`OyJgYxlhN&m*&~N`X@k|qbTfB$s)<@!h4Ydl~x)sdx zFkF$x(|?tLi}2t84zn(`9-~Ix;>5Y8*IL9HnYYci>5pxA38i^z3v2<7tx>bY$2WQ%W{Nw@)T7`kBC0Ae+#W;S~I!G z6zDQ|isPC5Vj{{nP=L`fC3*PB^*lo?Rcg74P;iKpja#}rfu@nVNOk=E#!!>TU>DP@ zqD%gh+hW7Pj{Kn$z7lYZUf=*wkKuB!Mn8% z6|gFk!4d)JN@nN1j&+sS?wdNk@x|ldN6RT6%B_jGDvC;mkILX4hDxj=w3*xq8TAuV zlMH|5F4+|!JNgixD(*la%YW2K{Z+^WgSbc9+{#k}HjQetCuLV7GK=KOIs)V-8|sb% z44 zVrvU|qVwK08PpMuO#}yyQ+hKU%5SI04K%Uwk`B6E`pS19^0(*=r|z2D|NCBh4?tEg z=57PixO?vB=MC<@K%4^kJpHrdWBG)(jzHiMykn3b1^{be&J~QALcCBdQu8Z|U>gWI z%?*Z|D7%595`^6#u%&7LV}20&1CtrLID(03@w~W+o^kU-EXGi?5+gd^B0KN`4fQ%n zc_%F>BVIAXpv#Y%Dc36*Lon6S*o-H4#)`^VQwCIVIlF@B(zgS8Gvlr93- zy}}yq!t73)J#*hk5vJUgCjHQ>4c@`4b^^?(7&{iv-&H039WdzVWv&&mko8kTxM?a*Gu63m&bpL7;TM_NC1Pm$*r8iYP4@+$&%9N2*}e@ zN)SyxZXerzYX)9vO$^n9aMg7RF>j3F%n8IN&7!)dp_gR^v|;ky^> z+wo9OpAq5w-}D=amR7riWuU39UcbMAk-0+Sl%bOcY6-BBWIR$W>IHqz*jOR6#HFz( zQC-eZQN#{Hzjgkh8c3QtWLz`GIPjYsb;;y&41y3qX*#Z9IkphOwu|+jSeQMqFVgsG z8u{uEK+1z)YF;maXQ+P?8d8b&aD~WoGe$w}5+L<;kVPgzQ(*Tf(JL-u8!nTz{&mW8 zx#7|UPKpmYImH2s(cJaF^7e{0?5VkvSqvSi%^g5y0Yy-q@i93GK1S_gL}is>YvJkU zh*dmIu!AArr*emL9%JrmN~Q!U;DvPK26Gju#>EHj@8NNYZAv9;!jXBC^)dxFznNhW z%&QnZVgr|da-ya4tbWemVf)~tIAyK#|)YzqL(`aCRMQAl=nXY?Nd9` zd&^~T67PXU@Tfx|;w_>;l5LVp#U;w4@MY3wX;nJA9k!F*hQjBpW-R&Q=aiqDI&i}B zhSt@SYoIG$d1uWKzl!Od*Xgx0bdr4U7;|BZ8zLq6lZ@3jpNKI9vpbfZRXVdOS6i_dYMaml*YxQS7_$9lf*4|_@}{BX2I|nM z5LIrEYZlSnk$GR1TjzeO1r1`*$swl0*|26a>rLF6_q81kUX>Wj%X9lM%x!hJVGh?m z(Z3Ftn%U`1;M+#{(Yx?h-=F^qQlAH$;Vx)ts^_I&{ZISU9$*wycKWnW>FnTdkbW|CoecjH6z*5EWE z95$3wOf_2;y8M&OjH{BY^{DCkoIsFg_?F*Tqs4G)FtLMCi!)pj4jq9>KW9qiXwllA?(_3Y z;+;2PcyKh6we}fu-eZ3GMrSUTh_Fo`TbnIet=R(CpU%3bnxT{RB%)nOlMKtkBZu_l(lUcmU)bb7%ZcRNCG@+GJgkFRdLm^D=Br1`*8LQ#88W^<3|5S;~tt*_gg zarGcYb{lG0Q5<|%x<_}j0C%(WXeH60m;)Eb5>^7cx^4~=JQ}%2Kbzo76J1xPT z6m|jJq@lGMzj|``OsCC%MWpH?^5zRabK^W_y5cPAKc@X;73~7rTW19{w*jp5mafjl z3e$cw5z%cBid(zvJog|!q# zwjsCM75h>m(13Q>Ft>zn>e_>034xI_QR6bKUy+Zx?XkG>Tzgwqwq0mC^yj76!4o42 zwev^EKN2xfL1VwsAXNN~k@Q=2Dr*`a!J`KEFvATe61h*Hs{z?6m_sf>d;*0&1e|_RO*w)oa*rW`Rx%nVc;G$mKHjAa`KksR9IEU{FRd47c0>Ia*jD4PrJB(R3C% zsAw^;M{AB&;J%V!HU03BwiwR(7BtK%sW$^=doGTHY>hwNbnP|9?l2m*Qo1b&tlr*J3=CiBW1b;}^U<>n29P zXk(P^)HTRospSD0LO}cAcimcVG*)IH0 zq!v|1vv)-KHL3@0*3k)*rdDoBINW<1_&qEP5a64*o2n@Q$Qzu=NtOZ(@I+MVN`z&Pk0Z~W2>J|8TFzMhBR5z{04gA{Avoou$zxW0~Ddx~Yn*eO76mMjpxr1vYC>T?FSl>C z?jM6x-+IGM2PrH=^w=f3X8!tqzeXLvmcz_!?sC+Y;a)dvaWvXsfc&N~9UT{T3gdy8 z{Y&mZRuV2V1F?_Nz}khVQYm|sQnYNJUbk-{i^)CE&YxVDA2tb2-83-n+jM~kgij_P znCNXH@veVfP#?X2@Z~~SG%4omRD`bp1*#3Eh(?C^iBPMjk5ZHv+-LTcU^yd3TRnYT zNR;$ESzJw3U%OnI%JH_4vw9G|M)L_={G3k7T-0NjC>E>&cYm#Y0=j-qtlN4qkFFxL z&Cacd4o2vIk3#IAL`H|CgrJ-bi5g0P)-SGIc8CXem~%$hq2Qh~M+ZQd&tlc)bnFMO zQNETzcB2Au5SdhZ_F;rwV{^oz*$n-&XrM(F%MHJ1M_OLX<;=P6op9|7^Amh8C6x22 zpgkkUNQo$I#CKwwzDqHQQso_u%DF}V;dF`r2>DpMFeWJQQ?jG(=j z>N64}-9e%#Ohtoyf{&o~`-4vqJ`Eac&@}05ly-b{7$mw^&c{b2>gPZv|CE*e9DtJy zWO{S+a(CGu!~{sAVnH8`7d8{<>q+=`C4$Qh!Jh@~MtNpuH%RDt(#(UQI#a(h&!hi) z0?L>Jvt{XAA^*Ft5nW(E9)AOYO5Ea2W^35Kzm>VUi=LLA+@KwWkeYpoRRi@US z-5{|k7EuY9=oTw5n>5{vX>7AHRGQ4DlkvMcD<@b#ECHGS3QnQgqJMd3W zL=}I1wZ*+jx=Fx%ZsM=IvQNO0Z>KoQlP2A^a;Jf+TVHWd$EwPD>gkIup}YL>Sz=7* z>sitUq?b=LQ039$?x_2-J@5EdbtlP>bWk32^5-u1;#tk9L(HWudbI|Nd%=ry^~wqs z4FLcD+0=VE5E$vkQ{$w=`>n_!@W#RAiHYGKXXYonCaOa(Y?N$lp$d5EbkG55pOH@^ zR@mp{t3+2HpJr|?h$kO~<==e5m0+jhT$PEgH$w4O;+{Al_dXY*y4gJpF9rJA&KGgo zS36f=dPSs>`BYVvw&X)IY})3a-F5ZtV_imRQJgSgqZz;0_E{WVD-}lwxN^}!glM%T zd&x>HO}XB!c6iRunM04%OIvpOQU9*Cj<0lxZ5E|pYc}9G+?IX`zHrdd34z!d1XjII2m|{M;KdR{ zLc&+{pCiZeeT&ubR1bIXYoRiTqBCH}a zLE`cRZe+6#9+|Fn-8N6xUSe`p06#(u@6;Tg!q^B1a5PZCkkNHpZI0W^iqH+~C1H>5 zfob!Lzk($KR!`s2LfwugDTtP5*RIG1n1hff+v*RY-X==3-%aYKfF08iPkHan{nYuAmEGcJ9| zc5?ocp1bh|+Vj5a4h`3fFR@19Wy?PdDtVKEzQ(dj<8J{&;cXkfFJNhK6YfP|(VLC$ z+Xo;taO7)GJunUt#Farq4qMJ^dP7m4JZJJl#ua}up9?N6f(vZGUa#&bzv>l1y4bb< zJ!upAzLk^BqG_+3Gy=2GB6n{-f`R-(Vd7R3Qv5wvqctRXM4?2RCDDAkmqB_#$-0p{ z_u)C^X7=is=>az$f!0d2JHqkfZ&ASYeLWJ?So8HhGka+oT-JqSX7_S$1e&#A@_%sX^%5TB>z_joum2> zY`0Ajq+jg%`QV6?z5UR0$j!{K6DEXG#tLPZx+8bA_SUlIR*liidirktwcRbq7u2{V z2T@YYbD#)0K#24q3*(U|7)?DuNR_yIns@HQW7~i+vrcw|0= z)onA1 zPcWTbVt;V98utP#@{i=AdkzzBciv4Pihy63 zF@4?!vdq*^LI|}yO&e&lxygDw-4N|7;kds%spd6RmJjL1WOf9}!b%<%Hf!|rbek77 z1Azw9rv4Kq%^oo0NbEt|FLmqN66vUz&>>Q`&Bg z;Rx~3$@70qcwG3}?MX)Yotz`T0#R$QC#ymTi$XU|hM$($vy)Z{A1;$o3&GAH!p?L* zPFMG59T~5lzS1ntou-={S5f538%p z)niL&q=wTwyRn~5t5KMefm^%R{eP`*dH<@3T$%A!7~7zR-;{R70lZm3;6_2vjmZ@Q zw!V?^YiH7UK+MR-ZmzT1tt-H|6m&r95RSgc{*qXKa-V!wN`bw?| zrS#1-nBhDE5SvmU9u`JGpn}67_BkfvfHAB9Fhtl5jFtmo6GpZU#)tY5eWQ0Q4W*;8 ztVFL#!K0z9Sq(r#=csor^OuViUqKx*`L^jrfYB^e9PQWNcUm4`<7?U&E5#Va#h?|P z3r+cHT|h_-@!oU%gTH|}lt7g`y zHjrB={gUN@}JQ^92&~}_RH;s z(umlVLOKNX!;T?n8=QiJ7`-08e1j{fVqQ#)iD3FUE0DSiebsS~<{j`0mrpj^p~{62 zx*pEf1z9B@>Pyk~jkkvKBCrZlqL#gyn2HOtTX8T74zCjMYSWg+jwU z?o;xoRNJy|>PuL!VrKto@3Y3+#nNCv%GHNNI_K0^1y?@QrZkk~ErkGn6%?H6?1peO zbSgG3w(T|3+c~8k#VUM>t2+2lwP`C1nOsL}(|cxjZ(dqM#1)a?GJrFel`52=r<`6E zg{HmGwEA8-{v1aohNl^Z;0yzZqju4!qN^QE>A`k|2 z%^w+oCjva`&!A{-{DjUb6f*5VZNhl{KKHH-h%x%u;j=d8*<&Bfhl>yH*`;aFc#hY% zoFDCd9aHNBiY0Yevyos{2TCaLbOAXNX#Y>&UM?O#hS(~Mxl$HPMGszK&820cb#Q2H z)f+0p!OJ!e!n%$RkYc%KP;tbzNTl%W@}9{t_v0L#?T?q1fvJE|h1fhV1KU$}a+pHa zKrZz4_fO`}jd)|w=FYXIn%_*-VY=(Z5vm|5@WaL|tkfnk*xN&MSBDS1dUlj_e()5| z%SUV61eNz>44lC}APQs)2M<2@H{_jbUE0T>+VvZmD_ECP;Kh=gJs==7BUtz6{-wl1 zvJN;P?~}Q7|C@v+l%atq6CIZjp+>~RD;ID}u+vA=Up0Jo^LW;AdBW>v_>DF>vUEmq z@4ISa27crz4+q*Y7*f$6Vcnr=5ygk!fI!6Q0o+cFL4OUp&N5jLeb99!8vG}>EX4}@ zV8c~{u>au{j4LhkHTWOIV9drp_{}>e_>> zvilc;BpaU!AwaPMbn$s381 zN=fGbR)IX~`@b7#hVMZ2laQ!4&rL)-z=wdLx(6_kJ*VRyV{a8}kY}KXbdYU0hr5qJ zeYN^|7Y*dO_|5|Qv1$yZlzRzv$H!l-rR20GX#Weil+C9f=8WW&sWbq}35kz%?SaD! zUW=US57}GX*02hs;VDM|jHiQCrfe^S*-bt%+JQivsy0#uo>7i#rhcBk27HAe!RZ;k<>hLI(zgf2i(ia*r@Kw(XS48uPvD$ad zm5Nj)Cw{gMjaZ9w4p85sU+7;|Y6xKozm@q+%071sXgMr>@?4SSa55X*4Xaba(8+om z@Z6WY=N~7y28o36<1Cuwa%}nDSq{q@Z@nlPrpI!*Z^JBVU4pv8UEg{1PUI_3ptN1J1`d0gn9N=;b#6hCxh z>{*xCC?2V^>Is1XpMAjg>4cCWvK<|bA+GR{U+|e;VJDZq;`QJ*P%0iLzZet7@>$$| zg79@B#CFp)8p%sV_Wjh;PTl1f(VY?LP4VF8SOQ?{y)tI$T$$Zm#+B)n<39%9kkRC; zf?5V>I}F6unDh^pJ+7pqLnIX1GAa8QG$!Z;5DrYhsCO<{#bwooF&TF*F~PN^RYnz2 zt_VO5XaMic^c;bJJ!F;agO}!HMlF{x8AD5-`zoL7XV}Pe{yYagQ*wpBg4K&Z(6{xa zezn1YXB#n+(;EdRQ~mfm1$T8WS8CtuB8Z-YU~tvQp3I|3^V;8{_Birw0N3Hht%h)u zVIrm*q)Bd?{dx^%oI?KZK5YU&xBdT|^Z!EV4!&?E3{mG6%wXJ!*RSp~kA3G1S$$`L zWb#sna@Un^Rz`z;lb3%HdIi>{&y8!bvrDG27ACsccRgKma{TGK3X)D?jFH!)0#6tnhBO%d70ddGxaI4N~oo zeb{XKe7$*0?AkgJ59gYuuOzRB6uAXSpA=<&j;_g5ZW}`kH49XQ%2=rR3lR4|Y6VHn zYU^EP-5*IPlshs$7q(VGv4!6y9Vy|sD2TWpEh_}A?=0~H~-D+gr zXPKp}AC)FOIq8P(#1*WU2a2mMNvxvAw4U@>W^ws{rR3^w3ED%J@vplG-7zM6FDmm4 zyHYmeR6OD*EAPBrC-IBorkNGE1#^=y*IYc^7lTsw!3K)b!f6vN(&j^hlHg5)Zf8D6 zHT1oy@|b)vFWdWEE>9$DZc7cJ9%dFIrx(e564_8rJ(mhXcn0rCX|$+s%roCK_){Bo zAScaC!qs8r88nYrn{rKaaX>hVH^*hsndtS>IuBJ&!`z%MK#(|b+;(G@{qb~3&tW~r z04Z_$kLoKi2o!z!cXSrOXW%E(?hM@r#z7nv{0$QePDLfUWlP;W;a=|8If=&)kj-#KUr>F4IW3ad;^D6i1TFjyzCmb#k#HvA4 zepn3!<$d*xlBhe7cJj2R*++kfgC`hk-G@F_Kl!~QohxdKM!u8N9vb-aB@OW@9&Q<)cmQLMDfj<3_I-Am7>399(=BBTGE@DdheXjB-XwjD95 zjj-qC(rlt)j7~j0h0GYA6LnfDbvgZA5(vT3KZo#)5`K3+N#H2XTjuI)bPwfzUrtV` z@PU<=7guwyo@>T2S#O{oSD{s4=~8|wlPHDIp0Ja7syE(veP79~ucMFlGxgGiSVeRF zArAp7%w+L!^0TCcrHJMPOc4tAqbD4AUXd82U9IqrpEDw>H1O>L9>1 zzB@h8#y~vUL3^!LhxW@o&YEW;?CECK_W#|b|JeVVb4?9()5&}UB-3(jE8pPombsEG zE&^VB`)?>6h;{qHrk1*6oe3=qk!uqD*I)>ihm?Ji%0y7mU1aM`UC}$4?XT9yIH+0p ze_|3SK_w4K0=!V4Yp4f-eAA}iBp#gQZu}1@a^F5n_-O6NTzF7gL~M4O{op&& zy&CgXIj%!3?JV;hYe<$+x+PYDwKx)hz$DscbCh(NZ^^7CCvq6mkV{M7+47;v@|_l1 zV*-9AD}=L`EZ9w9UW{$^6BaeIvwM($x)YEVaP_gT9wtqGD#pPW(SNFsxx9NL!o-}u zZv8x5Epworx!bsfq|ISa;tAX3OdsJw(@j2)ij0{bIGr0{+1oty*79WuFKFuPN7rCVTl_=DQgL zxuj*_frN~=3-aJd{GW)WB-6-bv|k~4BOaO}DiHSX~ zN_my%^xQA|;)pZPN6J~MTRdp<^92CzcM%`(baxi@+WpP_CZqA0Vrw1wtd;L2-ydG> zB5wwB`Z)=~V&>lE3&?~kYfSe_mkaY2)5klWy}Hh;i8Ix@YkDh#byYvhkYHR$yI^UP z`i_$J)RuBlapQ-(1@*}8u0c$)mIKy52sAkw(3|9RAe?J{kECEA7zL|H6j;UMPZtj9 zJuKPDFklu$8)4UhGPYd3Y1XvTQ2PI)>#L)pUc0D&2!aTLq9Bcu(hbs`Lr8ZB0@6zN zV4)z*P?9QLqewGIsKk(xN=tXQF!Mcg-|wIA{qDP#cX?U&4_$Z8oM-QS_Spv{5CQuR z&xWM*(=~SDhqyF1V7EL!0OB$_Srew%_d~`>8Wq!~)dcr0inT>IUEB%-ME%L-HXF?!+xPIr_bhvm5DbS?(VUd^%OW>Mh0A zk;}L!k#>~VP8muoU`n({;xexkFxIe+agr1`-`6J~R*?KFl-Vgj5jXh$zL_x-hJqOQ zyG*#Wx&#f3P1HIN!-+3hy7(^)G0e=GC9Zt$zeVt?JKuF6W^q<<^^!|HrkZ_m#5P-x z2(%m>*L0v8H)eitbr{S*=9bJ~y$hy@m#6p&9whZo55Ed+-uXOK>7vYa9*cS(Q*r?^ zBkXz9e^XQSY8$G*)Z~7m@sA43yPAsuXCZGbfi*qyQVsm)fnc?v>SnAl)3Vjc^<~(y zRfPt>gl7!vkNi)jrID{mr+gxw(jW+MQOV<2B?Jc09t0PbaMGA*W&X2iu#CNPk9FR1 zY*$1g=^|@bRf&uQ>z=;7j(%yA=gGE=hD%l`Z--pQ@FFod2WI_}lj-8s0zJv;*g(kI zjWf;EyuU+rKHQkZ(-A!1Bsph@8mu>f2#&7|dl6bJi(C3HQ$kqSz-+B1GFKWEP^WM& zZ|R6s>+qm5d+F6#j)L*7svhO*NwJMOte=U|Zj0>W`c{$Snjdu@>O zCA{Inh0K6?;sQb6Bq$&?kMq9`51#Ix;>r`)Tez-40A6;PbVbhs7MfeuBK@9MZ=ev`ZLE5q3uif@z z2m}6LX=Vq}Kr{(*t?>GUMlmN*+x0&faGRloLtg^KA?_#~NB#(+^J*GWEI**7!i93A zU~>5ITXGqpOD~oT>^Y}dLs>pNejGpj?ib4^oV#Uqd*wZ^sVl}@|A+)gQSaGCfW^5u zdocW7a!K;^1%MlM$^cti>CScQzlSX+_X$-2OftX@?LotY;f4FtcivMai@vduz{OM7 z#e3Hg|HwVoD|t|7E&9h{@DBX4+^)5LAQz8;jwqrA^vs*u8lsx5x{h~}ZW6MZ(kiYa zJDjf;o@hD7H*WY8|jOBDT5l|k6_lk=8(2dqMF+mv3>^@b-2ajJLm{{+HCN;@e7TM^{UQ zy@@rvKz!g?54E_U=lD%z`d$f^0P=-Rj;8*@%r|WDTfiNybDQ$AK@4{NoJm+(>6YHf z$s=u+IacOa`)kavU%W9iR&~CcNM9L$3r5!da6=$A);{TB)CYP=pOsv2N9)5qbI0mV zP0o*=2QgpwLah6Pz99S8zHT-3%l@S=FCejYJNo^1`nYMUy25t~7SfEQBv82i-@lp- z3wozQ&ksGRdO31JKP2Vp_7^Uy6%BgAAPSq~*I=`s7W-YW?K=4jKxR7TcmDD7tEI%%*h#Cs8 z&mhh#i!ZHuP1Br1@kX`hX(0BCXXzt;?Zsm3hjY~G zyVRv=d7Z-O8l*^y#!k@nN)#;Ikb%;Ki#K|AY-&l}R51*ZnXVAKjV zFS+T@bi9^eh>H+HVmv!=hokkaXM{9h`Ze5TT^LidG}e{W@6FLv7K`uBY$TK?eqMJR z#UCXvL%1cZroO4sTo^Qez?t%R?PH)5g>UKy9hgI(Mn<6RX_Xrfn(BUvOXhD`t-#+o zwEdQRt+`LcQXW~3=dfORe&@<_ZY636_xpeSn!T;-YE*@gjFUY@4+T#r4emZm?&wy` zZtt_SG8*sr%Ii5La4|#Cyw~8|aam(uJM^A=(lq%7Heh0wjgx^beOz(}bIwK-K?djg zDczHKjQXBcmFKkS%$eT<*}l>%_ux}^;k=M3oa1(v5?JoL?X1_{ATMVLIoQRZhm%6hLb$IXO(O7Ue9$zAUKp5_d zIq`pgoQUBTdewZ9OXG8UN_`Ck2J+L$2aD!OADnmLJNz9WB7J$VE8SLx5XJjOmwjoz z0#mCE89vQi9-BjbiMe{jP0QP3_$`CJx^kOGHwkCZDCQpt%hB1 zu^FoOoAHkcneMU|UA$O=MYv71F_xrTk@8Tkzt~)BM?3!4gS8KpuiQE<5Gz$Y>H)NC zpVfnghfbH6QnBLr@+yzEeNRmY`Hztg^spItkosTF38}8rN4C?C!<>!S^}b>rJr)sk zcO^@n(3NoJF3l(h!C)=J*!+W;V8~?zyM*^^_}8M+7mIe2R>cIpl;RQNFO*7eUJ=-I z$$ocT)G*ut&G&gsB41wP(D+@TxL-x`tgqNeP`~uC2h5_64R;qNMz1ge}<#%--GPq0IO<@Xk_MrQeREz3Vt9oD(7uI&J!xy zzG7eOSa*IOwk_!Ld8(UQ3=_>plDZ zHjGKCRdC(A3k#~fxWOBJ_``Q^6gUc{_|#=m_L>lb*lsZEwVs?Iv)TAOsJ<9+icUI)2GgbDT`jSe0XQGI{auXvM zuyeD^`vS26=_hF^ql6N8Pt{*>(k13KaK4q2i2h~2rr}Y_Ksvi7cYt4i3;1J{9f=0) zgIJxnFGsp^s~i~UU@rQ<@&-dl$+ExGp$kO9(63l#M*fTAHMl1PPP$MXqO^8aR_!}a zjejE}fIwIL-fz^zhlrj$K~G!`IE4Rz za$&=Eu1oVs_{WoknrYcbA@!G4-jGKKG2XX^p%K?UdvO*eP`vDxxt#gu|v5J*`R!NJ9I8YZ_Ans$MHhb6fr{152pUv7M zrS))`7*}kwQDAA|pZfcMOYg*J#|AsZF}3y~J5@W*LLvBakB!&t7K*rKtBI+2?r;RY zQad;{rhBpc-PuCFBBh*mGyf`=L)TJ6uf`AKQv((E{Iq4?@yRKv*K!M`CNrm)ll7Uj zGx#bH9FCexIAKMFik~vQ*IWMLJ~d9c+9%*iFTjW=OXQf|4cv0rvO*HcaY9fyq@k=} z_-!06@8#Xq*|0s8>eV|%Wt0LtV)z@PvYn1FD$GQ0sZhv#{4ma>hN^=rqef@ueX*&! z7dHC9gv#IEd8^`Jzy2+_BRz-*3+Q#FhQjKLGM|je1g9@02I+Q7npmetlQyxJEu3)i zW>(@sCYAY3=b~fXtKDe5#HRIKTuq=>t_%h&YAjWkK4S_3bG$|&s zLS2K+T}xN7MwiFC9y*ZZOB|_LYph5%B(UZ--7e$v26*s0#2OZHOdmhmJc{2^ zYi{k5gm-tfnI`_x-a}fhfOCXypf5T%X_Suw9oOvKei zCK9IP4@AGA+$|9%Iyyd|3p4`{x4ic}EBUz>wObB&j3W?n&$WKM67j1!%E-Ew8M3AO z4<>9)zDo-I|JYDrhkLH}=IF&%b57=TwVGtWYJB$eezu4b#UrJelv?(s!7<}q^SLqb z79Fn_xGj`|7MS6+Ik=#CtNE<&IP*aw&xmA`Lm%Hz!G88W465}$QM&2NYZ0nHjzlnA zR(dU0{rqdm$1=%*mYidm5D|yn%!7*pHC;0ln@qZFYJgP(sJOb_%jAs1ugEe_=D_Qe zK?zNZ1w>lJ3oCr65WQGNUuudl*^J{~tR8RezL2p#0|%=gaACLuLg5*|*rDPZD#dy? zQ#}n*5LQyBOy4cc+%Guv%!#sEiv-80m6uL3rECy(6G!U;i~cV6?r7WhA`ZOP`ULR9 zIX$`27==5yr3cbBEw7j*eCIF4`2 z9E|KE8g-*Q7i5@!g{cP3&KZoR*34f&8S5EE6h`+@XY8pmna>iRp*5EZQHDjG$J~vL zk7YRPo5R{9s)dcpiNbYzq|gIT1h_T4FFo$ZBQv;KN%`^CIbrJ32$4Ju@$=WQG{JRM zAD-i@tA*s3wOQ>a+qH0GWUf*+Aml&v7JsfBWHv5!<$KtVMBBer!?)R$(7j5SU{TY@ zq3nE@#i6^K^EbK_*_kw(gi5G{#c;}#uj__V;5bWb9XR0mZ*9`|=}3(3l*s;X-;AL) zo|Y^zfB)mAzgwn3D-o+$>zcC#00CJC>OIh^2G|Uu*>`f7(6$^54$6hedQa~sDjD4m z#Yhp~Gg|cuE$HK*NCAdcA$tb6k&UDJ@mR5 zg`c-dkj73KLFhe7{`aEigHB7P_-$#_Nx98{ihsZ$51};krVnO?foqvI5+$7;YaqTU z0B7Xr|)7K#D?-jqLUJhVSL@i@X}46Kh;Fqb!&oGar^s-8Sswdmx_jZA}Im zS8CyRaE~ZJ(GIHwnmebaA-E4xvk5}mOu6MuQ;PCYSIb8nS$LkkAsX))UTUxI8y={Q z^W||G&`wYs>Hp4H8iZY#OU7fqy!+1U6rN3He&U=}@a)s$;nR@-yEL+0n&~@z62c}6 zztJ(?Tw6bxsQzKt9U!RUU$A7D)wy3=gDVGieo4;r??qm-mG8X4eky&MDEvv#7$YUd zFmw^I_?O*xB!Rw#oa21e#-B&#do3W#ygzi=j0MFPg(?g@rtUsX^syCpplkX0#U@8< zM(1L^&!JSe0={$}H7#6H+q<0HP|{w&aNF>;@5tGh;hcyAzEbgDq*23+kW*?2rj(v1 z25!6fl(@d`o(Yl8SNEO4*;d`*00xQRR+3PQ>A9!|Dk4L`9n0Y9_t-Gy#Ru}d)@S?` zd1r9*Z}kuH3-2dX>HUX-wB``Bw_xHTl`yQAh~>x{FO9F~3R4&BzcbUr3V-P&r7+ff z?ySZo{42-)&*Tp#ogC~IfFa;aAvw%Uu1k#&+GAYl1qi1riX@dm)@QBzPpa%k_dK=d zn+=?Fks7D^TtevX+pk%dCp?%mRk|KkQN+^^9ivr>%+g$|%_i7je5eRXpoiy(UnjLqY>S{= zA>Mc@2&F|e4I`5XKc2%cpXGs){RN@Ua*C}!@RbK}oy7lnpb|)-qH?kQYKm9Aen(DE zS^0(uLE4c@0+GBmr!g(cWPD*T#G&6|6awpQh^63qxG<`$SsN584S15kV&URd|5Vx( zR*gTR$nN9__WKNNwLJ=|@uC?rHf8U=ib?;xL>};sn0s9#5PF0^V5eX6%!}h*o2szM zriO%Bmtui{X__{J7ouytH7DBh2fN`q-mFr({1yBP7IP=bERRFMV-J5rA^X41X<4 z?wsNoA7o2_e#+fQwg*{Wyv6`XAjNIso*KRi$U6~vm|aP6BIscG#Z!QtgAYF6n#;(J zf@|u0*?nkfD}^io$Ed3KoF_qp?s_HRj;0-;nZjq+p`heM9eC@%+w1rYuW}~rq7)EbUCB;g1DZSU&Wjp?J8o;xp4n{fX`orVe`4TUpa`2 zuF>m0enaco$>tpRad6{h60;K^%2BV)550GUAA+Wz)|cUDX<92GIGL~fck6X*yx&<) zXa>?S&I~_DD3oN7C65vRU z$N+>m065SK&B{R0U$={Fc=Je}zw{_J!deiO%(!6*%%TB;dd~BR5z300PiLWkdkgf3 z=D+z_g4Mpn2M7Tvw1k)Io*2FES6AUPp&3aaR!YV$t|%eZ4BaFmfy1xU<0#WF~J$UbVB>ElA6AAAi=GNo`(|ye@K0+{P%I z#mnLPND#YMn2xE(e%q~#?Bn@4YQD`JvVX8`bd&(}-|{C8Ss-bXFHsKSCl6vNWG!nY zWX=}22Y01E?FICY4;eEwFLb6O4LOV&+*jk-sY*m6U$giA3fj-9)xKEQS$%f@v}S{# zNTod-N6;;~$E@l$c0lL#BZCKYXIeS<>LVj_62gK!?gG#&XZq+$cUrF`S2v%q?O7hxRnMu(`48AD#7S z6cQ-D8zek)nWZn7(4+MQQQ%^LEaJI=gHNa-ksMK&)WfOC#)#KsaCC@MUYY`Xcgm|5 zW(9UVJ)zD7=}YCj@(fP^PDuNU6LEpSkUyAeB1FBPCE@@uN_}@uNMEfoxU(>)7R#yT z&JchFZMYZzNxB=9X|tH0zm#gaUo-LgaR%#lgMw97%DuwfWk5uiRjbk?XQ%58*l#1F zUy<#bpzMlTb+-dOF^TxmieF@y9@lVrdq*cHq_`Lpf7ee6dJ(&4jvZ~l-na%$si^6C#Bcb zb!p@%-_oqwv8XwF9;tJ||cpjH&OA zs~}NY{blMqqxd3Pa4&Q0<9{H8t>M3eiRaiPd)j=qmT0^syt<`0__kT_*?1SW&I8>Z zIaC7#&vT%fN@32#*>}xqC46TZbZEB~f!RZBokVv_k=jYUya64@gvnUh}Pq*%5Z9kbMWmkU=d$x3CjyC+_E0*j3P zE;Z?=^!k_XSZM~_7Slu_SLHZbn;6IkMF;6p7`3lyq|EmgF?)}mE5z!`jV>m+)ql{m z(MA7GEE7GhcqkdKo5mS(kCMGNx3%Gh5NlT;==Ei?O`2xjQtLSq{Sp$Gvz&&5N=6Zp z2n$;m6EW`V0A%A8$o&rcy_S?KWk>JXRlwhEvT!y3vTwre<2ZGIU-9L?XoLM8h@oQn z4Ps?*C4;d^8$Y}l>v|2MBoB}JU7Fam>8khkXlN$~`(bzD1tRvX`AJIHejx?;`Z;f> zua@!UO6LM`pAy>(_FNsI>ru=<;=~m3Xvp8N@p@JnC7jE(=UE0?ao+>&_a^_Y=d;^q zV{@V_lrlkYf9Tc+?RHb}QX;|*({g9Ff=`Ng9#M8~l8PV+A{(r7xJe&D14m@Ve>g`* z@rtP(E}V-Cq?>!Fo9JeS?*wU*w=n!xG+x6zBZgH>yen4_QN^hCbv4b15FR!&#cG&+ z?0?b?$rpgtwCvmTN~H&;@2{c2j9EIa$|MehSY>t~4-d*7-9xh-NT{t*6MC3i>kOHY zmr3j3s~h{Ue|Fc%mXnCsvNQeGLWAqN_N@OZFXw_Gfy&AB33|b)=`t zgatDAS@~5^_N@W#nW{{eA2=*#8&=KjpPCBz>j+$(K z{-4Ty@M4pMlT|T%^`zF-ah;k1%Rr%B34Mq?`p>-bK`p-@Q>-xI==i{St z{Ti5~#d)WoQL^!Fz+PNfBanzGRhG686l@$#fTB{cs3k7qAVi{;)LpdTcQKQNP*I0mD2u)u`YDq&q*VER z#cVa=FnFpt6$3O6O>$7k)iKdrfu)s)0KNoj|DOENII9~7nS-6@ZY-?ES`Z2#mtW`f zKG+z0Zhb-i>#F?z7$%Qsq3&@xrnYav7Ou0DpwVJrP1))6Az(fVV4XLbksa zuaMvIcvemHteiKwuBwLZE_O#ErZDSeL*8`aQm_L&BOngc~WXT>Dl*VUI0wOzCEpSCQ-hzHUT6$RBMf7dZv z<5&)N?kjLe3J2I#yMp_aKVkG_Zen8>4F9aRY+7Mh*Ac8w8xSjmmu2{GP+zp?lyu0& zf^$8X1w~Sa?RN3{NuY*V4(|);;h_Yx@^AG_9dBib!sEXMjb^i_s9HG5P?G?zYMXb3 zknjh5BD&NgWDRgSoJPC0RuO#U!YnJeaMt=`zR4mj|TAzKro{5EIzoJ91z^OLtJ zmVyhcc&aw;NqO0^bB^5%ceSK4D&M|nG;T8idjgev*aLE<+_tsi&#-T!&yH7f2H`@? zy`+#2I}1#zT%L(xSTAUJg5x0rhCHD(r{2Yxg0xxK@? zjl~Bi5^uC&5C_faXU&5-YlHgh{HCP{CYOYk4aX4CjzyA^B5c!lxH3=v6Rt1JMOou` z@)GesS;MP`??yZLBfcyGLj1`kQDmn3Ozjn}85N*ttaokZZcB&t8Z<_KWs9CeLs+u`4@vi>tq07e4_vdEMOb1!*o@eCBEpAkaW(=jdYI17UIOr5r z<2}ii+DqYaDWqqJDjJMHA1o*>UiS#J%){Pos?(o%+v z2a$+KJ?b;`?{&W~Ty2T??Ctds?LhA^WJgA^hI#rQ9{4}xjpwxgSXqm}&a28#@VUS| zMgHhw*WgE+2)4hVdvgM_Hojpu{6ct{t+Y}fZH(8@24r@^BRC37)7S~M&AwRZ(FSJG z*p#oz6-MoWV$d@)C{{mIGRW50%eO09l(>epr{m|ky@xP|>#BejO>zh?{$XO}P3QrX z4lQ^7>s%I|M{Or<0oyxq}m5~I5m6d)=sO9{kt-eO_JXC)K>rW~um0TkqAZtyE z2b)jyqd1?A5N<+uiYrR)XG|LKF5gVnB6Oh8r_u8dHQw2GuYXPatf6SxL3TL7+dBq6 zW94(B!)@Akcf|i|p$2_>7qMp_4{`DEPO|xShYdDDL-UJ6es03|X0(87n~PU^Qimgr zfukYaeM{Log{|kZPL@D>XS|`$4%cW}y-Jo#_bhm!09~bJ{$>7l@Ermpy!_bRp|1NT z9H0`WAHuhpv(P83!=yq`ZBKyn{FT_Tl-tr})r3Wl8>QNDvb?eNTa)v+BFr&Kwj(!< zMNvFjqWDj{w%MXkrXj)DAZW|QllHbR^T-=&I|tH0H}dZ3}R$n z5N}JScEtNQkT^Q?%_ONZ$#3J=6_+yikzVhs72Q;p5$ubD7{`EnOx{Zgwrr|l_C^I+ zPIV;X{jY_D1r$zFK0h#Ca9kCX<$$GjdtECvPD617o;m%)3keu*{;RZnWzBgLFaFwW z30;oJqfyhzXbj%6`o^xq#rBvY^Au^G8AxAj`B_nA*GB(m&&VLiwKG3Y z-_JHN!RfsC-*bSBlxN&Ka|Xc$mYqb5ZXSc#2Qj`tH9eBuIr&Y>j_D9wr@DW;bMNtQ zv0Gx3#pLt0mY)(g!58LX2^j;X3JhSYI}k^Z>|H$^R;a{d=?>SV@A}oXle8xbC7N5~ zMcAD6Aih)F^kxA_N@q#W$e!XY@J$cvA8-=a8SO2Z^k@$<_^WB{?GJ)78Yqzz>PR|s z5igs)d1|W9cdIvVUNOnLz|JL87HjpTPr_@7d%W3qHq_(K%5UV~oKTDXRAN_y=;JR- zt_jO#<63cmD9~DwQBUnVRWo&Hw?w zO;`Vp1`v}Y+&BRJ96P9u>$A1)Kp4!7TG~z@L*g)y*IGUEs?FN9B_ICXczOJT2}a9t+}9T z9uH)LL}WsgTw>wG@Ut<5g}={CqbJavS6_Ohe}OTV<8yqC&wX$?I_KBUKl1VSAkaQD z{H-RNjz1P2qiQR+H^6gg#5DG{M|C)}x;^KQ*ZhQS0LYXyuSoG5#sUQ|TVgx#EO2?} zb>bi+;B_?6yFjS@O5x%;(6B`XEpd{H!>BA`7B_5(YLHx9LwRq7BqZgb7zmK4{?>S*G?lJRP2@MF{G{k$L z3P$~Tnpc~`zzulMcQ;UL%iKZz(M8h*$E;RY_D8Skue;nDj`8_B@JF}Hk)pn&pJSN;dXotTl7?@C!0WbpmGSxnom9JkD(Tbu zq!)cN(T+kkbfInY;H?iASqW3tWR1}_qX6DJaNGGb5yhnoy@IgLYz^*E@SNrp{_pMqY-0s%2P`lMd zzl5)AbZq6!5&Ka#f`Ps4$rb7B;UurXlc-MXadQsc05P044< zx4ed(&X0uK^C?DrIM=E4pJ_{OzF{W1CHGLPi!|&Q^4b`>CZ%9Pm+{gt@dfb;jAtZ| zd0iH$Wct(l)NE^STw=n?&)|mkdit12)y)3G_(60OO2Ph$K(@n@_xwnWRPIAfvjyuQ zqhirTvwlwvPGx=refE2?3yc!stUbFucLrIAgb`6MhXn|q5UUQz{bz2nlJ>7^ox%VD zh(=3z0(32JbU@gntyfi~nQjW-1+vN?=cOyaW>zJl;0IkM0mANETfP}L;qO{pZLuAk zW1*=fJ+OiCpC2yDcG~Xq$CZwBiGI{RY<7+{_?U=u_LwW|K0SuiSKRUgm#3O>(BTf4 z7BG6dTwx>6IvXUs0BAQh`{EtBc4%ok622szuxfvwnmKIhQwbxGx*9>Q59Ew32HGA&Z>p_wAe(vyOie)2WwtH^`{*G4QnGB}?qsY_|Dd}#&}KEX&&lnt zfjJPcS8yek$luk!ok2@Tx)=ilp}V5IQ$=TIoZHkN-&Z~5`EkLU*92UHmB^iV=F2x= zVfS4g-ZRR`6xaWi`Z?9B$}nnD{9_do5I|wN@S01HZ|HpIZB?>OWrUDRso!&6$fWiY z#_v^4S(}{LOmJ3_C#j$vLAgFm5!C2~ar?RC>Nx9z%8TU5o5rbTkWbQM`PjqB3G+&+ z5-W_y9k1Ul9c^xpA#FbR-LE!u&P3cK1H`sMr>7F1mCFYIXa&kTJr{ljbQDdM=Z#yx zyQ{2f&RCP)*^6A{zYviqtNH|_BgE3zS6BT){&?wAz_i?i9taCuF~1M*!b|cpHk=J% z>soE-jf4u6(jI7~fTH>gzK@a$95&~jpNE#4*Uf_8>Et4-1QpX^r!VK@GEbwj|MckR z=QN(Y(BvQL6ni!72$}B8Duk&7Q?r=Y1&*nVbfsL${`)~gB-#0J|7rICg(6^Ht6oVL*2rXC6Qf&HI^p%gg)486+zFlW*2dVr&fw%90m%xu^Qu~M+zCYBA zAtD)csJp4BM7;{@-g1)3czYK!WQ+Zt=!zF!-w5Ug+A=%{K(uO#$cN0_^tSb*c6Q1h z|Fe=;k#8iDD;-{K^pY|wc{z`s3N>GZWZ%b?@lKBNznXFHJpNHc3PeqLS33D0_@6!; z_q17l@C7o2CYzYg$q>$rd%UB^S#CAR07N;ttWq@@6yj**b7e}ZQ0IX=;#yKHC`lER6y$Wm; z=GdOV5&I=0UWuTib^Yq4gy`h?Rq@E45QvB&sq*TB?esjMm+CATm3{n+lC355(lS!s zdC?nR{h64yfIFO~mppw*>&aXVu>TeazxWDhS+XaQM#{vne%xhny+_k7GLns?f_}0M zvQ3->mNu`SzsOe!D8_)>BURQHY z>v1|Tq82?^$GgKJP?x`ABMm@;mVBF*ge9h(?kZMw^G*#li`>=CZ@#PI1-xmK zo@!ViaOjpQdjZJ_H%>0#P5Sj1tSsa;W*Gtn=A_H@eT9HEG)7jw_!J0Y+{vy5nADdZ z0RA>S1v3NUc_2xlW?Nq*ik6C0o(1l*bZ})rSNM04`Fq?}u6{M{ri=E|2Ot;kl9`d+ zk~UgMwo6z0p>a3BfS^R|z^Dr>M99E3Z8yK&r{?95&bsD_UOEzY+`#=M>!AQb+YnlilBe&(n<=pqL_Q^xui9pOPTu&nbGi&N!SV4_AglT~`G25!R zMvsxCxt+s|7x_))N*LeNmm?A6B!dB_U?a`0vYVoX{*Td*wB#gk-tK}!A&%0VO@?o( zH2x!!3drx`N2q}$Me-{_MuSF!w=Q^Il?s%vo#56N)XkEbfQwHfIOFb9)bvgK+#X|? zGxYcm-bxGfU>EEo+Uh|2_|(9v>q!VMRn%!Qh9jD8W))+_LCm(D)AZRlH|Y{rvI9zF z-u<&j04Yb7>a%W+V0qmj%EM+F=*lqA{wPW<4Zr>DSy1H|qUd#)R+rs+HP52Y)!kGV zVtD4&+(t9|~)U3Bek-#UEkYeSedg47%k>QZvM6F?C3wx)LT@DN+QrcF{(6 zP!atiqpMMOCE5!gyxcr@WH7D%+Ewtd>b*9)5&!g@2`BTmnu37rf3ZanXcyzM-sJyg zK!(x~C7ry=6^FS(Fp*Pd?kOD;)~1cwYNkS3HHHMRS-P5c&I1#wBOL2Eu7>ECe-8&F&((Z@(aT>9~ z3oLaq(kDWL|Px7daTAq?Ac?4P9!OmAXIQ$)q3ktSs2?FcQ`4`Bv*@mZybP}4@ zw|-(bCSG#CclfDd5}k_IqMCHmypMIi>WX>03L%t8_YuD)Sd}+*0%v&u@JezYLWn`| zFIfuI!J={j^>7mO&Ft<*kta5jLQ@~Ua>Y5TUGS^;mY>a#LXIJcX8CR}endI}H}q_T z>TUr47IGvZ*d=-KBSq?8BWbR2p3ri0=8N*?DLWkF$iVH0^*+`5=~ zSYBp}=mG0P2`zp5<*3Vn-|!@DUW~XMTErR>*&FJ|l1#z2otFvT^%}HW7zFsO+*P6d zIemXpQEI{falJk7)*^jqTQx!s_<|F1x{mUK3aBH8|1b5S=KUY@1I{cO2t}03fDfMF z2YMwjDkP%J*1dibJ3)1hB1s)1QGd*5^RdR_{$R9OLx#cv2OrJ|2~qPYfuSP>URBuNwYTNG zv}k>@;!PxbJG=$B(zb!8{L#i)4a#WM+dzhb73WW5Q6_{gQ#_O84ECiaV}2lK2HXzG zt?bha2LcyQ7r9c2ZPYU5YOh(3r@J=XglR>c!pPG6EX{ZH&-igy*YnL0{Y`$Bdulp5 zIRbB2uY2XPsSeV%dP;GrTgrmX1X|~;$x8*xJFpy$2%V01sI;$(J&9Lf;{DZO*=yJt z5k`?k;U99^2OIG=bHKE-!WcZ7y_9nM5XHk*N^EiZWM!vt@eVEUu|)5gfJB-hAuUUX z)A>TQp|Ka3UPZZF)PFc8{n+0+E+RjXYzSKE?iNiZp!#Q0yahEQj&CUd`wS9N>)6>!%?`=1P%JX%kdI7N z@{Klm5F=$xX96piuF#%>t1vEiFZKar0l;|bBfOjMa6We6kp2eVz?|v*X<)U@3rHEL zztz=CpMNdaaO`OtmgQ%cnxJTBz_*^_7CQ8yeeb>fh^Ke$c*6~h-HvE-Ru&|GGV1m zc|Yi%QmId9e_1shq5>|0!tB%q!!Z28N{|b>5LN~^M=!sHSN`&TIq@elcUHoGm&hY$ z<1@gFtL5CxZWFH`PF{m(c`AazBn@?N%H%I!2ywPQM<5@a#Z-?CSX5Go~#HU z1-tPIaOgx=#*2sdkvz?%xtA=b$_hf@rll%~9H{un_qr^kYMqAv_&8v-Ssbd`fdc5l z{V(~<;_VD#2SF%>v)cMK)ug-j0|rMih#Nn04(jvg97$%q@>J>B<*rxHE5>n-*IyuR z2XJ!G%c78<>BxUY-|xxYxQzFI|L{p6aJdW*&c);!9qc8CRRTL9h^cPZ#4z38y}ZrFb7VrJ z_GV`)SPp!>eZB#PjzlRKA!^eAvzVD=qJy;X*RDYn5o@-booqCzvS}t}oOwi)C?_Ey zgU1>xTyH+IIK_hYv#1O9F~N4oL#0YUr=FtE%n21okZk!5x4<+|uLrhSemAKm zJ4N{G;G*|AAZP_c?rOMP6yWXvKLH+KxP}Gx)}2rHmU%+AaBeHGgXigqtdOAb1aIF0 zSFy6;Wlvl}6@}@##NQV5d?F?TFC5lM)mAIr{Fn~EH7De#P^bElrXx)yro^rs0h(?6+-u)rc%B0o|%P9;aFqt;X~NJ3U#N`AmnS zr+P9G0VC!Km@)O@T8Z{sSWbTiD|9f;*RFtTRby~a`&DH z;zQ(DV(uulUjvE;S)(D=-wi6l;nwhW!#Ph?;W* zu5*nq=~ASn!&r)yZru0~bv8o>jT>T3z*dzIt`Ajx#E2(_$07+ny${rT+e689&%?V0 zIKmzzU`R4J%YW_|0b}`v&1XEY)pZps%#=(QIL@W0Nei4AFWL*Lyh4)AsD23$W~`(G*9kPVe09x0@hz`V=|iS@kJ? zp5}WQYn}$nK^!mXieN*67B@bmVSNNGT_R5Tnty@8yMcrI&p7^)rNt*$)oOegSBAWBOk1mlp{ntaC#rGegeWJ z4HOjM!Q*$$f&DHU(}y;zG1X~BI!-{*djghOsH6kp*GujNJ43lNz$3a~Vft`qmIFw6 zegNpN&|HdCpC2Le6EMe>;n(Dzr&CLYt49FLeZxCA2Q&gF+C~3*-n)=i@bl56K}A6` zfI7`{Mk8;=4syOE!R~E1Y^CDUKySof$kpHQP$N<&2w~mUlYbKn&R7_}+$eFlx;H3~`)0aA&Qlct5{Ul>9$#yYM{h;6ZSG^RgE;1jy4U)Y5wXGAETWe6Q)8 zH2m9-s)W5$72 z{XDUEr#s`()HTOfNTB>Tu_M^AQ5xuec_vq0uHV68nAzMIhy8bMjG6;fN6#3pDO+1+ zt%0HM>2ikr1qCfcSG?Ko(M)I^Z=3w6CWK;c;44#KZ&-7ZyT>Rea*)9&6X7=oEWey@ zmAYZ$N*evQ>k~VPc{e28+YFLlGsFdG6G#q>5|ZL2J%@SEKMMHDhDj$oXI&h*Y*Sq7 zkiSFz_8;W-KZLmxIn>-tw_pYhB>4av2kgOojL;u8jQgCgiG9cV8mdKywvMxQE3Ikv z6~Gliwu`%9(99IJDm=kKq!(w2m0dp*5) z)lFu>@PGJv%b={Iu6y`L2qGX#NJ@uvcc*lBi*%=Sh=PE0cXvv63P>X%T}p?9bYAb_ zex5J?nfrM^A)_;R4QHRd_S$Q$V>Y%<oA_wg3bbyMjl95Gm&c zxU=XPPo(ElYOp<)wNkO}-}e9FTfG z%*>X)ZF}jOJdVoDjGe4Bb*L1vDr^g@)>wU4y2aG+$Zsb^9-c^QRWnuP5#Uq1Z*81W z3U7p|cI{7|F_x@H7JQ*prY?z1PiXhgB!*zUwBR{ZB#0RKjL<#FnU0>m{?Tq!(OH!H z;P4J&+2lsgh7H4+Al4UrIuTj9%@rtAtyq=4N<$XO^>@ze-8YA#Z;V`6Hbdtlk-Hwx z^6`Ii6u_d&mj$aKaS}m<@>F~*uTa*sJT%&QBaLr$4GX_Z3S69z*J0K3X(}Fzlpof= z)l zUQaZ1-dd$l(sH32^VGE*qei_7f3tdtT=%HG01HKAVyN@gq;v5MLUw&vjV~%kQ(KIE zrmF;vQQX&i)T#Sfrl|HCqxZd@A&c<}ncUkE1fPxg8ngu`tIsemRmW(lU+3)nf>Bca zMed7;hGSr#!{8Uc{>Z*hJHD>*6)^(W!4=P4L3?c6MvmIS6N#F^y<6Lnziw2R`9F^4 zD~12sq}Oo6>NtUYxd>)mC+#?hQUyHrz+PZ>unD6FQ}>g_VgaaApDpt(06C7IqXShAD449LF&crrn(?3t?G zh4Ae~L$_RS@^nNPH@`Vh3FU`vX?Ss3<;k(SN?sb#$13V<71UIjEN|r##s|hZG*@+h z%91V^`YVSsS{Bv>b`uDrdHC+at{V&b3Nvp#ezMA6081cVHdsOor2+kE<6jEAm!UdT z5*IBn)yR^aUssrZ;5a{nm(kVB_}Q~oBX*1PoBAHNt^%zOlRDBh3m^u{r;0k=<=mhe zZ0I3Fhat(l1f}HV(w7||-h+17#dEyuxnhK`uRe^o+!qB>h)NcTu^q=J~ z%6)yJqm>5T9a`+d9apjo>JPmQ7JRzXI6wbF68mNPKPVYprf6z~3d;@G8kVwd3#!71nv7EH*&eqF8$Z5h7r8fY<0U;bkDY!m?Wk27W35djU z9IPtPpt@e7=d@qycF*P7YfKjNVVmZ!sS1!mPJ`Jm|8qU7EaeVs^iPt`r<*Xl9eUPm z7UgWc^x{@pU zgM7`=EV18fRh7S|E{TY$8%m>T?K_`y|HbLH&2%OXn?jabaHJNo+R5KGSKfLtKcz&^ z(v&c@$_>h5@tNHa45>q_WQZMht4Zuln1DM+sr@7&TK9r$?~O1y<4>g>Dw~`jlcA3l z5~h3pPd+J|8^;a>O|sV9=eJF7O!Ny-<;3uM;^{>1bZCdM8|~QD_TzJe3+24OkNY36 zN%3C+!13@p;2Q+0e@B2F$aR&}umer`Z53>HfB9+)?34|G!H*ilPLy3^s(2a(_#1iJ zUueu{K*xRA7&Utm^`z<#UA_LK+~e@Wk+;qC@U7;kJl~+Omb)Oy^s5hBo_996eH@Yh z%Ka@+)wHVG{^9||O$no?U`og9#|2Boq>t8|(Ah_;24Zc`^x)Cv)4o^#ESX~u#};4W zffYi@vms!#PGE7>t3*KesR8HfQEjFvLnC`PCB4F+=j#lFNwkZY9#l_#(~)0`hZ%dV z#8Z`0b6YeO*e1Ff?v0y^jaa$3vmX-t0kIRwZ~-TO1P9+D=+eUZ@kT%W2jo5l58S(* zIU#gpJ=@H@EZj%XPu+W?VD9Q=w{b&iitP=t8bM$x$U7DSBB7SPLf+c64wGPK7Qu2~ z98+k`<2+UXvd;e-OIA@kDoWiUF*sQ=Z2UeENpbjZ+$Eh%NBlBuqY`p})=+x>?t{y7 zjTV8PbobrvfhRSX37eKc@b&^QjU4}RFo@irM3QN*kYNMDhrdY z?%GP!I6x5dPx^mHgBULg@m^Nadw;Tzz)PH2b(S0Q?2o?( z4X+ywTFO?W_oyn#$>gZ>43sK;r8_XEF%2`kIie61dclr&EQRuxWoJb6*BbY2?`ZQ- zYXzb!nnUIICJg7oaA!5peE$tTKn-fax8#e_fjf?|p&Pe_!_2e94e&AlRox98jk0{a)C#)}zYmg;u z2Xj&UFc-6)FB=ZdS9B9|aBcsCEhHHORS-~gUh2Vlc-DdE+tljY1FC_jw1jLrkwDLS zBEGMN?pPkR`5r8#MG>}`d5z7y{!$7}e~MJ;$%zXkN2=V#cG@)&TSd(nU z7@nB#yZ{6sEcTxuKWMETxR@pS>WKEjb5^g`h zYnH8%f710+N!7m((9FCa!DgcS-4QwIwr^yXz2R{%`kOHdN zbK$c8z*(+7?vpGFBrXoe(^lrjh{NNl5G%BK0%!+MgOY#i2~C?E?3pAbEcDeT4iQP= zSqwMW<+>1YxL|u6b!rP6h%xK7=J;K!g0Wd5*(0^O=bh7wet}0!W z3krhijn}=y0~EwH!omiqj+4{)VVv=Hn=8P)S3Zb$T8Xy@myq9cQ>n4fd zTYKgWQAcK>ckQ>xFHlK7%JJln7HUBb)Ub=&aeRGeY1=T(;uj$x=kEsfQgy)3UslZv zh96p+rh?|I&JE~`4DzFekH{#j9dPjlr_$Ets7~^d>wN{@+#SsiDW{WmtJP=9z@6(B zYR+c`@(gLBdAO^i(i^U z-{u9+tN71x?nk;+z>@c zBcEvdZyXo}0Yvv0!2vX6V50_B0)=$mHcB{hu8iLZuG_#8Ud0~%XC$)7CM-dB+~Dq` zd2tIYL=j-3RL(r#NYh1x4C63=qa!1xBwcGksQx**uH4uJ7aJRNY;jXvpb#Y{)QFPy zPaiMgW>qW@BBlO?=R(A)kl++ zqr3WjhGxpl((qx5jiz*F{6JgYiNMnX$}>Wg#5ha2k74G%ZD6`Mg4>yUtdY6rQ26wX zZH>vo&|Avn2?Cvc#CzJTWc=bG0ZkidZ6iIgY12^E&vj3op+Ejq#)Q%}k#0%fCytH+(vj7De+#fOr%UeSGBOgmlC zM8whBhBDR8C>6+gtjHR>v>sUhhaUMqQjGdoK&HTBq9AAw>AXkRz{j83x$!vC@u^wJ zrsT^G(xR?aX5A>s2+LuJpz2D)+NDOP#Hv1QqC-9Ow{L@R&)mB}9|XZ1d;s|L-vc2u z=ZCh&*gd+!N|XPnN+oORdLEbTKz)p&@i_RI8kQ>g0NU8&I1V6|a{sNi=ST^R%=Afw zAKdQSEdK6RGN1z|TLoYuTpPhEtTt>|lQV@|v)TiUqLilzh6-Lr1cN1%om(!tecpZF zB({bAeNqv%kVThKe-Tj{BL4<6&J;sIH85+8=6NVn%d!oL`p1;Y&XdF}x2remBLs0*QRGk{T)rUP()G z=OxXR)+{X=`%ce^xH;K<>S?9@XM68O)fLHC5N~&+ix6-LXa$DsGm@kem&L$9 zwpkr+*q23zDTM4Q9&JJD0ayWYc0HDH_|V$3B?HNuqs@nkYLZFGSXpn6mX|al$f-&J zJTdJGt@J;=(c)f7R{Vkqu?)>AvqW=%Xtu*Qn>6*6!{Yi;&NVx|!8fbmebGJt&Oqzx z)KZ3G+h6&#Sv59Hn|J;6p+U1H{>wVlRI~>Lq}!1L0f zX{)kTKk$}1oYRm^ug>v)i5Ej{eyv;FaSm1&a3a3B#H8;qR|uFhqV-F!aP=1sB_owp z)tddsib=n-tk;E6jM#p8bu;>^CBcj_R5G~kunk+@GYyy2UTp=VTbSYhZ}`ntI0TRZ zWJuZpBJZJ$z8`%GR$Qg3RI@mOq@wQteGbhgs!espZx?V=rQ!Ga2Lqk9--Ex z64=`UNpL=lTJ*G~&b)4>EW#4Hn)dE~* zih5zmV&+8_h!lx+J^|ucFrlk2n~3L8Bs~=$8Fzo~FO6LRtA+~@)~L@&W(XRi7w4Yg3JzRGGL=)`9vu{n${N_bfsXmlZ=P90d2h*O0QB;=Lw)X~Ut9%Pv zBTm3-a`y_Kc9mmVscNJA%~L(Jolqp~Z@q{<6P8b^ij`4C12~%BZg=l<`vOq?x<3t@-2jZsiN5*<$!P8p>xX*$SYZhZ7N={{B_YQ4uNVTg>cB zkC5cqo^&yRiR4eu$W&q;^xSnC2e`6tC)J`xbO<0*l6r4^{yNQ)Bl6>L>RMj@nRUbm-el_r?fX92SGoqzy@^}`&&5<(;_!r$Q+Kz1uFB z;ZsW!lw+3EFbCr~?b1zwEWB-q%kk#UeV>aa;SOx^0NSFhC=H`OB6?8fbb8bamhzyi z=a(mxcfQ6DsetQJAI6-ORj?t32+Dh407vnBqP^&?)Bl)USP2Y`w~x(0vB%+F|EZMZ z(34N?Y-yCyH3$-3?l}2cA5SOK$Pl`KWH`KOdJ$X@q}a3k;1GEvrFN>@a!-WE?drub z*cg2Ukvs2z<+3^PqUnWdJBUHm?j!&t?={wkqx<4kGNLL#mLIMzLI=JDSYY_jr883~ z9E9Ttu3XpEPtq~J&tnu)pUb?M5;j+njv!c}c5IxVUVc-M{?B$ZfryQ)EMkz3DEqo^ zbds!~G)?YjEbxQ8T}X-UOWokW{CB4xYGlxhX4YTOMj<*R^zkK$2!$$r3e^aY=MV<< zVd{Pin+>!*cg-rq3HJ|b+sx()08x93lSLeW!&=M-8R$}~wq!K8;>EA{7!3mx)%@+;ij zhE9*!iIG}m2tRF`mRpWr#%6=cJ6ZO}IN^im zFC8G@aRjTc{oA*n3AwT2dry|iZ>%L(7y?C2P0cV!W#|UKo#kfXn`9vje+JLj^BB@# zf6leT>1hGdB}KWVq3``f8!ZA)<9j`(TD&X#W$gq%GJdhBfD;Ku)*0@Hj}dQ-4y#w* zD15bLz-h^qQ)#(@M-^@5IbW!f7UvFK`L5_m75xz(#$>O#o)_kPY&C0IivLFy#S#Ki zeF4~rVRf6Z?z5!8h7>UyklgqfLj|H~xBRK{MgAm%?W7}rTTH4lx$T$_uq^lbl<{*<-Ru2=?H4`7#mNt|DK`ntCfbwfmpz?sQ>_RD+g}H$>7nQXk|+A~*nW)v z8D+*jD>Vh88?@rylWf(RSe8Nt8%+;Dlc8(yDK+ zfL5eulWj{*PDH1OXaq@_*r-P%|CaevI?@~*@cudhA?64Lis|rNC3v#8QAZ9xR}3j2 z%qw9$MTbv#_D`i+W~pX*2DMIxxi9@rBe+3R(Wl4swZs#`=~<{wD44JF#1*M2eTu`wKnS3q(*OkYzWUWVX=-`7ZGWRh zm`{Q)Y=|oS%ac;^A#1ATOyGG*?AS1>`9OEI__=y#*jw{>kA6w6oH;@$hx|WD!5**T z->J#%!WGX!pjX>`gxUQVK%LgTG3qXRjH5uLbAM-#%+AP?kl&bCFF#fQ2r%h?>`qs#?;3 z7+al>ka1WH-v;jFy0&n2y5_`=x1E=Tx}pvICHP3d7aB2-1ZI|iX3{3J0tsqT16lvV zHV^acU2P%TcikFdwSQ~lM|n^Xx^E;>hH_)%hl5PVOg;PI!akT+k06<0bMCLy`17b< zD^TAAM9$)ezY^4!Jr%6<&9A2HbT1&5*Om~L zT1KL?{G?xIaQerR<#O*&|9|BX43fikM>V*G>T@sU-76!HFj`~t%ef!Jqk)7(<@IH= zrwx3<%fG?Rdw&lZ{%lZ!bygj)#^tCP$@Ve}rVQQ>dp)Lw zzwu0=RHl_nQh%bkP#^ZJ;x!0J`D`Y!~O z#F7iZIGhN9te6*2k$~ZMtFUPYw2iZX8&hX4=-7^ywMg8u!POb5=+9b~&%?tPQCYGq z7VFRH663VP){psJbl0ln%=tFL&RbxJ7A(-=qbjx7CCYj5T&|gPxkYJhciI-7} zb+9nnG8X?whOEh0dA>yxg|2of%ua0g3uw6_m$GBS5~LBw3klpvF%9)8$!S6sk>lf= zr)sY<3(HA1Pk{q)Y5}Y-bKwMVLl85W1-$x;Cv5E?(!Wz$UNdz8-&9CRwn1)JP{`M(?nMH&h{fbq5KDn zHI5I|=NCKaIHpL_^B!uM(OR7t0g<-IyZ=(w>0n114|!t55aA`}K1Zf&oz9+r#MiaB zcr6K#XuGnLgDrfMIM^cBA( zls6O{m7@t*5U;iIR{d0FOf5;D6st#9SQsY1NTV_|UTO`y`5XZ^HU~Wpb7Abv>n8t?WG@!LviCR7sa7guS*Y5ci zrM1QUAfuPea<1M_L#2}B=L=A2&G8iG#KKRw24p#F+b%X?!tiF!7P)HyGj4)i=_r*- zMTrw@!9-{N6wbD7)?VLhL-hZ27ViHdM>QsD2End|ML^xqa@N__$mS<{EN2QNGo{*( zDT2MHBc9_~La+?sgJ<72bej$w0iNOr-;x=ga~ogbcUCdAvdQn^;EWBWRb$!^$nzGd z|3VdQ0QSYF(rF+S;$&#>|=9E9b0<>>_|+Ytxc;-8nWn#0dPp5jw26lCz^H=Kwy z8)1Oyk5U`Mg-5=%B}cB#u3t6oFDd&KF{wO+vNcin$HOa>3co19mIJs*k~P_)G)6Fy1m$5ak{MZq z+vpA&~$QPI@S)yDlg8& z2P&8=cg(|hnHr3n9q5aUH{0<;W|r+8)52Qf*JpCo|LJ!mXm{2iNc9=#rQV|zfSioy zET7~N^_$7FTvSwu-}{b@OwPN~`D)Mq%uXrDm!SI{zr8j03l_{*#O#p#O~}DL?-DGX zq>!59i`Xet@kw27M{Ga{!Dm?;kRuS97ygb`OfZ`$*7=B){@k*)k_DRED>Lb15KQsQ z(A3eH2Ok(+3*_PUrv{TnPyd)>Enl8LUB8?+UXmGbO|oY<(<1g)9F|-H5{NeGcJ@1~ z0w->S0M$3>dE+*;ugC7pdf0BC>Q+oiPy0v;myOPhcYLwof4eN^5Fh!RsXK)cFPYZ-^ZsZW z#KP^lbpu{umr&U%I}IUz(h~($!RFAqY;As&rSR*!~{}%Oe?iKHkUge%k*7NdJm$QZ4yj zw+y`8fJ`&lQ%G;b|bb5r&qwjS~0bn)9kkv27*CWReS!Kdkg?u! zx9#|=@A=cN^h-4-Oguu*W}w{fT@>5-s8k~9@MCt$9v$?ZHC!fAb^1U|bA z>&LvD7?{KWJNM7#Q4oh{kd#Qj~$kFRa$ zRae|?hd`?YHZ0r`F?(-o6rAMWiJ ztkbi$4+Am4Fd_S0OUM@uq~5(uOH0HE8bM(rEDqub4rayT#J3_-YS|}9V*pP%%z8n0 ze})p}%SE)g&T!a!jLYkZzmcDC#1ct2ko`z}8=F#3`O{YQdAi|&t#X+HchJq;Nl^tJ zR7akgfewvMI@e-XoDG!N+v7ph8+P~{ug)46znPV6DrNmhCF>-*mzgbSV@GlFc)KDl z^8&}`jl057e=?`%;wxg)5&cMY)QY&YbC&{(X-2P+c^)=TeAmesTW8;hbFfO>ukj2< zn$v_Dve{f>RxG_=46D;J3!N{~={gAIu|&U67H-z1sV@m@8c0a+-zwA2aTM z3H0dyqDQbWe{=kZuBE@E*RAHuV%UltnXafy9r0UkvR1 zgm)bZlAVF*7$7`XumYibLI<9C3d?OJ;S-~%x?W!$HW@*R==|_c7%AIS?ou{ET&z`|p9jENiTDig@NOTc~9GFN-ydi~vI5uoge&fk)-*LYAR z?AjBMcaumzM-WIq&Q5n89stGzWaHpr4_-b>>%kEQwp|^`#-y4xRkM5`D9>lO*|xpV zE8Elcvj;g2Rk>bgx*NKb%HS1{qp~BPPTTXruL zj5U`@0^uqlwbx-c5g2~b(zu@;pVIH3#aYJLCHE0<4jO{HRQ_I=|LZ`gwjY%f+5D%j z_nX;X-+@I_9c1UPfkaDW5jv^Rm)*S~QXmMg*+0lx_1I8&qowA>nHjshRwbjs%&9#Y zyIsx$cRPTmj&ju~kQP}FJ+~O)(Df#bI{Wm1)jV6TZ2^s4&8%!Y6}eWw^!#DprfQ|u z=(wj+PbWyp>bUc_0J6Tu70A(!sUgET(~6NE_bhf$JCrIGS}*=s%QO9#Vb60ue)X^P zogPp&1GMLi1yvUFozV)n`mUp++^7*hk&?Zh=ji@`*Uh{tXSb2WvLpXSfgWaOjR#5W z+r6?(6EFvwtBQZ2Cqp!&Oz&98Rbk%Ck3To;X4RbIBb{8-G;Co$j{~y20uw*|?V?1K zm^Zqqo2W0yU0Jp9%~P0SN!YA3N2t@}ytAC9bMV1rw)D;%p@EHg? zLwnsbCo?quSz~BYipW=(3$l#oO!_NYZXk3v@~eY*GO_sev8!0DG;@{}7vKlPTi_89hKU>=;K|_I2EnZP zDU0q0r{D;ywcGvcI`5-~dVsM4nCWU}(5n6cmCc!Z0PacD>&Isp0Ea2tMC(ZsFxtwr za{u#X#01D(yZ$#fX)e?GWHL7Kkye(*Y6AiTHi6HywLlWLnMLJO&I#2i)2$|=Lp2e* z&P%BNKy$)lh9x%S7PDK;=7ER3d>+_#AG9~Tk|^hON)ttIy$yMVs?i_uNER*F2fI+3~AupJf@_dv)7 zJuMWGYz14a;d!tVi%`X4rijS+oQ0+3a%zYLARTV3CRmst1(@#`E0X&sZ8Qi3@2os( z8-yE^6>z5iCd`yV0!6wB!-Gk$H7=6#w~4-=nrSwq7xc@|F3EeojRc!d6@|tjjPo{n zbf}jQqeSEST|W7I$7m1sF=lOHdDIb|En%2cU(Rw&Nf*_G=EHB@$q+zQG2)!V;4PqU z3Q&3dqrAxPLRue{7URoBp>pB{@;)B@n8DYM<&VbN*%W3gme0WDaItig@_V|;PHKj zw!@f7<0bEQ=54mxSRnV8@%!}g?<+P{^%p`nepPlG-r=Do37dOpGh_qi;Wg@C?dLqH zvk-_vGNRaR(ECL@P(~aPp*TAS#Mn$WN*l%*0~b5yB%#HbQ0~fl1$GZw^eLH8PiNLl z)Z?9yUb5!q4Kkk_2XqDPfR&eCbKgqfJl%ZRUOYvF|0qK96i$TnfByLYe2M8kYi2&= zzdOlOYNxxwZgTlkc*919U-WmYdf(#ycR*aqjP2EI6RlpQ@DIKh#jLg41@*p3kr}uD zY;OwPhttTNBT~*7h`pCR=uk=cV&qk7-Bxc)gj-ybJtTmN_KJtN<8ybx z62;!F(Zh&NKzl!~!}o_Qvses$No#cH=lD`}-fycyQmv`(V=$0keb1-Q zV0lP6|lClTzr8K$gzSJzQGJ2(nNNdwYyD+(0eYo z!wkeD4ja2ImZ=L7$GEY&j5h-~8?T6q7w!h{WaUrd6Sj{ekd$j-dMFS?7H8YZAg^#L z?VB3pWY8ALQH;)XHRUb)mZc+G@ue?MDMnVvt^F6S=*X{)JHNf$9-_zQVRdnoZB9S< z3Cj~Z-+!`eix!^o97&(;8=GZjk%tqhgoE}g)&vjteuwX}@aL_4-=ms)8+M;XVTS0% zcSz*L{Ty9Q4qMY%7zMJf^ruG~0I8zEcQQ47b{xHPA792JKB;}NYXUh#`8O&5wn1yy=pAuz6mrxk94Czx1 zeMy2?(`Sp%r*ze#f8wEzt4t0a-{~`vt9Fo<;Nbow{+F=mX$cQ0(2sQT1UQraXk%I} z7oW%c5ncMW2O`pTgbSE4U-0;hNDjad<1@Yt8ESzUqTYQx+&^{vt`8p{3o87L81!Gt zO2qh$G|8QjllhrJ`+NU;_c5gg%y1KyY3^tAFdsv-;B+!d%#j?mtf;h_zM}*I|Xf&H-IHPnwLj-Whsk2=i&<0|&N`z|`VMj~Y0 z;vb<4k)lI+6oyFyx7534?m~Q59Lw#&r zz=e==%>Y4p07_*`=A9AWP~i~4iMh^ycVj)2E{NI4?gw|c01gO|(_y-N8oSa$?|oW2%g|U|rhP1L(cM^$-J3I< z`@XNva2l2IE`?3XYB0TOSlTnl2Mdy?3ub*)I9eylsP&1}jj837?IMuvL(Z)AUL~jW zGDBOtF|7af(MCpvdz2N15#C0+AJ|}4kKj7jn(`5KmKQ!?7$J~eJs`AKY)c5}r$J57 zn(jB4=Yjye&zOfN^E4zs8ba^>PO9x?k(uL(qj_WQoqx`rI!_%Yv>{jGL)NPsX!hyM zn?s8H#h(m>U7z%uBlrNoX%)yc3n{1QjM3U(asXdpGd(VZCaqLub)P}uA33#z;<#N! zqh`%IVM!XxxPB_Xb1V=oKO1&SJF_G7vh+CVi*cNu9aaEeg4@%7gx@KbRjfy-uf1f@ z6WcV6tl%h;DxW}h;Rm=)kVxFuB2ked%TVTxWAU31?=`&CpY?R7^(4rHHF18N8`^fQ zc9!-DRBnb`vl3gn6t;$hH2*2GuAeX91O8hd`_x~YCCFLfodx5)sa!F**J?fD=Qwfa zmmJn^+>O9dN*{Je5xSHdyUn_d^6SCUyfkDOkn&wzd8`+;)(b^$p_9LzH)(Vaf#A9y zc~}?T??;56ecJeNSLLpBj~q!8Mw7+vZHRe|g7yVrn)fihNoE?KKt!I=?`ostI|&wb zyWR@r5O}&z(^M4RI?#!Hd&S@5pbA#G*Q3wnx1g!g-7oK@i3z`8^b--KTD(ZesFRmb z_d09}>m27Lx97#7shgmU^KU--*AWW&STAnYjOE24Qc#JS#k&trti$}hrzs!a zi`Ja`44;=(a5bPpy>I#i)h{%XG89%f2m%C= zg`MFbdx~e-b16)ldkqQ@-vq=%s5HV7>B(%@Rh9(WEAC)bzVq+FCn&1%KltU5vYnTE zl94D<#)THo1CfqPo}CD=*J~C&;X{5khKhqq4i{%}Onx#e*)UcDGl9uLYXkwA$WgDp z!cD$r@_P8!h#cu(Dt6%W#{=}bi6^<^ThF7g!t`6mo~f4&vEi0;n}zIzidDclUUb%W z>EWo+h);UBFQ?xKyKT(Dp4o}Q{fQrie=^}OGQv^)f=g@8dO&>(e=+P2Z6eKfA3|p5 z0p9h;kvw@xbvnW+u2)vi8ZY1hE_el9QA54_`|_%vKRf1U`y?T0j4DY5;hO2FJICV0 zrA9qZJZPw(2?*)YS3ZdN#Hk)&G-bjB4VXck>zyJ@5Wo-t#xISy@ITE^DIL!7(7Yxi z+NoEzgqi~Ez4Tq-#l+WFYzl5pt9+(Db?0*Do$rer{C-Fh9`?NBobAN<*E-|Q0Ifx| zacl8ft37FvpUwZ>JIKmhIQ7Dk!vIo_yZVA87(sIz7$&12n`X+ihacSFl&KRnK(MIn z++YFQKFvmj(r>B?;%9_iJ@p$#j5kFPW4OQJXb!#2l1?J;n}>n_ELC7?WZcAl+@`o{ zHQVnEYpejSGuO8Yhet0S5VxDAn3bMNaHt&g&%%dt$+aeIkDHd6m48et32xsf@*=cG z=S8v~)bkh^t&mhe2ux3u=kIp?)MqK)Ari|HYJSYOOaJ-2AttCW_BrE{ER;RiH)~)} z80m=ZC2$bn?`7Sme77s$$BSUJd3aJx%i@H_$M*ey-xpV_bxb&*ilLi1%7Zh-FK=y*#NSBWV(UT8GZR0orPd!sG|jv8)@XExmr2 z8P7qMC>cJgFg_;>{;Jb{$7P?3!J@m2#>b>eA>V_gB!f%hC70v8K8!3%JPk~b_6b8? zQpFz%^I~tg4n4l?OWLZQom?-iTt009*P=#_8tFZxwC{Pm1HiHgqEi$R4U^CL!s6;l zqDF%tJX~29iNyh|ni|486-N)qqrP|Vxy7~ig9Q}h-+liwwJY_CbGI`Asp|=pTN|f{ zuOr1ml1H%3>`&jr!9=X?3%7bS^wUPaYermVomCx57vAiB})tj0|xl!l;B> z{F7jaL03m`H5e+oNcTe$6o9Drv)d(_5kSQBR-

qb$(_Z4u-Gx7j9-Yo{a={h)5c~`l2 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%0AN_qXJ|BgjKc3t3x%qvJwTcE&vW^(b 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 z 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%0D5SDP1PH;%La)o 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

VoJeOXX`J93tGQ(M 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�{{uFqtB$z?7;t!Fake9CFt&;xjn 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%0AJ&bKg|JGCzCBw@G_KH( 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

    P|ue;{FIIbWYx|OAjEnIz%FOe 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

    --@2NB8R)C99nt0_y`8W#V`6R+Cq(1K-=C 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�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

    %!{zT@LRh%`u- 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

    ~|JdWx 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 !&`%S@uk{`|9pyNY-m3Z~WRLDJRFm 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π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 literal 0 HcmV?d00001 diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala index 0726b3cb..ec607279 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala @@ -5,25 +5,23 @@ import io.computenode.cyfra.* import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.control.Pure.pure import io.computenode.cyfra.dsl.struct.GStruct.Empty -import io.computenode.cyfra.runtime.{GContext, GFunction} -import org.apache.commons.io.IOUtils -import org.junit.runner.RunWith +import io.computenode.cyfra.e2e.ImageTests import io.computenode.cyfra.runtime.mem.Vec4FloatMem +import io.computenode.cyfra.runtime.{GContext, GFunction} +import io.computenode.cyfra.spirvtools.* +import io.computenode.cyfra.spirvtools.SpirvTool.{Param, ToFile} import io.computenode.cyfra.utility.ImageUtility import munit.FunSuite import java.io.File -import java.nio.file.Files +import java.nio.file.Paths +import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContext.Implicits -import scala.concurrent.duration.DurationInt -import scala.concurrent.{Await, ExecutionContext} -import io.computenode.cyfra.e2e.ImageTests class JuliaSet extends FunSuite: - given GContext = new GContext() given ExecutionContext = Implicits.global - test("Render julia set"): + def runJuliaSet(referenceImgName: String)(using GContext): Unit = { val dim = 4096 val max = 1 val RECURSION_LIMIT = 1000 @@ -70,5 +68,22 @@ class JuliaSet extends FunSuite: val r = Vec4FloatMem(dim * dim).map(function).asInstanceOf[Vec4FloatMem].toArray val outputTemp = File.createTempFile("julia", ".png") ImageUtility.renderToImage(r, dim, outputTemp.toPath) - val referenceImage = getClass.getResource("julia.png") + val referenceImage = getClass.getResource(referenceImgName) ImageTests.assertImagesEquals(outputTemp, new File(referenceImage.getPath)) + } + + test("Render julia set"): + given GContext = new GContext + runJuliaSet("/julia.png") + + test("Render julia set optimized"): + given GContext = new GContext( + SpirvToolsRunner( + validator = SpirvValidator.Enable(throwOnFail = true), + optimizer = SpirvOptimizer.Enable(toolOutput = ToFile(Paths.get("output/optimized.spv")), settings = Seq(Param("-O"))), + disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/optimized.spvasm")), throwOnFail = true), + crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl")), throwOnFail = true), + originalSpirvOutput = ToFile(Paths.get("output/original.spv")), + ), + ) + runJuliaSet("/julia_O_optimized.png") diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala index 422370ee..90f0f91c 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala @@ -1,30 +1,26 @@ package io.computenode.cyfra.runtime -import io.computenode.cyfra.dsl.{*, given} -import Value.{Float32, Int32, Vec4} -import io.computenode.cyfra.vulkan.VulkanContext -import io.computenode.cyfra.vulkan.compute.{Binding, ComputePipeline, InputBufferSize, LayoutInfo, LayoutSet, Shader, UniformSize} -import io.computenode.cyfra.vulkan.executor.{BufferAction, SequenceExecutor} -import SequenceExecutor.* +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.{Float32, FromExpr, Int32, Vec4} import io.computenode.cyfra.dsl.collections.GArray import io.computenode.cyfra.dsl.struct.* -import io.computenode.cyfra.dsl.struct.GStruct.* import io.computenode.cyfra.runtime.mem.GMem.totalStride +import io.computenode.cyfra.runtime.mem.{FloatMem, GMem, IntMem, Vec4FloatMem} import io.computenode.cyfra.spirv.SpirvTypes.typeStride import io.computenode.cyfra.spirv.compilers.DSLCompiler import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.{UniformStructRef, WorkerIndex} -import mem.{FloatMem, GMem, IntMem, Vec4FloatMem} -import org.lwjgl.system.{Configuration, MemoryUtil} +import io.computenode.cyfra.spirvtools.SpirvToolsRunner +import io.computenode.cyfra.vulkan.VulkanContext +import io.computenode.cyfra.vulkan.compute.* +import io.computenode.cyfra.vulkan.executor.SequenceExecutor.* +import io.computenode.cyfra.vulkan.executor.{BufferAction, SequenceExecutor} import izumi.reflect.Tag +import org.lwjgl.system.Configuration -import java.io.FileOutputStream -import java.nio.ByteBuffer -import java.nio.channels.FileChannel import java.util.concurrent.Executors import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} -class GContext: - +class GContext(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()): Configuration.STACK_SIZE.set(1024) // fix lwjgl stack size val vkContext = new VulkanContext() @@ -38,20 +34,17 @@ class GContext: val uniformStruct = uniformStructSchema.fromTree(UniformStructRef) val tree = function.fn .apply(uniformStruct, WorkerIndex, GArray[H](0)) - val shaderCode = DSLCompiler.compile(tree, function.arrayInputs, function.arrayOutputs, uniformStructSchema) - dumpSpvToFile(shaderCode, "program.spv") // TODO remove before release + + val optimizedShaderCode = + spirvToolsRunner.processShaderCodeWithSpirvTools(DSLCompiler.compile(tree, function.arrayInputs, function.arrayOutputs, uniformStructSchema)) + val inOut = 0 to 1 map (Binding(_, InputBufferSize(typeStride(summon[Tag[H]])))) val uniform = Option.when(uniformStructSchema.fields.nonEmpty)(Binding(2, UniformSize(totalStride(uniformStructSchema)))) val layoutInfo = LayoutInfo(Seq(LayoutSet(0, inOut ++ uniform))) - val shader = new Shader(shaderCode, new org.joml.Vector3i(256, 1, 1), layoutInfo, "main", vkContext.device) - new ComputePipeline(shader, vkContext) - } - private def dumpSpvToFile(code: ByteBuffer, path: String): Unit = - val fc: FileChannel = new FileOutputStream("program.spv").getChannel - fc.write(code) - fc.close() - code.rewind() + val shader = Shader(optimizedShaderCode, org.joml.Vector3i(256, 1, 1), layoutInfo, "main", vkContext.device) + ComputePipeline(shader, vkContext) + } def execute[G <: GStruct[G]: Tag: GStructSchema, H <: Value, R <: Value](mem: GMem[H], fn: GFunction[G, H, R])(using uniformContext: UniformContext[G], diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala new file mode 100644 index 00000000..73304350 --- /dev/null +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala @@ -0,0 +1,56 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.spirvtools.SpirvDisassembler.executeSpirvCmd +import io.computenode.cyfra.spirvtools.SpirvTool.{Ignore, Param, ToFile, ToLogger} +import io.computenode.cyfra.utility.Logger.logger + +import java.nio.ByteBuffer + +object SpirvCross extends SpirvTool("spirv-cross"): + + def crossCompileSpirv(shaderCode: ByteBuffer, crossCompilation: CrossCompilation): Option[String] = + crossCompilation match + case Enable(throwOnFail, toolOutput, params) => + val crossCompilationRes = tryCrossCompileSpirv(shaderCode, params) + crossCompilationRes match + case Left(err) if throwOnFail => throw err + case Left(err) => + logger.warn(err.message) + None + case Right(crossCompiledCode) => + toolOutput match + case Ignore => + case toFile @ SpirvTool.ToFile(_) => + toFile.write(crossCompiledCode) + logger.debug(s"Saved cross compiled shader code in ${toFile.filePath}.") + case ToLogger => logger.debug(s"SPIR-V Cross Compilation result:\n$crossCompiledCode") + Some(crossCompiledCode) + case Disable => + logger.debug("SPIR-V cross compilation is disabled.") + None + + private def tryCrossCompileSpirv(shaderCode: ByteBuffer, params: Seq[Param]): Either[SpirvToolError, String] = + val cmd = Seq(toolName) ++ Seq("-") ++ params.flatMap(_.asStringParam.split(" ")) + for + (stdout, stderr, exitCode) <- executeSpirvCmd(shaderCode, cmd) + result <- Either.cond( + exitCode == 0, { + logger.debug("SPIR-V cross compilation succeeded.") + stdout.toString + }, + SpirvToolCrossCompilationFailed(exitCode, stderr.toString), + ) + yield result + + sealed trait CrossCompilation + + case class Enable(throwOnFail: Boolean = false, toolOutput: ToFile | Ignore.type | ToLogger.type = ToLogger, settings: Seq[Param] = Seq.empty) + extends CrossCompilation + + final case class SpirvToolCrossCompilationFailed(exitCode: Int, stderr: String) extends SpirvToolError: + def message: String = + s"""SPIR-V cross compilation failed with exit code $exitCode. + |Cross errors: + |$stderr""".stripMargin + + case object Disable extends CrossCompilation diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala new file mode 100644 index 00000000..e845adde --- /dev/null +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala @@ -0,0 +1,57 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.spirvtools.SpirvTool.{Ignore, Param, ToFile, ToLogger} +import io.computenode.cyfra.utility.Logger.logger + +import java.nio.ByteBuffer +import java.nio.charset.StandardCharsets +import java.nio.file.Files + +object SpirvDisassembler extends SpirvTool("spirv-dis"): + + def disassembleSpirv(shaderCode: ByteBuffer, disassembly: Disassembly): Option[String] = + disassembly match + case Enable(throwOnFail, toolOutput, params) => + val disassemblyResult = tryGetDisassembleSpirv(shaderCode, params) + disassemblyResult match + case Left(err) if throwOnFail => throw err + case Left(err) => + logger.warn(err.message) + None + case Right(disassembledShader) => + toolOutput match + case Ignore => + case toFile @ SpirvTool.ToFile(_) => + toFile.write(disassembledShader) + logger.debug(s"Saved disassembled shader code in ${toFile.filePath}.") + case ToLogger => logger.debug(s"SPIR-V Assembly:\n$disassembledShader") + Some(disassembledShader) + case Disable => + logger.debug("SPIR-V disassembly is disabled.") + None + + private def tryGetDisassembleSpirv(shaderCode: ByteBuffer, params: Seq[Param]): Either[SpirvToolError, String] = + val cmd = Seq(toolName) ++ params.flatMap(_.asStringParam.split(" ")) ++ Seq("-") + for + (stdout, stderr, exitCode) <- executeSpirvCmd(shaderCode, cmd) + result <- Either.cond( + exitCode == 0, { + logger.debug("SPIR-V disassembly succeeded.") + stdout.toString + }, + SpirvToolDisassemblyFailed(exitCode, stderr.toString), + ) + yield result + + sealed trait Disassembly + + final case class SpirvToolDisassemblyFailed(exitCode: Int, stderr: String) extends SpirvToolError: + def message: String = + s"""SPIR-V disassembly failed with exit code $exitCode. + |Disassembly errors: + |$stderr""".stripMargin + + case class Enable(throwOnFail: Boolean = false, toolOutput: ToFile | Ignore.type | ToLogger.type = ToLogger, settings: Seq[Param] = Seq.empty) + extends Disassembly + + case object Disable extends Disassembly diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala new file mode 100644 index 00000000..b42c0651 --- /dev/null +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala @@ -0,0 +1,61 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.spirvtools.SpirvDisassembler.executeSpirvCmd +import io.computenode.cyfra.spirvtools.SpirvTool.{Ignore, Param, ToFile} +import io.computenode.cyfra.utility.Logger.logger + +import java.nio.ByteBuffer + +object SpirvOptimizer extends SpirvTool("spirv-opt"): + + def optimizeSpirv(shaderCode: ByteBuffer, optimization: Optimization): Option[ByteBuffer] = + optimization match + case Enable(throwOnFail, toolOutput, params) => + val optimizationRes = tryGetOptimizeSpirv(shaderCode, params) + optimizationRes match + case Left(err) if throwOnFail => throw err + case Left(err) => + logger.warn(err.message) + None + case Right(optimizedShaderCode) => + toolOutput match + case SpirvTool.Ignore => + case toFile @ SpirvTool.ToFile(_) => + toFile.write(optimizedShaderCode) + logger.debug(s"Saved optimized shader code in ${toFile.filePath}.") + Some(optimizedShaderCode) + case Disable => + logger.debug("SPIR-V optimization is disabled.") + None + + private def tryGetOptimizeSpirv(shaderCode: ByteBuffer, params: Seq[Param]): Either[SpirvToolError, ByteBuffer] = + val cmd = Seq(toolName) ++ params.flatMap(_.asStringParam.split(" ")) ++ Seq("-", "-o", "-") + for + (stdout, stderr, exitCode) <- executeSpirvCmd(shaderCode, cmd) + result <- Either.cond( + exitCode == 0, { + logger.debug("SPIR-V optimization succeeded.") + val optimized = toDirectBuffer(ByteBuffer.wrap(stdout.toByteArray)) + optimized + }, + SpirvToolOptimizationFailed(exitCode, stderr.toString), + ) + yield result + + private def toDirectBuffer(buf: ByteBuffer): ByteBuffer = + val direct = ByteBuffer.allocateDirect(buf.remaining()) + direct.put(buf) + direct.flip() + direct + + sealed trait Optimization + + case class Enable(throwOnFail: Boolean = false, toolOutput: ToFile | Ignore.type = Ignore, settings: Seq[Param] = Seq.empty) extends Optimization + + final case class SpirvToolOptimizationFailed(exitCode: Int, stderr: String) extends SpirvToolError: + def message: String = + s"""SPIR-V optimization failed with exit code $exitCode. + |Optimizer errors: + |$stderr""".stripMargin + + case object Disable extends Optimization diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvTool.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvTool.scala new file mode 100644 index 00000000..729c0efd --- /dev/null +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvTool.scala @@ -0,0 +1,119 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.utility.Logger.logger + +import java.io.* +import java.nio.ByteBuffer +import java.nio.charset.StandardCharsets +import java.nio.file.{Files, Path} +import scala.annotation.tailrec +import scala.sys.process.{ProcessIO, stringSeqToProcess} +import scala.util.{Try, Using} + +abstract class SpirvTool(protected val toolName: String): + + protected def executeSpirvCmd( + shaderCode: ByteBuffer, + cmd: Seq[String], + ): Either[SpirvToolError, (ByteArrayOutputStream, ByteArrayOutputStream, Int)] = + logger.debug(s"SPIR-V cmd $cmd.") + val inputBytes = + val arr = new Array[Byte](shaderCode.remaining()) + shaderCode.get(arr) + shaderCode.rewind() + arr + val inputStream = new ByteArrayInputStream(inputBytes) + val outputStream = new ByteArrayOutputStream() + val errorStream = new ByteArrayOutputStream() + + def safeIOCopy(inStream: InputStream, outStream: OutputStream, description: String): Either[SpirvToolIOError, Unit] = + @tailrec + def loopOverBuffer(buf: Array[Byte]): Unit = + val len = inStream.read(buf) + if len == -1 then () + else + outStream.write(buf, 0, len) + loopOverBuffer(buf) + + Using + .Manager { use => + val in = use(inStream) + val out = use(outStream) + val buf = new Array[Byte](1024) + loopOverBuffer(buf) + out.flush() + } + .toEither + .left + .map(e => SpirvToolIOError(s"$description failed: ${e.getMessage}")) + + def createProcessIO(): Either[SpirvToolError, ProcessIO] = + val inHandler: OutputStream => Unit = + in => + safeIOCopy(inputStream, in, "Writing to stdin") match + case Left(err) => SpirvToolIOError(s"Failed to create ProcessIO: ${err.getMessage}") + case Right(_) => () + + val outHandler: InputStream => Unit = + out => + safeIOCopy(out, outputStream, "Reading stdout") match + case Left(err) => SpirvToolIOError(s"Failed to create ProcessIO: ${err.getMessage}") + case Right(_) => () + + val errHandler: InputStream => Unit = + err => + safeIOCopy(err, errorStream, "Reading stderr") match + case Left(err) => SpirvToolIOError(s"Failed to create ProcessIO: ${err.getMessage}") + case Right(_) => () + + Try { + new ProcessIO(inHandler, outHandler, errHandler) + }.toEither.left.map(e => SpirvToolIOError(s"Failed to create ProcessIO: ${e.getMessage}")) + + for + processIO <- createProcessIO() + process <- Try(cmd.run(processIO)).toEither.left.map(ex => SpirvToolCommandExecutionFailed(s"Failed to execute SPIR-V command: ${ex.getMessage}")) + yield (outputStream, errorStream, process.exitValue()) + + trait SpirvToolError extends RuntimeException: + def message: String + + override def getMessage: String = message + + final case class SpirvToolNotFound(toolName: String) extends SpirvToolError: + def message: String = s"Tool '$toolName' not found in PATH." + + final case class SpirvToolCommandExecutionFailed(details: String) extends SpirvToolError: + def message: String = s"SPIR-V command execution failed: $details" + + final case class SpirvToolIOError(details: String) extends SpirvToolError: + def message: String = s"SPIR-V command encountered IO error: $details" + +object SpirvTool: + sealed trait ToolOutput + + case class Param(value: String): + def asStringParam: String = value + + case class ToFile(filePath: Path) extends ToolOutput: + require(filePath != null, "filePath must not be null") + + def write(outputToSave: String | ByteBuffer): Unit = + Option(filePath.getParent).foreach { dir => + if !Files.exists(dir) then + Files.createDirectories(dir) + logger.debug(s"Created output directory: $dir") + outputToSave match + case stringOutput: String => Files.write(filePath, stringOutput.getBytes(StandardCharsets.UTF_8)) + case byteBuffer: ByteBuffer => dumpByteBufferToFile(byteBuffer, filePath) + } + + private def dumpByteBufferToFile(code: ByteBuffer, path: Path): Unit = + Using.resource(new FileOutputStream(path.toAbsolutePath.toString).getChannel) { fc => + fc.write(code) + } + code.rewind() + + case object ToLogger extends ToolOutput + + case object Ignore extends ToolOutput diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvToolsRunner.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvToolsRunner.scala new file mode 100644 index 00000000..234fca7b --- /dev/null +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvToolsRunner.scala @@ -0,0 +1,35 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.spirvtools.SpirvTool.{Ignore, ToFile} +import io.computenode.cyfra.utility.Logger.logger + +import java.nio.ByteBuffer + +class SpirvToolsRunner( + val validator: SpirvValidator.Validation = SpirvValidator.Enable(), + val optimizer: SpirvOptimizer.Optimization = SpirvOptimizer.Disable, + val disassembler: SpirvDisassembler.Disassembly = SpirvDisassembler.Disable, + val crossCompilation: SpirvCross.CrossCompilation = SpirvCross.Disable, + val originalSpirvOutput: ToFile | Ignore.type = Ignore, +): + + def processShaderCodeWithSpirvTools(shaderCode: ByteBuffer): ByteBuffer = + def runTools(code: ByteBuffer): Unit = + SpirvDisassembler.disassembleSpirv(code, disassembler) + SpirvCross.crossCompileSpirv(code, crossCompilation) + SpirvValidator.validateSpirv(code, validator) + + originalSpirvOutput match + case toFile @ SpirvTool.ToFile(_) => + toFile.write(shaderCode) + logger.debug(s"Saved original shader code in ${toFile.filePath}.") + case Ignore => + + val optimized = SpirvOptimizer.optimizeSpirv(shaderCode, optimizer) + optimized match + case Some(optimizedCode) => + runTools(optimizedCode) + optimizedCode + case None => + runTools(shaderCode) + shaderCode diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvValidator.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvValidator.scala new file mode 100644 index 00000000..d1f0b3c4 --- /dev/null +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvValidator.scala @@ -0,0 +1,38 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.spirvtools.SpirvDisassembler.executeSpirvCmd +import io.computenode.cyfra.spirvtools.SpirvTool.Param +import io.computenode.cyfra.utility.Logger.logger + +import java.nio.ByteBuffer + +object SpirvValidator extends SpirvTool("spirv-val"): + + def validateSpirv(shaderCode: ByteBuffer, validation: Validation): Unit = + validation match + case Enable(throwOnFail, params) => + val validationRes = tryValidateSpirv(shaderCode, params) + validationRes match + case Left(err) if throwOnFail => throw err + case Left(err) => logger.warn(err.message) + case Right(_) => () + case Disable => logger.debug("SPIR-V validation is disabled.") + + private def tryValidateSpirv(shaderCode: ByteBuffer, params: Seq[Param]): Either[SpirvToolError, Unit] = + val cmd = Seq(toolName) ++ params.flatMap(_.asStringParam.split(" ")) ++ Seq("-") + for + (stdout, stderr, exitCode) <- executeSpirvCmd(shaderCode, cmd) + _ <- Either.cond(exitCode == 0, logger.debug("SPIR-V validation succeeded."), SpirvToolValidationFailed(exitCode, stderr.toString())) + yield () + + sealed trait Validation + + case class Enable(throwOnFail: Boolean = false, settings: Seq[Param] = Seq.empty) extends Validation + + final case class SpirvToolValidationFailed(exitCode: Int, stderr: String) extends SpirvToolError: + def message: String = + s"""SPIR-V validation failed with exit code $exitCode. + |Validation errors: + |$stderr""".stripMargin + + case object Disable extends Validation diff --git a/cyfra-spirv-tools/src/test/resources/optimized.glsl b/cyfra-spirv-tools/src/test/resources/optimized.glsl new file mode 100644 index 00000000..5c37820b --- /dev/null +++ b/cyfra-spirv-tools/src/test/resources/optimized.glsl @@ -0,0 +1,53 @@ +#version 450 +layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in; + +layout(binding = 1, std430) buffer BufferOut +{ + vec4 _m0[]; +} dataOut; + +void main() +{ + vec2 rotatedUv = vec2(float((int(gl_GlobalInvocationID.x) % 4096) - 2048) * 0.000732421875, float((int(gl_GlobalInvocationID.x) / 4096) - 2048) * 0.000732421875); + int _309; + vec2 _312; + _312 = vec2(dot(rotatedUv, vec2(0.4999999701976776123046875, 0.866025447845458984375)), dot(rotatedUv, vec2(-vec2(0.4999999701976776123046875, 0.866025447845458984375).y, vec2(0.4999999701976776123046875, 0.866025447845458984375).x))) * 0.89999997615814208984375; + _309 = 0; + bool _263; + vec2 _281; + int _283; + int _315; + bool _307 = true; + int _308 = 0; + for (; _307 && (_308 < 1000); _312 = _281, _309 = _315, _308 = _283, _307 = _263) + { + _263 = length(_312) < 2.0; + if (_263) + { + _315 = _309 + 1; + } + else + { + _315 = _309; + } + float _268 = _312.x; + float _269 = _312.y; + _281 = vec2((_268 * _268) - (_269 * _269), (2.0 * _268) * _269) + vec2(0.3549999892711639404296875); + _283 = _308 + 1; + } + vec4 _311; + if (_309 > 20) + { + float f = float(_309) * 0.00999999977648258209228515625; + float _336 = (f > 1.0) ? 1.0 : f; + float _289 = 1.0 - _336; + vec3 _306 = ((vec3(0.0313725508749485015869140625, 0.086274512112140655517578125, 0.407843172550201416015625) * (_289 * _289)) + (vec3(0.2431372702121734619140625, 0.3215686380863189697265625, 0.780392229557037353515625) * ((2.0 * _336) * _289))) + (vec3(0.866666734218597412109375, 0.913725554943084716796875, 1.0) * (_336 * _336)); + _311 = vec4(_306.x, _306.y, _306.z, 1.0); + } + else + { + _311 = vec4(0.0313725508749485015869140625, 0.086274512112140655517578125, 0.4078431427478790283203125, 1.0); + } + dataOut._m0[int(gl_GlobalInvocationID.x)] = _311; +} + diff --git a/cyfra-spirv-tools/src/test/resources/optimized.spv b/cyfra-spirv-tools/src/test/resources/optimized.spv new file mode 100644 index 0000000000000000000000000000000000000000..63ab9b72078df757ff382f653181047d6da16eba GIT binary patch literal 2948 zcmZXWO>9+F5XVn@`wD5RfRri%rlm1ae5t5KiO?2^T7)7+3am6VmS?I$BfN*Gi99ro ziisvrkhsPe7bXy6VqCH@?$C{Hj9ZNhKO!HJX#M@}JLmCgFHC3VKmVC~&dj-|&6;}` zgwPa<$gZZ4KTAS0UI^`>HP^!X*1 za_G78|}!d=w|OpIzu~ z#MqrV7V`P)uZX@}ee28j+;sEPwRu*=eHRBcuho?6me7XQ7B{~m+SW6F5!$%;QYzJI zc>-&7S7F(g9^@`;d!ldd2wJ|_hUnW9vHS4d<1WM(B>(A}TlaTIzewlpi~To8o-y-W z`xxRnlfMVsLFwC%z51a#l>B|UA2ucavo*h-zh8gh&HU$aKe+V8V9KAwFO^DpJ>UNV z@-t0I^N$BCv4_s1fTX=z zdn3*dpFdOI+W`LT?Cf9>rsri4Urb)YhOpg}Qlx`D=uKd*)3v!CdzRMw7_l4IkJb18 zIR3}y&)5AY@W1(bc*r?#}uqzSs9Vz!Jn7I7+ z#y8jR_LGQZ_~sb9N^e%7U5C#NeB&*Mxa-&M;JiDhR&4%9H z#`b|<_;O4*Qm{TOwx7 zbe3)db8YeywiH{glCVx}IgPw!_~y%di*?(FE^N8hNN3^>Y;pM~;5lz+Ebcv&_U!ze zN!qi$w=e3(b7TKMi~XIZmOb#kw7+N3KK9qxhsZg^I@;+w^KSt2(*FFLMa=u+t62La zzW83`(>Ui*;^Jb)(!P7Z#f+z#tFi5EBX$p%xctOh6a7Z42xgw*cjTSghwZ&;jfCBg z?Hy{3gssIML9AiF&3yn{t~C<&Ahx*tbVg3W75Dd7!cIrbxg=~RVxF&2PHYeQ3?eSy zI`+f4okiP!=g{bjdzQ_8gm;?njQl+$cQZZjMSq0&cZ2V$AcM?V%$$Gt>eeIw0UMnQ Aj{pDw literal 0 HcmV?d00001 diff --git a/cyfra-spirv-tools/src/test/resources/optimized.spvasm b/cyfra-spirv-tools/src/test/resources/optimized.spvasm new file mode 100644 index 00000000..dd916bfe --- /dev/null +++ b/cyfra-spirv-tools/src/test/resources/optimized.spvasm @@ -0,0 +1,179 @@ +; SPIR-V +; Version: 1.0 +; Generator: LunarG; 44 +; Bound: 337 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %4 "main" %gl_GlobalInvocationID + OpExecutionMode %4 LocalSize 256 1 1 + OpSource GLSL 450 + OpName %BufferOut "BufferOut" + OpName %dataOut "dataOut" + OpName %ff "ff" + OpName %y "y" + OpName %function "function" + OpName %x "x" + OpName %function_0 "function" + OpName %function_1 "function" + OpName %y_0 "y" + OpName %f "f" + OpName %rotatedUv "rotatedUv" + OpName %function_2 "function" + OpName %function_3 "function" + OpName %x_0 "x" + OpName %y_1 "y" + OpName %rotatedUv_0 "rotatedUv" + OpName %x_1 "x" + OpName %function_4 "function" + OpName %y_2 "y" + OpName %ff_0 "ff" + OpName %y_3 "y" + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize + OpDecorate %_runtimearr_v4float ArrayStride 16 + OpMemberDecorate %BufferOut 0 Offset 0 + OpDecorate %BufferOut BufferBlock + OpDecorate %dataOut DescriptorSet 0 + OpDecorate %dataOut Binding 1 + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %v3uint = OpTypeVector %uint 3 + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 + %v3float = OpTypeVector %float 3 + %v4float = OpTypeVector %float 4 +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float + %int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int + %v3int = OpTypeVector %int 3 +%_ptr_Input_v3int = OpTypePointer Input %v3int + %void = OpTypeVoid + %3 = OpTypeFunction %void +%_runtimearr_v4float = OpTypeRuntimeArray %v4float + %BufferOut = OpTypeStruct %_runtimearr_v4float +%_ptr_Uniform_BufferOut = OpTypePointer Uniform %BufferOut + %dataOut = OpVariable %_ptr_Uniform_BufferOut Uniform + %uint_256 = OpConstant %uint 256 + %uint_1 = OpConstant %uint 1 + %uint_1_0 = OpConstant %uint 1 +%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_256 %uint_1 %uint_1_0 + %int_1 = OpConstant %int 1 + %int_4096 = OpConstant %int 4096 + %float_1 = OpConstant %float 1 + %float_2 = OpConstant %float 2 + %int_0 = OpConstant %int 0 + %int_2048 = OpConstant %int 2048 +%float_0_354999989 = OpConstant %float 0.354999989 +%float_0_899999976 = OpConstant %float 0.899999976 + %int_1000 = OpConstant %int 1000 + %int_2 = OpConstant %int 2 +%float_0_0313725509 = OpConstant %float 0.0313725509 +%float_0_0862745121 = OpConstant %float 0.0862745121 +%float_0_407843143 = OpConstant %float 0.407843143 + %int_20 = OpConstant %int 20 + %true = OpConstantTrue %bool +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3int Input +%float_0_866025448 = OpConstant %float 0.866025448 +%float_0_49999997 = OpConstant %float 0.49999997 + %318 = OpConstantComposite %v2float %float_0_49999997 %float_0_866025448 + %319 = OpConstantComposite %v2float %float_0_354999989 %float_0_354999989 + %320 = OpConstantComposite %v4float %float_0_0313725509 %float_0_0862745121 %float_0_407843143 %float_1 +%float_0_24313727 = OpConstant %float 0.24313727 +%float_0_321568638 = OpConstant %float 0.321568638 +%float_0_78039223 = OpConstant %float 0.78039223 + %327 = OpConstantComposite %v3float %float_0_24313727 %float_0_321568638 %float_0_78039223 +%float_0_407843173 = OpConstant %float 0.407843173 + %329 = OpConstantComposite %v3float %float_0_0313725509 %float_0_0862745121 %float_0_407843173 +%float_0_866666734 = OpConstant %float 0.866666734 +%float_0_913725555 = OpConstant %float 0.913725555 + %332 = OpConstantComposite %v3float %float_0_866666734 %float_0_913725555 %float_1 +%float_0_000732421875 = OpConstant %float 0.000732421875 +%float_0_00999999978 = OpConstant %float 0.00999999978 + %4 = OpFunction %void None %3 + %115 = OpLabel + %116 = OpAccessChain %_ptr_Input_int %gl_GlobalInvocationID %int_0 + %y_0 = OpLoad %int %116 + %x_0 = OpSDiv %int %y_0 %int_4096 + %x_1 = OpSMod %int %y_0 %int_4096 + %y = OpISub %int %x_0 %int_2048 + %x = OpISub %int %x_1 %int_2048 + %y_3 = OpConvertSToF %float %y + %y_1 = OpConvertSToF %float %x + %y_2 = OpFMul %float %y_3 %float_0_000732421875 +%rotatedUv_0 = OpFMul %float %y_1 %float_0_000732421875 + %rotatedUv = OpCompositeConstruct %v2float %rotatedUv_0 %y_2 + %239 = OpVectorExtractDynamic %float %318 %int_1 + %240 = OpVectorExtractDynamic %float %318 %int_0 + %241 = OpFNegate %float %239 + %242 = OpCompositeConstruct %v2float %241 %240 + %244 = OpDot %float %rotatedUv %242 + %245 = OpDot %float %rotatedUv %318 + %246 = OpCompositeConstruct %v2float %245 %244 + %247 = OpVectorTimesScalar %v2float %246 %float_0_899999976 + OpBranch %254 + %254 = OpLabel + %312 = OpPhi %v2float %247 %115 %281 %284 + %309 = OpPhi %int %int_0 %115 %315 %284 + %308 = OpPhi %int %int_0 %115 %283 %284 + %307 = OpPhi %bool %true %115 %263 %284 + %258 = OpSLessThan %bool %308 %int_1000 + %259 = OpLogicalAnd %bool %307 %258 + OpLoopMerge %285 %284 None + OpBranchConditional %259 %260 %285 + %260 = OpLabel + %262 = OpExtInst %float %1 Length %312 + %263 = OpFOrdLessThan %bool %262 %float_2 + OpSelectionMerge %267 None + OpBranchConditional %263 %264 %267 + %264 = OpLabel + %266 = OpIAdd %int %309 %int_1 + OpBranch %267 + %267 = OpLabel + %315 = OpPhi %int %309 %260 %266 %264 + %268 = OpVectorExtractDynamic %float %312 %int_0 + %269 = OpVectorExtractDynamic %float %312 %int_1 + %274 = OpFMul %float %float_2 %268 + %275 = OpFMul %float %269 %269 + %276 = OpFMul %float %268 %268 + %277 = OpFMul %float %274 %269 + %278 = OpFSub %float %276 %275 + %280 = OpCompositeConstruct %v2float %278 %277 + %281 = OpFAdd %v2float %280 %319 + %283 = OpIAdd %int %308 %int_1 + OpBranch %284 + %284 = OpLabel + OpBranch %254 + %285 = OpLabel + %function_1 = OpSGreaterThan %bool %309 %int_20 + OpSelectionMerge %150 None + OpBranchConditional %function_1 %151 %function + %151 = OpLabel + %ff_0 = OpConvertSToF %float %309 + %f = OpFMul %float %ff_0 %float_0_00999999978 + %ff = OpFOrdGreaterThan %bool %f %float_1 + %336 = OpSelect %float %ff %float_1 %f + %289 = OpFSub %float %float_1 %336 + %290 = OpFMul %float %float_2 %336 + %296 = OpFMul %float %290 %289 + %298 = OpFMul %float %289 %289 + %300 = OpFMul %float %336 %336 + %302 = OpVectorTimesScalar %v3float %327 %296 + %303 = OpVectorTimesScalar %v3float %329 %298 + %304 = OpVectorTimesScalar %v3float %332 %300 + %305 = OpFAdd %v3float %303 %302 + %306 = OpFAdd %v3float %305 %304 + %function_4 = OpVectorExtractDynamic %float %306 %int_2 + %function_0 = OpVectorExtractDynamic %float %306 %int_1 + %function_2 = OpVectorExtractDynamic %float %306 %int_0 + %function_3 = OpCompositeConstruct %v4float %function_2 %function_0 %function_4 %float_1 + OpBranch %150 + %function = OpLabel + OpBranch %150 + %150 = OpLabel + %311 = OpPhi %v4float %function_3 %151 %320 %function + %154 = OpAccessChain %_ptr_Uniform_v4float %dataOut %int_0 %y_0 + OpStore %154 %311 + OpReturn + OpFunctionEnd diff --git a/cyfra-spirv-tools/src/test/resources/original.spv b/cyfra-spirv-tools/src/test/resources/original.spv new file mode 100644 index 0000000000000000000000000000000000000000..d11e1e51ba3e4d3d035a863ca3267c0e26a93c0a GIT binary patch literal 6396 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 literal 0 HcmV?d00001 diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvCrossTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvCrossTest.scala new file mode 100644 index 00000000..6a21f550 --- /dev/null +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvCrossTest.scala @@ -0,0 +1,19 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.spirvtools.SpirvCross.Enable +import munit.FunSuite + +class SpirvCrossTest extends FunSuite { + + test("SPIR-V cross compilation succeeded") { + val shaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") + val glslShader = SpirvCross.crossCompileSpirv(shaderCode, crossCompilation = Enable(throwOnFail = true)) match { + case None => fail("Failed to disassemble shader.") + case Some(assembly) => assembly + } + + val referenceGlsl = SpirvTestUtils.loadResourceAsString("optimized.glsl") + + assertEquals(glslShader, referenceGlsl) + } +} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvDisassemblerTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvDisassemblerTest.scala new file mode 100644 index 00000000..0138b0cd --- /dev/null +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvDisassemblerTest.scala @@ -0,0 +1,19 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.spirvtools.SpirvDisassembler.Enable +import munit.FunSuite + +class SpirvDisassemblerTest extends FunSuite { + + test("SPIR-V disassembly succeeded") { + val shaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") + val assembly = SpirvDisassembler.disassembleSpirv(shaderCode, disassembly = Enable(throwOnFail = true)) match { + case None => fail("Failed to disassemble shader.") + case Some(assembly) => assembly + } + + val referenceAssembly = SpirvTestUtils.loadResourceAsString("optimized.spvasm") + + assertEquals(assembly, referenceAssembly) + } +} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvOptimizerTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvOptimizerTest.scala new file mode 100644 index 00000000..5557cfe0 --- /dev/null +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvOptimizerTest.scala @@ -0,0 +1,24 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.spirvtools.SpirvDisassembler.Enable +import io.computenode.cyfra.spirvtools.SpirvTool.Param +import munit.FunSuite + +import java.nio.ByteBuffer + +class SpirvOptimizerTest extends FunSuite { + + test("SPIR-V optimization succeeded") { + val shaderCode = SpirvTestUtils.loadShaderFromResources("original.spv") + val optimizedShaderCode = SpirvOptimizer.optimizeSpirv(shaderCode, SpirvOptimizer.Enable(throwOnFail = true, settings = Seq(Param("-O")))) match { + case None => fail("Failed to optimize shader code.") + case Some(optimizedShaderCode) => optimizedShaderCode + } + val optimizedAssembly = SpirvDisassembler.disassembleSpirv(optimizedShaderCode, disassembly = Enable(throwOnFail = true)) + + val referenceOptimizedShaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") + val referenceAssembly = SpirvDisassembler.disassembleSpirv(referenceOptimizedShaderCode, disassembly = Enable(throwOnFail = true)) + + assertEquals(optimizedAssembly, referenceAssembly) + } +} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvTestUtils.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvTestUtils.scala new file mode 100644 index 00000000..ccb74760 --- /dev/null +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvTestUtils.scala @@ -0,0 +1,31 @@ +package io.computenode.cyfra.spirvtools + +import java.nio.ByteBuffer +import java.nio.file.{Files, Paths} +import scala.io.Source + +object SpirvTestUtils { + def loadShaderFromResources(path: String): ByteBuffer = { + val resourceUrl = getClass.getClassLoader.getResource(path) + require(resourceUrl != null, s"Resource not found: $path") + val bytes = Files.readAllBytes(Paths.get(resourceUrl.toURI)) + ByteBuffer.wrap(bytes) + } + + def loadResourceAsString(path: String): String = { + val source = Source.fromResource(path) + try source.mkString + finally source.close() + } + + def corruptMagicNumber(original: ByteBuffer): ByteBuffer = { + val corrupted = ByteBuffer.allocate(original.capacity()) + original.rewind() + corrupted.put(original) + corrupted.rewind() + corrupted.put(0, 0.toByte) + + corrupted.rewind() + corrupted + } +} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvToolTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvToolTest.scala new file mode 100644 index 00000000..b819aec0 --- /dev/null +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvToolTest.scala @@ -0,0 +1,71 @@ +package io.computenode.cyfra.spirvtools + +import munit.FunSuite + +import java.io.{ByteArrayOutputStream, File} +import java.nio.ByteBuffer +import java.nio.file.Files + +class SpirvToolTest extends FunSuite { + private def isWindows: Boolean = + System.getProperty("os.name").toLowerCase.contains("win") + + class TestSpirvTool(toolName: String) extends SpirvTool(toolName) { + def runExecuteCmd(input: ByteBuffer, cmd: Seq[String]): Either[SpirvToolError, (ByteArrayOutputStream, ByteArrayOutputStream, Int)] = + executeSpirvCmd(input, cmd) + } + + if !isWindows then + test("executeSpirvCmd returns exit code and output streams on valid command") { + val tool = new TestSpirvTool("cat") + + val inputBytes = "hello SPIR-V".getBytes("UTF-8") + val byteBuffer = ByteBuffer.wrap(inputBytes) + + val cmd = Seq("cat") + + val result = tool.runExecuteCmd(byteBuffer, cmd) + assert(result.isRight) + + val (outStream, errStream, exitCode) = result.getOrElse(fail("Execution failed")) + val outputString = outStream.toString("UTF-8") + + assertEquals(exitCode, 0) + assert(outputString == "hello SPIR-V") + assertEquals(errStream.size(), 0) + } + + test("executeSpirvCmd returns non-zero exit code on invalid command") { + val tool = new TestSpirvTool("invalid-cmd") + + val byteBuffer = ByteBuffer.wrap("".getBytes("UTF-8")) + val cmd = Seq("invalid-cmd") + + val result = tool.runExecuteCmd(byteBuffer, cmd) + assert(result.isLeft) + val error = result.left.getOrElse(fail("Should have error")) + assert(error.getMessage.contains("Failed to execute SPIR-V command")) + } + + test("dumpSpvToFile writes ByteBuffer content to file") { + val tmpFile = Files.createTempFile("spirv-dump-test", ".spv") + + val data = "SPIRV binary data".getBytes("UTF-8") + val buffer = ByteBuffer.wrap(data) + + val tmp = SpirvTool.ToFile(tmpFile) + tmp.write(buffer) + + val fileBytes = Files.readAllBytes(tmpFile) + assert(java.util.Arrays.equals(data, fileBytes)) + + assert(buffer.position() == 0) + + Files.deleteIfExists(tmpFile) + } + + test("Param.asStringParam returns correct string") { + val param = SpirvTool.Param("test-value") + assertEquals(param.asStringParam, "test-value") + } +} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvValidatorTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvValidatorTest.scala new file mode 100644 index 00000000..df49b5c3 --- /dev/null +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvValidatorTest.scala @@ -0,0 +1,33 @@ +package io.computenode.cyfra.spirvtools + +import io.computenode.cyfra.spirvtools.SpirvValidator.Enable +import munit.FunSuite + +class SpirvValidatorTest extends FunSuite { + + test("SPIR-V validation succeeded") { + val shaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") + + try { + SpirvValidator.validateSpirv(shaderCode, validation = Enable(throwOnFail = true)) + assert(true) + } catch { + case e: Throwable => + fail(s"Validation unexpectedly failed: ${e.getMessage}") + } + } + + test("SPIR-V validation fail") { + val shaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") + val corruptedShaderCode = SpirvTestUtils.corruptMagicNumber(shaderCode) + + try { + SpirvValidator.validateSpirv(corruptedShaderCode, validation = Enable(throwOnFail = true)) + fail(s"Validation was supposed to fail.") + } catch { + case e: Throwable => + val result = e.getMessage + assertEquals(result, "SPIR-V validation failed with exit code 1.\nValidation errors:\nerror: line 0: Invalid SPIR-V magic number.\n") + } + } +} diff --git a/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/Logger.scala b/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/Logger.scala index 68cae972..296d9882 100644 --- a/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/Logger.scala +++ b/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/Logger.scala @@ -1,6 +1,6 @@ package io.computenode.cyfra.utility -import org.slf4j.LoggerFactory +import org.slf4j.{Logger, LoggerFactory} object Logger: - val logger = LoggerFactory.getLogger("Cyfra") + val logger: Logger = LoggerFactory.getLogger("Cyfra") From 6392ce749bbe7d4bc2f1a7a2d80eb02e83c6c093 Mon Sep 17 00:00:00 2001 From: Soleod Date: Fri, 20 Jun 2025 10:21:59 +0200 Subject: [PATCH 07/59] Syntax modernization and cleanup (#52) * Added "-feature", "-deprecation", "-unchecked", "-language:implicitConversions" to scalacOptions Whole code base should now use Scala3 new syntax and significant indents. If anyone sees unnecessary {} that I missed, please get rid of them. --- build.sbt | 1 + .../cyfra/spirv/BlockBuilder.scala | 6 +- .../io/computenode/cyfra/spirv/Context.scala | 3 +- .../io/computenode/cyfra/spirv/Opcodes.scala | 151 +++------ .../computenode/cyfra/spirv/SpirvTypes.scala | 16 +- .../cyfra/spirv/compilers/DSLCompiler.scala | 22 +- .../spirv/compilers/ExpressionCompiler.scala | 41 +-- .../spirv/compilers/ExtFunctionCompiler.scala | 7 +- .../spirv/compilers/FunctionCompiler.scala | 11 +- .../cyfra/spirv/compilers/GSeqCompiler.scala | 11 +- .../spirv/compilers/GStructCompiler.scala | 3 +- .../compilers/SpirvProgramCompiler.scala | 25 +- .../cyfra/spirv/compilers/WhenCompiler.scala | 14 +- .../io/computenode/cyfra/dsl/Expression.scala | 20 +- .../cyfra/dsl/collections/GArray2D.scala | 3 +- .../cyfra/dsl/collections/GSeq.scala | 20 +- .../computenode/cyfra/dsl/library/Color.scala | 6 +- .../cyfra/dsl/library/Functions.scala | 4 +- .../cyfra/dsl/library/Math3D.scala | 18 +- .../computenode/cyfra/dsl/macros/FnCall.scala | 10 +- .../computenode/cyfra/dsl/macros/Source.scala | 6 +- .../computenode/cyfra/dsl/macros/Util.scala | 6 +- ...icTests.scala => ArithmeticsE2eTest.scala} | 0 ...ionsTests.scala => FunctionsE2eTest.scala} | 0 ...StructTests.scala => GStructE2eTest.scala} | 0 .../{GSeqTests.scala => GseqE2eTest.scala} | 3 +- .../io/computenode/cyfra/e2e/ImageTests.scala | 8 +- .../{WhenTests.scala => WhenE2eTest.scala} | 0 .../cyfra/e2e/juliaset/JuliaSet.scala | 3 +- .../samples/cyfra/foton/AnimatedJulia.scala | 9 +- .../cyfra/foton/AnimatedRaytrace.scala | 7 +- .../samples/cyfra/oldsamples/Raytracing.scala | 301 +++++++++--------- .../samples/cyfra/slides/1sample.scala | 10 +- .../samples/cyfra/slides/2simpleray.scala | 25 +- .../samples/cyfra/slides/3rays.scala | 67 ++-- .../samples/cyfra/slides/4random.scala | 66 ++-- .../foton/animation/AnimatedFunction.scala | 12 - .../animation/AnimatedFunctionRenderer.scala | 15 +- .../foton/animation/AnimationFunctions.scala | 7 +- .../foton/animation/AnimationRenderer.scala | 19 +- .../cyfra/foton/rt/ImageRtRenderer.scala | 21 +- .../cyfra/foton/rt/RtRenderer.scala | 109 +++---- .../io/computenode/cyfra/foton/rt/Scene.scala | 3 +- .../rt/animation/AnimationRtRenderer.scala | 16 +- .../cyfra/foton/rt/shapes/Box.scala | 12 +- .../cyfra/foton/rt/shapes/Plane.scala | 13 +- .../cyfra/foton/rt/shapes/Quad.scala | 32 +- .../cyfra/foton/rt/shapes/Shape.scala | 5 +- .../foton/rt/shapes/ShapeCollection.scala | 12 +- .../cyfra/foton/rt/shapes/Sphere.scala | 29 +- .../cyfra/runtime/Executable.scala | 3 +- .../computenode/cyfra/runtime/GContext.scala | 3 +- .../computenode/cyfra/runtime/GFunction.scala | 3 +- .../cyfra/runtime/mem/FloatMem.scala | 4 +- .../computenode/cyfra/runtime/mem/GMem.scala | 14 +- .../cyfra/runtime/mem/IntMem.scala | 1 - .../cyfra/runtime/mem/Vec4FloatMem.scala | 7 +- .../cyfra/spirvtools/SpirvDisassembler.scala | 2 - .../cyfra/spirvtools/SpirvCrossTest.scala | 9 +- .../spirvtools/SpirvDisassemblerTest.scala | 9 +- .../cyfra/spirvtools/SpirvOptimizerTest.scala | 9 +- .../cyfra/spirvtools/SpirvTestUtils.scala | 12 +- .../cyfra/spirvtools/SpirvToolTest.scala | 18 +- .../cyfra/spirvtools/SpirvValidatorTest.scala | 19 +- .../cyfra/utility/ImageUtility.scala | 10 +- .../computenode/cyfra/utility/Utility.scala | 1 - .../vscode}/VscodeConnection.scala | 3 +- .../cyfra/vulkan/VulkanContext.scala | 9 +- .../cyfra/vulkan/command/CommandPool.scala | 28 +- .../cyfra/vulkan/command/Fence.scala | 35 +- .../vulkan/command/OneTimeCommandPool.scala | 4 +- .../cyfra/vulkan/command/Queue.scala | 16 +- .../cyfra/vulkan/command/Semaphore.scala | 15 +- .../vulkan/command/StandardCommandPool.scala | 3 +- .../vulkan/compute/ComputePipeline.scala | 28 +- .../cyfra/vulkan/compute/Shader.scala | 26 +- .../cyfra/vulkan/core/DebugCallback.scala | 26 +- .../cyfra/vulkan/core/Device.scala | 167 +++++----- .../cyfra/vulkan/core/Instance.scala | 27 +- .../vulkan/executor/AbstractExecutor.scala | 41 +-- .../cyfra/vulkan/executor/MapExecutor.scala | 24 +- .../vulkan/executor/SequenceExecutor.scala | 42 +-- .../cyfra/vulkan/memory/Allocator.scala | 7 +- .../cyfra/vulkan/memory/Buffer.scala | 34 +- .../cyfra/vulkan/memory/DescriptorPool.scala | 20 +- .../cyfra/vulkan/memory/DescriptorSet.scala | 14 +- .../computenode/cyfra/vulkan/util/Util.scala | 3 +- .../vulkan/util/VulkanAssertionError.scala | 3 +- .../cyfra/vulkan/util/VulkanObject.scala | 7 +- .../vulkan/util/VulkanObjectHandle.scala | 3 +- 90 files changed, 746 insertions(+), 1171 deletions(-) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{ArithmeticTests.scala => ArithmeticsE2eTest.scala} (100%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{FunctionsTests.scala => FunctionsE2eTest.scala} (100%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{GStructTests.scala => GStructE2eTest.scala} (100%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{GSeqTests.scala => GseqE2eTest.scala} (97%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{WhenTests.scala => WhenE2eTest.scala} (100%) rename cyfra-vscode/src/main/scala/io/computenode/{vscode' => cyfra/vscode}/VscodeConnection.scala (95%) diff --git a/build.sbt b/build.sbt index 2fef2351..8005cccd 100644 --- a/build.sbt +++ b/build.sbt @@ -36,6 +36,7 @@ lazy val vulkanNatives = else Seq.empty lazy val commonSettings = Seq( + scalacOptions ++= Seq("-feature", "-deprecation", "-unchecked", "-language:implicitConversions"), libraryDependencies ++= Seq( "dev.zio" % "izumi-reflect_3" % "2.3.10", "com.lihaoyi" % "pprint_3" % "0.9.0", diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala index b4a6a302..2886e837 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/BlockBuilder.scala @@ -1,12 +1,8 @@ package io.computenode.cyfra.spirv -import io.computenode.cyfra.dsl.Expression.{E, FunctionCall} -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.macros.Source -import izumi.reflect.Tag +import io.computenode.cyfra.dsl.Expression.E import scala.collection.mutable -import scala.quoted.Expr private[cyfra] object BlockBuilder: diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala index a8fb18d2..974f045f 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala @@ -1,9 +1,8 @@ package io.computenode.cyfra.spirv import io.computenode.cyfra.dsl.macros.FnCall.FnIdentifier -import io.computenode.cyfra.dsl.macros.Source -import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction import io.computenode.cyfra.spirv.SpirvConstants.HEADER_REFS_TOP +import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction import io.computenode.cyfra.spirv.compilers.SpirvProgramCompiler.ArrayBufferBlock import izumi.reflect.Tag import izumi.reflect.macrortti.LightTypeTag diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Opcodes.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Opcodes.scala index 38809183..1f8c4cb6 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Opcodes.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Opcodes.scala @@ -2,33 +2,30 @@ package io.computenode.cyfra.spirv import java.nio.charset.StandardCharsets -private[cyfra] object Opcodes { +private[cyfra] object Opcodes: def intToBytes(i: Int): List[Byte] = List[Byte]((i >>> 24).asInstanceOf[Byte], (i >>> 16).asInstanceOf[Byte], (i >>> 8).asInstanceOf[Byte], (i >>> 0).asInstanceOf[Byte]) - private[cyfra] trait Words { + private[cyfra] trait Words: def toWords: List[Byte] def length: Int - } - private[cyfra] case class Word(bytes: Array[Byte]) extends Words { + private[cyfra] case class Word(bytes: Array[Byte]) extends Words: def toWords: List[Byte] = bytes.toList def length = 1 override def toString = s"Word(${bytes.mkString(", ")}${if bytes.length == 4 then s" [i = ${BigInt(bytes).toInt}])" else ""}" - } - private[cyfra] case class WordVariable(name: String) extends Words { + private[cyfra] case class WordVariable(name: String) extends Words: def toWords: List[Byte] = List(-1, -1, -1, -1) def length = 1 - } - private[cyfra] case class Instruction(code: Code, operands: List[Words]) extends Words { + private[cyfra] case class Instruction(code: Code, operands: List[Words]) extends Words: override def toWords: List[Byte] = code.toWords.take(2) ::: intToBytes(length).reverse.take(2) ::: operands.flatMap(_.toWords) @@ -41,38 +38,32 @@ private[cyfra] object Opcodes { }) override def toString: String = s"${code.mnemo} ${operands.mkString(", ")}" - } - private[cyfra] case class Code(mnemo: String, opcode: Int) extends Words { + private[cyfra] case class Code(mnemo: String, opcode: Int) extends Words: override def toWords: List[Byte] = intToBytes(opcode).reverse override def length: Int = 1 - } - private[cyfra] case class Text(text: String) extends Words { - override def toWords: List[Byte] = { + private[cyfra] case class Text(text: String) extends Words: + override def toWords: List[Byte] = val textBytes = text.getBytes(StandardCharsets.UTF_8).toList val complBytesLength = 4 - (textBytes.length % 4) val complBytes = List.fill[Byte](complBytesLength)(0) textBytes ::: complBytes - } override def length: Int = toWords.length / 4 - } - private[cyfra] case class IntWord(i: Int) extends Words { + private[cyfra] case class IntWord(i: Int) extends Words: override def toWords: List[Byte] = intToBytes(i).reverse override def length: Int = 1 - } - private[cyfra] case class ResultRef(result: Int) extends Words { + private[cyfra] case class ResultRef(result: Int) extends Words: override def toWords: List[Byte] = intToBytes(result).reverse override def length: Int = 1 override def toString: String = s"%$result" - } val MagicNumber = Code("MagicNumber", 0x07230203) val Version = Code("Version", 0x00010000) @@ -81,16 +72,15 @@ private[cyfra] object Opcodes { val OpCodeMask = Code("OpCodeMask", 0xffff) val WordCountShift = Code("WordCountShift", 16) - object SourceLanguage { + object SourceLanguage: val Unknown = Code("Unknown", 0) val ESSL = Code("ESSL", 1) val GLSL = Code("GLSL", 2) val OpenCL_C = Code("OpenCL_C", 3) val OpenCL_CPP = Code("OpenCL_CPP", 4) val HLSL = Code("HLSL", 5) - } - object ExecutionModel { + object ExecutionModel: val Vertex = Code("Vertex", 0) val TessellationControl = Code("TessellationControl", 1) val TessellationEvaluation = Code("TessellationEvaluation", 2) @@ -98,21 +88,18 @@ private[cyfra] object Opcodes { val Fragment = Code("Fragment", 4) val GLCompute = Code("GLCompute", 5) val Kernel = Code("Kernel", 6) - } - object AddressingModel { + object AddressingModel: val Logical = Code("Logical", 0) val Physical32 = Code("Physical32", 1) val Physical64 = Code("Physical64", 2) - } - object MemoryModel { + object MemoryModel: val Simple = Code("Simple", 0) val GLSL450 = Code("GLSL450", 1) val OpenCL = Code("OpenCL", 2) - } - object ExecutionMode { + object ExecutionMode: val Invocations = Code("Invocations", 0) val SpacingEqual = Code("SpacingEqual", 1) val SpacingFractionalEven = Code("SpacingFractionalEven", 2) @@ -150,9 +137,8 @@ private[cyfra] object Opcodes { val SubgroupsPerWorkgroup = Code("SubgroupsPerWorkgroup", 36) val PostDepthCoverage = Code("PostDepthCoverage", 4446) val StencilRefReplacingEXT = Code("StencilRefReplacingEXT", 5027) - } - object StorageClass { + object StorageClass: val UniformConstant = Code("UniformConstant", 0) val Input = Code("Input", 1) val Uniform = Code("Uniform", 2) @@ -166,9 +152,8 @@ private[cyfra] object Opcodes { val AtomicCounter = Code("AtomicCounter", 10) val Image = Code("Image", 11) val StorageBuffer = Code("StorageBuffer", 12) - } - object Dim { + object Dim: val Dim1D = Code("Dim1D", 0) val Dim2D = Code("Dim2D", 1) val Dim3D = Code("Dim3D", 2) @@ -176,22 +161,19 @@ private[cyfra] object Opcodes { val Rect = Code("Rect", 4) val Buffer = Code("Buffer", 5) val SubpassData = Code("SubpassData", 6) - } - object SamplerAddressingMode { + object SamplerAddressingMode: val None = Code("None", 0) val ClampToEdge = Code("ClampToEdge", 1) val Clamp = Code("Clamp", 2) val Repeat = Code("Repeat", 3) val RepeatMirrored = Code("RepeatMirrored", 4) - } - object SamplerFilterMode { + object SamplerFilterMode: val Nearest = Code("Nearest", 0) val Linear = Code("Linear", 1) - } - object ImageFormat { + object ImageFormat: val Unknown = Code("Unknown", 0) val Rgba32f = Code("Rgba32f", 1) val Rgba16f = Code("Rgba16f", 2) @@ -232,9 +214,8 @@ private[cyfra] object Opcodes { val Rg8ui = Code("Rg8ui", 37) val R16ui = Code("R16ui", 38) val R8ui = Code("R8ui", 39) - } - object ImageChannelOrder { + object ImageChannelOrder: val R = Code("R", 0) val A = Code("A", 1) val RG = Code("RG", 2) @@ -255,9 +236,8 @@ private[cyfra] object Opcodes { val sRGBA = Code("sRGBA", 17) val sBGRA = Code("sBGRA", 18) val ABGR = Code("ABGR", 19) - } - object ImageChannelDataType { + object ImageChannelDataType: val SnormInt8 = Code("SnormInt8", 0) val SnormInt16 = Code("SnormInt16", 1) val UnormInt8 = Code("UnormInt8", 2) @@ -275,9 +255,8 @@ private[cyfra] object Opcodes { val Float = Code("Float", 14) val UnormInt24 = Code("UnormInt24", 15) val UnormInt101010_2 = Code("UnormInt101010_2", 16) - } - object ImageOperandsShift { + object ImageOperandsShift: val Bias = Code("Bias", 0) val Lod = Code("Lod", 1) val Grad = Code("Grad", 2) @@ -286,9 +265,8 @@ private[cyfra] object Opcodes { val ConstOffsets = Code("ConstOffsets", 5) val Sample = Code("Sample", 6) val MinLod = Code("MinLod", 7) - } - object ImageOperandsMask { + object ImageOperandsMask: val MaskNone = Code("MaskNone", 0) val Bias = Code("Bias", 0x00000001) val Lod = Code("Lod", 0x00000002) @@ -298,44 +276,38 @@ private[cyfra] object Opcodes { val ConstOffsets = Code("ConstOffsets", 0x00000020) val Sample = Code("Sample", 0x00000040) val MinLod = Code("MinLod", 0x00000080) - } - object FPFastMathModeShift { + object FPFastMathModeShift: val NotNaN = Code("NotNaN", 0) val NotInf = Code("NotInf", 1) val NSZ = Code("NSZ", 2) val AllowRecip = Code("AllowRecip", 3) val Fast = Code("Fast", 4) - } - object FPFastMathModeMask { + object FPFastMathModeMask: val MaskNone = Code("MaskNone", 0) val NotNaN = Code("NotNaN", 0x00000001) val NotInf = Code("NotInf", 0x00000002) val NSZ = Code("NSZ", 0x00000004) val AllowRecip = Code("AllowRecip", 0x00000008) val Fast = Code("Fast", 0x00000010) - } - object FPRoundingMode { + object FPRoundingMode: val RTE = Code("RTE", 0) val RTZ = Code("RTZ", 1) val RTP = Code("RTP", 2) val RTN = Code("RTN", 3) - } - object LinkageType { + object LinkageType: val Export = Code("Export", 0) val Import = Code("Import", 1) - } - object AccessQualifier { + object AccessQualifier: val ReadOnly = Code("ReadOnly", 0) val WriteOnly = Code("WriteOnly", 1) val ReadWrite = Code("ReadWrite", 2) - } - object FunctionParameterAttribute { + object FunctionParameterAttribute: val Zext = Code("Zext", 0) val Sext = Code("Sext", 1) val ByVal = Code("ByVal", 2) @@ -344,9 +316,8 @@ private[cyfra] object Opcodes { val NoCapture = Code("NoCapture", 5) val NoWrite = Code("NoWrite", 6) val NoReadWrite = Code("NoReadWrite", 7) - } - object Decoration { + object Decoration: val RelaxedPrecision = Code("RelaxedPrecision", 0) val SpecId = Code("SpecId", 1) val Block = Code("Block", 2) @@ -396,9 +367,8 @@ private[cyfra] object Opcodes { val PassthroughNV = Code("PassthroughNV", 5250) val ViewportRelativeNV = Code("ViewportRelativeNV", 5252) val SecondaryViewportRelativeNV = Code("SecondaryViewportRelativeNV", 5256) - } - object BuiltIn { + object BuiltIn: val Position = Code("Position", 0) val PointSize = Code("PointSize", 1) val ClipDistance = Code("ClipDistance", 3) @@ -463,50 +433,43 @@ private[cyfra] object Opcodes { val SecondaryViewportMaskNV = Code("SecondaryViewportMaskNV", 5258) val PositionPerViewNV = Code("PositionPerViewNV", 5261) val ViewportMaskPerViewNV = Code("ViewportMaskPerViewNV", 5262) - } - object SelectionControlShift { + object SelectionControlShift: val Flatten = Code("Flatten", 0) val DontFlatten = Code("DontFlatten", 1) - } - object SelectionControlMask { + object SelectionControlMask: val MaskNone = Code("MaskNone", 0) val Flatten = Code("Flatten", 0x00000001) val DontFlatten = Code("DontFlatten", 0x00000002) - } - object LoopControlShift { + object LoopControlShift: val Unroll = Code("Unroll", 0) val DontUnroll = Code("DontUnroll", 1) val DependencyInfinite = Code("DependencyInfinite", 2) val DependencyLength = Code("DependencyLength", 3) - } - object LoopControlMask { + object LoopControlMask: val MaskNone = Code("MaskNone", 0) val Unroll = Code("Unroll", 0x00000001) val DontUnroll = Code("DontUnroll", 0x00000002) val DependencyInfinite = Code("DependencyInfinite", 0x00000004) val DependencyLength = Code("DependencyLength", 0x00000008) - } - object FunctionControlShift { + object FunctionControlShift: val Inline = Code("Inline", 0) val DontInline = Code("DontInline", 1) val Pure = Code("Pure", 2) val Const = Code("Const", 3) - } - object FunctionControlMask { + object FunctionControlMask: val MaskNone = Code("MaskNone", 0) val Inline = Code("Inline", 0x00000001) val DontInline = Code("DontInline", 0x00000002) val Pure = Code("Pure", 0x00000004) val Const = Code("Const", 0x00000008) - } - object MemorySemanticsShift { + object MemorySemanticsShift: val Acquire = Code("Acquire", 1) val Release = Code("Release", 2) val AcquireRelease = Code("AcquireRelease", 3) @@ -517,9 +480,8 @@ private[cyfra] object Opcodes { val CrossWorkgroupMemory = Code("CrossWorkgroupMemory", 9) val AtomicCounterMemory = Code("AtomicCounterMemory", 10) val ImageMemory = Code("ImageMemory", 11) - } - object MemorySemanticsMask { + object MemorySemanticsMask: val MaskNone = Code("MaskNone", 0) val Acquire = Code("Acquire", 0x00000002) val Release = Code("Release", 0x00000004) @@ -531,51 +493,43 @@ private[cyfra] object Opcodes { val CrossWorkgroupMemory = Code("CrossWorkgroupMemory", 0x00000200) val AtomicCounterMemory = Code("AtomicCounterMemory", 0x00000400) val ImageMemory = Code("ImageMemory", 0x00000800) - } - object MemoryAccessShift { + object MemoryAccessShift: val Volatile = Code("Volatile", 0) val Aligned = Code("Aligned", 1) val Nontemporal = Code("Nontemporal", 2) - } - object MemoryAccessMask { + object MemoryAccessMask: val MaskNone = Code("MaskNone", 0) val Volatile = Code("Volatile", 0x00000001) val Aligned = Code("Aligned", 0x00000002) val Nontemporal = Code("Nontemporal", 0x00000004) - } - object Scope { + object Scope: val CrossDevice = Code("CrossDevice", 0) val Device = Code("Device", 1) val Workgroup = Code("Workgroup", 2) val Subgroup = Code("Subgroup", 3) val Invocation = Code("Invocation", 4) - } - object GroupOperation { + object GroupOperation: val Reduce = Code("Reduce", 0) val InclusiveScan = Code("InclusiveScan", 1) val ExclusiveScan = Code("ExclusiveScan", 2) - } - object KernelEnqueueFlags { + object KernelEnqueueFlags: val NoWait = Code("NoWait", 0) val WaitKernel = Code("WaitKernel", 1) val WaitWorkGroup = Code("WaitWorkGroup", 2) - } - object KernelProfilingInfoShift { + object KernelProfilingInfoShift: val CmdExecTime = Code("CmdExecTime", 0) - } - object KernelProfilingInfoMask { + object KernelProfilingInfoMask: val MaskNone = Code("MaskNone", 0) val CmdExecTime = Code("CmdExecTime", 0x00000001) - } - object Capability { + object Capability: val Matrix = Code("Matrix", 0) val Shader = Code("Shader", 1) val Geometry = Code("Geometry", 2) @@ -664,9 +618,8 @@ private[cyfra] object Opcodes { val SubgroupShuffleINTEL = Code("SubgroupShuffleINTEL", 5568) val SubgroupBufferBlockIOINTEL = Code("SubgroupBufferBlockIOINTEL", 5569) val SubgroupImageBlockIOINTEL = Code("SubgroupImageBlockIOINTEL", 5570) - } - object Op { + object Op: val OpNop = Code("OpNop", 0) val OpUndef = Code("OpUndef", 1) val OpSourceContinued = Code("OpSourceContinued", 2) @@ -995,9 +948,8 @@ private[cyfra] object Opcodes { val OpSubgroupBlockWriteINTEL = Code("OpSubgroupBlockWriteINTEL", 5576) val OpSubgroupImageBlockReadINTEL = Code("OpSubgroupImageBlockReadINTEL", 5577) val OpSubgroupImageBlockWriteINTEL = Code("OpSubgroupImageBlockWriteINTEL", 5578) - } - object GlslOp { + object GlslOp: val Round = Code("Round", 1) val RoundEven = Code("RoundEven", 2) val Trunc = Code("Trunc", 3) @@ -1078,6 +1030,3 @@ private[cyfra] object Opcodes { val NMin = Code("NMin", 79) val NMax = Code("NMax", 80) val NClamp = Code("NClamp", 81) - } - -} diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala index 122f6505..9fe1b386 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala @@ -2,7 +2,6 @@ package io.computenode.cyfra.spirv import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.spirv.Context.initialContext import io.computenode.cyfra.spirv.Opcodes.* import izumi.reflect.Tag import izumi.reflect.macrortti.{LTag, LightTypeTag} @@ -37,12 +36,11 @@ private[cyfra] object SpirvTypes: type Vec3C[T <: Value] = Vec3[T] type Vec4C[T <: Value] = Vec4[T] - def scalarTypeDefInsn(tag: Tag[?], typeDefIndex: Int) = tag match { + def scalarTypeDefInsn(tag: Tag[?], typeDefIndex: Int) = tag match case Int32Tag => Instruction(Op.OpTypeInt, List(ResultRef(typeDefIndex), IntWord(32), IntWord(1))) case UInt32Tag => Instruction(Op.OpTypeInt, List(ResultRef(typeDefIndex), IntWord(32), IntWord(0))) case Float32Tag => Instruction(Op.OpTypeFloat, List(ResultRef(typeDefIndex), IntWord(32))) case GBooleanTag => Instruction(Op.OpTypeBool, List(ResultRef(typeDefIndex))) - } def vecSize(tag: LightTypeTag): Int = tag match case v if v <:< LVec2Tag => 2 @@ -59,19 +57,17 @@ private[cyfra] object SpirvTypes: def typeStride(tag: Tag[?]): Int = typeStride(tag.tag) - def toWord(tpe: Tag[?], value: Any): Words = tpe match { + def toWord(tpe: Tag[?], value: Any): Words = tpe match case t if t == Int32Tag => IntWord(value.asInstanceOf[Int]) case t if t == UInt32Tag => IntWord(value.asInstanceOf[Int]) case t if t == Float32Tag => - val fl = value match { + val fl = value match case fl: Float => fl case dl: Double => dl.toFloat case il: Int => il.toFloat - } Word(intToBytes(java.lang.Float.floatToIntBits(fl)).reverse.toArray) - } def defineScalarTypes(types: List[Tag[?]], context: Context): (List[Words], Context) = val basicTypes = List(Int32Tag, Float32Tag, UInt32Tag, GBooleanTag) @@ -99,9 +95,9 @@ private[cyfra] object SpirvTypes: ctx.copy( valueTypeMap = ctx.valueTypeMap ++ Map( valType.tag -> typeDefIndex, - (summon[LTag[Vec2C]].tag.combine(valType.tag)) -> (typeDefIndex + 4), - (summon[LTag[Vec3C]].tag.combine(valType.tag)) -> (typeDefIndex + 5), - (summon[LTag[Vec4C]].tag.combine(valType.tag)) -> (typeDefIndex + 11), + summon[LTag[Vec2C]].tag.combine(valType.tag) -> (typeDefIndex + 4), + summon[LTag[Vec3C]].tag.combine(valType.tag) -> (typeDefIndex + 5), + summon[LTag[Vec4C]].tag.combine(valType.tag) -> (typeDefIndex + 11), ), funPointerTypeMap = ctx.funPointerTypeMap ++ Map( typeDefIndex -> (typeDefIndex + 1), diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala index 4d58ae7f..07ae9aab 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala @@ -1,29 +1,26 @@ package io.computenode.cyfra.spirv.compilers import io.computenode.cyfra.* -import io.computenode.cyfra.spirv.Opcodes.* -import izumi.reflect.Tag -import izumi.reflect.macrortti.{LTag, LTagK, LightTypeTag} -import org.lwjgl.BufferUtils -import SpirvProgramCompiler.* -import io.computenode.cyfra.dsl.Expression.E import io.computenode.cyfra.dsl.* +import io.computenode.cyfra.dsl.Expression.E import io.computenode.cyfra.dsl.Value.Scalar import io.computenode.cyfra.dsl.struct.GStruct.* import io.computenode.cyfra.dsl.struct.GStructSchema +import io.computenode.cyfra.spirv.Context +import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.spirv.SpirvConstants.* import io.computenode.cyfra.spirv.SpirvTypes.* -import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.compileBlock +import io.computenode.cyfra.spirv.compilers.FunctionCompiler.compileFunctions import io.computenode.cyfra.spirv.compilers.GStructCompiler.* -import io.computenode.cyfra.spirv.Context -import io.computenode.cyfra.spirv.compilers.FunctionCompiler.{compileFunctions, defineFunctionTypes} +import io.computenode.cyfra.spirv.compilers.SpirvProgramCompiler.* +import izumi.reflect.Tag +import izumi.reflect.macrortti.LightTypeTag +import org.lwjgl.BufferUtils import java.nio.ByteBuffer import scala.annotation.tailrec import scala.collection.mutable -import scala.math.random import scala.runtime.stdLibPatches.Predef.summon -import scala.util.Random private[cyfra] object DSLCompiler: @@ -80,10 +77,9 @@ private[cyfra] object DSLCompiler: decorations ::: uniformStructDecorations ::: typeDefs ::: structDefs ::: fnTypeDefs ::: uniformDefs ::: uniformStructInsns ::: inputDefs ::: constDefs ::: varDefs ::: main ::: fnDefs - val fullCode = code.map { + val fullCode = code.map: case WordVariable(name) if name == BOUND_VARIABLE => IntWord(ctxWithFnDefs.nextResultId) case x => x - } val bytes = fullCode.flatMap(_.toWords).toArray BufferUtils.createByteBuffer(bytes.length).put(bytes).rewind() diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala index 8ef41c8d..1a8cd62b 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala @@ -1,24 +1,22 @@ package io.computenode.cyfra.spirv.compilers -import io.computenode.cyfra.spirv.Opcodes.* -import ExtFunctionCompiler.compileExtFunctionCall -import FunctionCompiler.compileFunctionCall -import WhenCompiler.compileWhen -import io.computenode.cyfra.dsl.Expression.* import io.computenode.cyfra.dsl.* +import io.computenode.cyfra.dsl.Expression.* import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.collections.GArray.GArrayElem import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.macros.Source import io.computenode.cyfra.dsl.struct.GStruct.{ComposeStruct, GetField} import io.computenode.cyfra.dsl.struct.GStructSchema +import io.computenode.cyfra.spirv.Opcodes.* +import io.computenode.cyfra.spirv.SpirvTypes.* +import io.computenode.cyfra.spirv.compilers.ExtFunctionCompiler.compileExtFunctionCall +import io.computenode.cyfra.spirv.compilers.FunctionCompiler.compileFunctionCall +import io.computenode.cyfra.spirv.compilers.WhenCompiler.compileWhen import io.computenode.cyfra.spirv.{BlockBuilder, Context} -import io.computenode.cyfra.dsl.collections.GArray.GArrayElem import izumi.reflect.Tag -import io.computenode.cyfra.spirv.SpirvConstants.* -import io.computenode.cyfra.spirv.SpirvTypes.* import scala.annotation.tailrec -import scala.collection.immutable.List as expr private[cyfra] object ExpressionCompiler: @@ -38,14 +36,13 @@ private[cyfra] object ExpressionCompiler: private def compileBinaryOpExpression(bexpr: BinaryOpExpression[?], ctx: Context): (List[Instruction], Context) = val tpe = bexpr.tag val typeRef = ctx.valueTypeMap(tpe.tag) - val subOpcode = tpe match { + val subOpcode = tpe match case i if i.tag <:< summon[Tag[IntType]].tag || i.tag <:< summon[Tag[UIntType]].tag || (i.tag <:< summon[Tag[Vec[?]]].tag && i.tag.typeArgs.head <:< summon[Tag[IntType]].tag) => binaryOpOpcode(bexpr)._1 case f if f.tag <:< summon[Tag[FloatType]].tag || (f.tag <:< summon[Tag[Vec[?]]].tag && f.tag.typeArgs.head <:< summon[Tag[FloatType]].tag) => binaryOpOpcode(bexpr)._2 - } val instructions = List( Instruction( subOpcode, @@ -58,14 +55,13 @@ private[cyfra] object ExpressionCompiler: private def compileConvertExpression(cexpr: ConvertExpression[?, ?], ctx: Context): (List[Instruction], Context) = val tpe = cexpr.tag val typeRef = ctx.valueTypeMap(tpe.tag) - val tfOpcode = (cexpr.fromTag, cexpr) match { + val tfOpcode = (cexpr.fromTag, cexpr) match case (from, _: ToFloat32[?]) if from.tag =:= Int32Tag.tag => Op.OpConvertSToF case (from, _: ToFloat32[?]) if from.tag =:= UInt32Tag.tag => Op.OpConvertUToF case (from, _: ToInt32[?]) if from.tag =:= Float32Tag.tag => Op.OpConvertFToS case (from, _: ToUInt32[?]) if from.tag =:= Float32Tag.tag => Op.OpConvertFToU case (from, _: ToInt32[?]) if from.tag =:= UInt32Tag.tag => Op.OpBitcast case (from, _: ToUInt32[?]) if from.tag =:= Int32Tag.tag => Op.OpBitcast - } val instructions = List(Instruction(tfOpcode, List(ResultRef(typeRef), ResultRef(ctx.nextResultId), ResultRef(ctx.exprRefs(cexpr.a.treeid))))) val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (cexpr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) @@ -81,35 +77,34 @@ private[cyfra] object ExpressionCompiler: private def compileBitwiseExpression(bexpr: BitwiseOpExpression[?], ctx: Context): (List[Instruction], Context) = val tpe = bexpr.tag val typeRef = ctx.valueTypeMap(tpe.tag) - val subOpcode = bexpr match { + val subOpcode = bexpr match case _: BitwiseAnd[?] => Op.OpBitwiseAnd case _: BitwiseOr[?] => Op.OpBitwiseOr case _: BitwiseXor[?] => Op.OpBitwiseXor case _: BitwiseNot[?] => Op.OpNot case _: ShiftLeft[?] => Op.OpShiftLeftLogical case _: ShiftRight[?] => Op.OpShiftRightLogical - } val instructions = List( Instruction(subOpcode, List(ResultRef(typeRef), ResultRef(ctx.nextResultId)) ::: bexpr.exprDependencies.map(d => ResultRef(ctx.exprRefs(d.treeid)))), ) val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (bexpr.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (instructions, updatedContext) - def compileBlock(tree: E[?], ctx: Context): (List[Words], Context) = { + def compileBlock(tree: E[?], ctx: Context): (List[Words], Context) = @tailrec - def compileExpressions(exprs: List[E[?]], ctx: Context, acc: List[Words]): (List[Words], Context) = { + def compileExpressions(exprs: List[E[?]], ctx: Context, acc: List[Words]): (List[Words], Context) = if exprs.isEmpty then (acc, ctx) - else { + else val expr = exprs.head if ctx.exprRefs.contains(expr.treeid) then compileExpressions(exprs.tail, ctx, acc) - else { + else val name: Option[String] = expr.of match case Some(v) => Some(v.source.name) case _ => None - val (instructions, updatedCtx) = expr match { + val (instructions, updatedCtx) = expr match case c @ Const(x) => val constRef = ctx.constRefs((c.tag, x)) val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (c.treeid -> constRef)) @@ -322,6 +317,7 @@ private[cyfra] object ExpressionCompiler: GSeqCompiler.compileFold(fd, ctx) case cs: ComposeStruct[?] => + // noinspection ScalaRedundantCast val schema = cs.resultSchema.asInstanceOf[GStructSchema[?]] val fields = cs.fields val insns: List[Instruction] = List( @@ -365,12 +361,7 @@ private[cyfra] object ExpressionCompiler: (insns, updatedContext) case ph: PhantomExpression[?] => (List(), ctx) - } val ctxWithName = updatedCtx.copy(exprNames = updatedCtx.exprNames ++ name.map(n => (updatedCtx.nextResultId - 1, n)).toMap) compileExpressions(exprs.tail, ctxWithName, acc ::: instructions) - } - } - } val sortedTree = BlockBuilder.buildBlock(tree, providedExprIds = ctx.exprRefs.keySet) compileExpressions(sortedTree, ctx, Nil) - } diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala index 3d3f916f..21c04283 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExtFunctionCompiler.scala @@ -1,13 +1,12 @@ package io.computenode.cyfra.spirv.compilers -import io.computenode.cyfra.dsl.Expression.E -import io.computenode.cyfra.dsl.library.Functions.FunctionName -import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.dsl.Expression import io.computenode.cyfra.dsl.library.Functions +import io.computenode.cyfra.dsl.library.Functions.FunctionName import io.computenode.cyfra.spirv.Context -import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction +import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.spirv.SpirvConstants.GLSL_EXT_REF +import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction private[cyfra] object ExtFunctionCompiler: private val fnOpMap: Map[FunctionName, Code] = Map( diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala index e8910c71..3e76f60f 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/FunctionCompiler.scala @@ -1,16 +1,9 @@ package io.computenode.cyfra.spirv.compilers -import io.computenode.cyfra.spirv.Context -import io.computenode.cyfra.dsl.Expression.E -import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.dsl.Expression -import io.computenode.cyfra.spirv.Context -import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction -import io.computenode.cyfra.spirv.SpirvConstants.GLSL_EXT_REF -import io.computenode.cyfra.dsl.macros.Source -import io.computenode.cyfra.dsl.library.Functions -import io.computenode.cyfra.dsl.library.Functions.FunctionName import io.computenode.cyfra.dsl.macros.FnCall.FnIdentifier +import io.computenode.cyfra.spirv.Context +import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.compileBlock import io.computenode.cyfra.spirv.compilers.SpirvProgramCompiler.bubbleUpVars import izumi.reflect.macrortti.LightTypeTag diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala index 3a44a2cf..e635c4c5 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GSeqCompiler.scala @@ -3,11 +3,10 @@ package io.computenode.cyfra.spirv.compilers import io.computenode.cyfra.dsl.Expression.E import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.collections.GSeq.* +import io.computenode.cyfra.spirv.Context import io.computenode.cyfra.spirv.Opcodes.* -import io.computenode.cyfra.spirv.{BlockBuilder, Context} -import izumi.reflect.Tag -import io.computenode.cyfra.spirv.SpirvConstants.* import io.computenode.cyfra.spirv.SpirvTypes.* +import izumi.reflect.Tag private[cyfra] object GSeqCompiler: @@ -49,7 +48,7 @@ private[cyfra] object GSeqCompiler: def generateSeqOps(seqExprs: List[(ElemOp[?], E[?])], context: Context, elemRef: Int): (List[Words], Context) = val withElemRefCtx = context.copy(exprRefs = context.exprRefs + (fold.seq.currentElemExprTreeId -> elemRef)) - seqExprs match { + seqExprs match case Nil => // No more transformations, so reduce ops now val resultRef = context.nextResultId val forReduceCtx = withElemRefCtx @@ -72,7 +71,7 @@ private[cyfra] object GSeqCompiler: (instructions, ctx.joinNested(reduceCtx)) case (op, dExpr) :: tail => - op match { + op match case MapOp(_) => val (mapOps, mapContext) = ExpressionCompiler.compileBlock(dExpr, withElemRefCtx) val newElemRef = mapContext.exprRefs(dExpr.treeid) @@ -105,8 +104,6 @@ private[cyfra] object GSeqCompiler: Instruction(Op.OpLabel, List(ResultRef(trueLabel))), ) ::: tailOps ::: List(Instruction(Op.OpBranch, List(ResultRef(mergeBlock))), Instruction(Op.OpLabel, List(ResultRef(mergeBlock)))) (instructions, tailContext.copy(exprNames = tailContext.exprNames ++ Map(condResultRef -> "takeUntilCondResult"))) - } - } val seqExprs = fold.seq.elemOps.zip(fold.seqExprs) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala index d495444d..fe3faacc 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala @@ -1,9 +1,8 @@ package io.computenode.cyfra.spirv.compilers import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} -import io.computenode.cyfra.dsl.struct.GStructSchema.* -import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.spirv.Context +import io.computenode.cyfra.spirv.Opcodes.* import izumi.reflect.Tag import izumi.reflect.macrortti.LightTypeTag diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index 32828fc2..8d16743c 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -14,12 +14,11 @@ import izumi.reflect.Tag private[cyfra] object SpirvProgramCompiler: def bubbleUpVars(exprs: List[Words]): (List[Words], List[Words]) = - exprs.partition { + exprs.partition: case Instruction(Op.OpVariable, _) => true case _ => false - } - def compileMain(tree: Value, resultType: Tag[?], ctx: Context): (List[Words], Context) = { + def compileMain(tree: Value, resultType: Tag[?], ctx: Context): (List[Words], Context) = val init = List( Instruction(Op.OpFunction, List(ResultRef(ctx.voidTypeRef), ResultRef(MAIN_FUNC_REF), SamplerAddressingMode.None, ResultRef(VOID_FUNC_TYPE_REF))), @@ -49,7 +48,7 @@ private[cyfra] object SpirvProgramCompiler: List( ResultRef(codeCtx.uniformPointerMap(codeCtx.valueTypeMap(resultType.tag))), ResultRef(codeCtx.nextResultId), - ResultRef(codeCtx.outBufferBlocks(0).blockVarRef), + ResultRef(codeCtx.outBufferBlocks.head.blockVarRef), ResultRef(codeCtx.constRefs((Int32Tag, 0))), ResultRef(codeCtx.workerIndexRef), ), @@ -59,7 +58,6 @@ private[cyfra] object SpirvProgramCompiler: Instruction(Op.OpFunctionEnd, List()), ) (init ::: vars ::: initWorkerIndex ::: nonVarsBody ::: end, codeCtx.copy(nextResultId = codeCtx.nextResultId + 1)) - } def getNameDecorations(ctx: Context): List[Instruction] = val funNames = ctx.functions.map { case (id, fn) => @@ -96,23 +94,21 @@ private[cyfra] object SpirvProgramCompiler: Instruction(Op.OpDecorate, List(ResultRef(GL_GLOBAL_INVOCATION_ID_REF), Decoration.BuiltIn, BuiltIn.GlobalInvocationId)) :: // OpDecorate %GL_GLOBAL_INVOCATION_ID_REF BuiltIn GlobalInvocationId Instruction(Op.OpDecorate, List(ResultRef(GL_WORKGROUP_SIZE_REF), Decoration.BuiltIn, BuiltIn.WorkgroupSize)) :: Nil - def defineVoids(context: Context): (List[Words], Context) = { + def defineVoids(context: Context): (List[Words], Context) = val voidDef = List[Words]( Instruction(Op.OpTypeVoid, List(ResultRef(TYPE_VOID_REF))), Instruction(Op.OpTypeFunction, List(ResultRef(VOID_FUNC_TYPE_REF), ResultRef(TYPE_VOID_REF))), ) val ctxWithVoid = context.copy(voidTypeRef = TYPE_VOID_REF, voidFuncTypeRef = VOID_FUNC_TYPE_REF) (voidDef, ctxWithVoid) - } - def initAndDecorateUniforms(ins: List[Tag[?]], outs: List[Tag[?]], context: Context): (List[Words], List[Words], Context) = { + def initAndDecorateUniforms(ins: List[Tag[?]], outs: List[Tag[?]], context: Context): (List[Words], List[Words], Context) = val (inDecor, inDef, inCtx) = createAndInitBlocks(ins, in = true, context) val (outDecor, outDef, outCtx) = createAndInitBlocks(outs, in = false, inCtx) val (voidsDef, voidCtx) = defineVoids(outCtx) (inDecor ::: outDecor, voidsDef ::: inDef ::: outDef, voidCtx) - } - def createInvocationId(context: Context): (List[Words], Context) = { + def createInvocationId(context: Context): (List[Words], Context) = val definitionInstructions = List( Instruction(Op.OpConstant, List(ResultRef(context.valueTypeMap(UInt32Tag.tag)), ResultRef(context.nextResultId + 0), IntWord(localSizeX))), Instruction(Op.OpConstant, List(ResultRef(context.valueTypeMap(UInt32Tag.tag)), ResultRef(context.nextResultId + 1), IntWord(localSizeY))), @@ -129,9 +125,8 @@ private[cyfra] object SpirvProgramCompiler: ), ) (definitionInstructions, context.copy(nextResultId = context.nextResultId + 3)) - } - def createAndInitBlocks(blocks: List[Tag[?]], in: Boolean, context: Context): (List[Words], List[Words], Context) = { + def createAndInitBlocks(blocks: List[Tag[?]], in: Boolean, context: Context): (List[Words], List[Words], Context) = val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { case ((decAcc, insnAcc, ctx), tpe) => val block = ArrayBufferBlock(ctx.nextResultId, ctx.nextResultId + 1, ctx.nextResultId + 2, ctx.nextResultId + 3, ctx.nextBinding) @@ -159,7 +154,6 @@ private[cyfra] object SpirvProgramCompiler: ) } (decoration, definition, newContext) - } def getBlockNames(context: Context, uniformSchema: GStructSchema[?]): List[Words] = def namesForBlock(block: ArrayBufferBlock, tpe: String): List[Words] = @@ -215,7 +209,7 @@ private[cyfra] object SpirvProgramCompiler: ) val predefinedConsts = List((Int32Tag, 0), (UInt32Tag, 0), (Int32Tag, 1)) - def defineConstants(exprs: List[E[?]], ctx: Context): (List[Words], Context) = { + def defineConstants(exprs: List[E[?]], ctx: Context): (List[Words], Context) = val consts = (exprs.collect { case c @ Const(x) => (c.tag, x) @@ -234,10 +228,9 @@ private[cyfra] object SpirvProgramCompiler: withBool, newC.copy( nextResultId = newC.nextResultId + 2, - constRefs = newC.constRefs ++ Map((GBooleanTag, true) -> (newC.nextResultId), (GBooleanTag, false) -> (newC.nextResultId + 1)), + constRefs = newC.constRefs ++ Map((GBooleanTag, true) -> newC.nextResultId, (GBooleanTag, false) -> (newC.nextResultId + 1)), ), ) - } def defineVarNames(ctx: Context): (List[Words], Context) = ( diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala index 9a889b8f..3b3d1c13 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/WhenCompiler.scala @@ -1,19 +1,17 @@ package io.computenode.cyfra.spirv.compilers -import ExpressionCompiler.compileBlock -import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.dsl.Expression.E import io.computenode.cyfra.dsl.control.When.WhenExpr -import io.computenode.cyfra.spirv.{BlockBuilder, Context} +import io.computenode.cyfra.spirv.Context +import io.computenode.cyfra.spirv.Opcodes.* +import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.compileBlock import izumi.reflect.Tag -import io.computenode.cyfra.spirv.SpirvConstants.* -import io.computenode.cyfra.spirv.SpirvTypes.* private[cyfra] object WhenCompiler: - def compileWhen(when: WhenExpr[?], ctx: Context): (List[Words], Context) = { + def compileWhen(when: WhenExpr[?], ctx: Context): (List[Words], Context) = def compileCases(ctx: Context, resultVar: Int, conditions: List[E[?]], thenCodes: List[E[?]], elseCode: E[?]): (List[Words], Context) = - (conditions, thenCodes) match { + (conditions, thenCodes) match case (Nil, Nil) => val (elseInstructions, elseCtx) = compileBlock(elseCode, ctx) val elseWithStore = elseInstructions :+ Instruction(Op.OpStore, List(ResultRef(resultVar), ResultRef(elseCtx.exprRefs(elseCode.treeid)))) @@ -42,7 +40,6 @@ private[cyfra] object WhenCompiler: ), postCtx.joinNested(elseCtx), ) - } val resultVar = ctx.nextResultId val resultLoaded = ctx.nextResultId + 1 @@ -58,4 +55,3 @@ private[cyfra] object WhenCompiler: List(Instruction(Op.OpVariable, List(ResultRef(ctx.funPointerTypeMap(resultTypeTag)), ResultRef(resultVar), StorageClass.Function))) ::: caseInstructions ::: List(Instruction(Op.OpLoad, List(ResultRef(resultTypeTag), ResultRef(resultLoaded), ResultRef(resultVar)))) (instructions, caseCtx.copy(exprRefs = caseCtx.exprRefs + (when.treeid -> resultLoaded))) - } diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala index 707b637b..52b8b844 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala @@ -18,7 +18,7 @@ trait Expression[T <: Value: Tag] extends Product: .map(e => s"#${e.treeid}") .mkString("[", ", ", "]") override def toString: String = s"${this.productPrefix}(${of.fold("")(v => s"name = ${v.source}, ")}children=$childrenStrings, id=$treeid)" - private def exploreDeps(children: List[Any]): (List[Expression[?]], List[Scope[?]]) = (for (elem <- children) yield elem match { + private def exploreDeps(children: List[Any]): (List[Expression[?]], List[Scope[?]]) = (for elem <- children yield elem match { case b: Scope[?] => (None, Some(b)) case x: Expression[?] => @@ -46,10 +46,9 @@ object Expression: type E[T <: Value] = Expression[T] case class Negate[T <: Value: Tag](a: T) extends Expression[T] - sealed trait BinaryOpExpression[T <: Value: Tag] extends Expression[T] { + sealed trait BinaryOpExpression[T <: Value: Tag] extends Expression[T]: def a: T def b: T - } case class Sum[T <: Value: Tag](a: T, b: T) extends BinaryOpExpression[T] case class Diff[T <: Value: Tag](a: T, b: T) extends BinaryOpExpression[T] case class Mul[T <: Scalar: Tag](a: T, b: T) extends BinaryOpExpression[T] @@ -59,10 +58,9 @@ object Expression: case class DotProd[S <: Scalar: Tag, V <: Vec[S]](a: V, b: V) extends Expression[S] sealed trait BitwiseOpExpression[T <: Scalar: Tag] extends Expression[T] - sealed trait BitwiseBinaryOpExpression[T <: Scalar: Tag] extends BitwiseOpExpression[T] { + sealed trait BitwiseBinaryOpExpression[T <: Scalar: Tag] extends BitwiseOpExpression[T]: def a: T def b: T - } case class BitwiseAnd[T <: Scalar: Tag](a: T, b: T) extends BitwiseBinaryOpExpression[T] case class BitwiseOr[T <: Scalar: Tag](a: T, b: T) extends BitwiseBinaryOpExpression[T] case class BitwiseXor[T <: Scalar: Tag](a: T, b: T) extends BitwiseBinaryOpExpression[T] @@ -70,11 +68,10 @@ object Expression: case class ShiftLeft[T <: Scalar: Tag](a: T, by: UInt32) extends BitwiseOpExpression[T] case class ShiftRight[T <: Scalar: Tag](a: T, by: UInt32) extends BitwiseOpExpression[T] - sealed trait ComparisonOpExpression[T <: Value: Tag] extends Expression[GBoolean] { + sealed trait ComparisonOpExpression[T <: Value: Tag] extends Expression[GBoolean]: def operandTag = summon[Tag[T]] def a: T def b: T - } case class GreaterThan[T <: Scalar: Tag](a: T, b: T) extends ComparisonOpExpression[T] case class LessThan[T <: Scalar: Tag](a: T, b: T) extends ComparisonOpExpression[T] case class GreaterThanEqual[T <: Scalar: Tag](a: T, b: T) extends ComparisonOpExpression[T] @@ -87,20 +84,17 @@ object Expression: case class ExtractScalar[V <: Vec[?]: Tag, S <: Scalar: Tag](a: V, i: Int32) extends Expression[S] - sealed trait ConvertExpression[F <: Scalar: Tag, T <: Scalar: Tag] extends Expression[T] { + sealed trait ConvertExpression[F <: Scalar: Tag, T <: Scalar: Tag] extends Expression[T]: def fromTag: Tag[F] = summon[Tag[F]] def a: F - } case class ToFloat32[T <: Scalar: Tag](a: T) extends ConvertExpression[T, Float32] case class ToInt32[T <: Scalar: Tag](a: T) extends ConvertExpression[T, Int32] case class ToUInt32[T <: Scalar: Tag](a: T) extends ConvertExpression[T, UInt32] - sealed trait Const[T <: Scalar: Tag] extends Expression[T] { + sealed trait Const[T <: Scalar: Tag] extends Expression[T]: def value: Any - } - object Const { + object Const: def unapply[T <: Scalar](c: Const[T]): Option[Any] = Some(c.value) - } case class ConstFloat32(value: Float) extends Const[Float32] case class ConstInt32(value: Int) extends Const[Int32] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala index a1963157..090797bf 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala @@ -7,7 +7,6 @@ import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag import io.computenode.cyfra.dsl.Value.FromExpr -class GArray2D[T <: Value: Tag: FromExpr](width: Int, val arr: GArray[T]) { +class GArray2D[T <: Value: Tag: FromExpr](width: Int, val arr: GArray[T]): def at(x: Int32, y: Int32)(using Source): T = arr.at(y * width + x) -} diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala index cb380b30..103c5050 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala @@ -10,9 +10,6 @@ import io.computenode.cyfra.dsl.macros.Source import io.computenode.cyfra.dsl.{Expression, Value} import izumi.reflect.Tag -import java.util.Base64 -import scala.util.Random - class GSeq[T <: Value: Tag: FromExpr]( val uninitSource: Expression[?] => GSeqStream[?], val elemOps: List[GSeq.ElemOp[?]], @@ -64,19 +61,16 @@ object GSeq: def of[T <: Value: Tag: FromExpr](xs: List[T]) = GSeq .gen[Int32](0, _ + 1) - .map { i => - val first = when(i === 0) { - xs(0) - } + .map: i => + val first = when(i === 0): + xs.head (if xs.length == 1 then first else - xs.init.zipWithIndex.tail.foldLeft(first) { case (acc, (x, j)) => - acc.elseWhen(i === j) { - x - } - } + xs.init.zipWithIndex.tail.foldLeft(first): + case (acc, (x, j)) => + acc.elseWhen(i === j): + x ).otherwise(xs.last) - } .limit(xs.length) case class CurrentElem[T <: Value: Tag](tid: Int) extends PhantomExpression[T] with CustomTreeId: diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Color.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Color.scala index 0e34626c..5b1f0013 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Color.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Color.scala @@ -10,19 +10,17 @@ import scala.annotation.targetName object Color: - def SRGBToLinear(rgb: Vec3[Float32]): Vec3[Float32] = { + def SRGBToLinear(rgb: Vec3[Float32]): Vec3[Float32] = val clampedRgb = vclamp(rgb, 0.0f, 1.0f) mix(pow((clampedRgb + vec3(0.055f)) * (1.0f / 1.055f), vec3(2.4f)), clampedRgb * (1.0f / 12.92f), lessThan(clampedRgb, 0.04045f)) - } // https://www.youtube.com/shorts/TH3OTy5fTog def igPallette(brightness: Vec3[Float32], contrast: Vec3[Float32], freq: Vec3[Float32], offsets: Vec3[Float32], f: Float32): Vec3[Float32] = brightness addV (contrast mulV cos(((freq * f) addV offsets) * 2f * math.Pi.toFloat)) - def linearToSRGB(rgb: Vec3[Float32]): Vec3[Float32] = { + def linearToSRGB(rgb: Vec3[Float32]): Vec3[Float32] = val clampedRgb = vclamp(rgb, 0.0f, 1.0f) mix(pow(clampedRgb, vec3(1.0f / 2.4f)) * 1.055f - vec3(0.055f), clampedRgb * 12.92f, lessThan(clampedRgb, 0.0031308f)) - } type InterpolationTheme = (Vec3[Float32], Vec3[Float32], Vec3[Float32]) object InterpolationThemes: diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala index 0f2b3a4f..0de27564 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala @@ -2,13 +2,11 @@ package io.computenode.cyfra.dsl.library import io.computenode.cyfra.dsl.Expression.* import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +import io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag -import scala.annotation.targetName - object Functions: sealed class FunctionName diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Math3D.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Math3D.scala index b8249e51..57f50add 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Math3D.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Math3D.scala @@ -1,12 +1,10 @@ package io.computenode.cyfra.dsl.library -import io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} -import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} -import Functions.* import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +import io.computenode.cyfra.dsl.algebra.VectorAlgebra.{*, given} import io.computenode.cyfra.dsl.control.When.when - -import scala.concurrent.duration.DurationInt +import io.computenode.cyfra.dsl.library.Functions.* object Math3D: def scalarTriple(u: Vec3[Float32], v: Vec3[Float32], w: Vec3[Float32]): Float32 = (u cross v) dot w @@ -14,22 +12,20 @@ object Math3D: def fresnelReflectAmount(n1: Float32, n2: Float32, normal: Vec3[Float32], incident: Vec3[Float32], f0: Float32, f90: Float32): Float32 = val r0 = ((n1 - n2) / (n1 + n2)) * ((n1 - n2) / (n1 + n2)) val cosX = -(normal dot incident) - when(n1 > n2) { + when(n1 > n2): val n = n1 / n2 val sinT2 = n * n * (1f - cosX * cosX) - when(sinT2 > 1f) { + when(sinT2 > 1f): f90 - } otherwise { + .otherwise: val cosX2 = sqrt(1.0f - sinT2) val x = 1.0f - cosX2 val ret = r0 + ((1.0f - r0) * x * x * x * x * x) mix(f0, f90, ret) - } - } otherwise { + .otherwise: val x = 1.0f - cosX val ret = r0 + ((1.0f - r0) * x * x * x * x * x) mix(f0, f90, ret) - } def lessThan(f: Vec3[Float32], f2: Float32): Vec3[Float32] = (when(f.x < f2)(1.0f).otherwise(0.0f), when(f.y < f2)(1.0f).otherwise(0.0f), when(f.z < f2)(1.0f).otherwise(0.0f)) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/FnCall.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/FnCall.scala index f5ad184c..f84122e1 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/FnCall.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/FnCall.scala @@ -13,10 +13,9 @@ object FnCall: implicit inline def generate: FnCall = ${ fnCallImpl } - def fnCallImpl(using Quotes): Expr[FnCall] = { + def fnCallImpl(using Quotes): Expr[FnCall] = import quotes.reflect.* resolveFnCall - } case class FnIdentifier(shortName: String, fullName: String, args: List[LightTypeTag]) @@ -30,18 +29,17 @@ object FnCall: val name = Util.getName(ownerDef) val ddOwner = actualOwner(ownerDef) val ownerName = ddOwner.map(d => d.fullName).getOrElse("unknown") - ownerDef.tree match { + ownerDef.tree match case dd: DefDef if isPure(dd) => - val paramTerms: List[Term] = for { + val paramTerms: List[Term] = for paramGroup <- dd.paramss param <- paramGroup.params - } yield Ref(param.symbol) + yield Ref(param.symbol) val paramExprs: List[Expr[Value]] = paramTerms.map(_.asExpr.asInstanceOf[Expr[Value]]) val paramList = Expr.ofList(paramExprs) '{ FnCall(${ Expr(name) }, ${ Expr(ownerName) }, ${ paramList }) } case _ => quotes.reflect.report.errorAndAbort(s"Expected pure function. Found: $ownerDef") - } case None => quotes.reflect.report.errorAndAbort(s"Expected pure function") def isPure(using Quotes)(defdef: quotes.reflect.DefDef): Boolean = diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Source.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Source.scala index e6212397..9acf9f39 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Source.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Source.scala @@ -13,11 +13,10 @@ object Source: implicit inline def generate: Source = ${ sourceImpl } - def sourceImpl(using Quotes): Expr[Source] = { + def sourceImpl(using Quotes): Expr[Source] = import quotes.reflect.* val name = valueName '{ Source(${ name }) } - } def valueName(using Quotes): Expr[String] = import quotes.reflect.* @@ -29,14 +28,13 @@ object Source: case None => Expr("unknown") - def findOwner(using Quotes)(owner: quotes.reflect.Symbol, skipIf: quotes.reflect.Symbol => Boolean): Option[quotes.reflect.Symbol] = { + def findOwner(using Quotes)(owner: quotes.reflect.Symbol, skipIf: quotes.reflect.Symbol => Boolean): Option[quotes.reflect.Symbol] = import quotes.reflect.* var owner0 = owner while skipIf(owner0) do if owner0 == Symbol.noSymbol then return None owner0 = owner0.owner Some(owner0) - } def actualOwner(using Quotes)(owner: quotes.reflect.Symbol): Option[quotes.reflect.Symbol] = findOwner(owner, owner0 => Util.isSynthetic(owner0) || Util.getName(owner0) == "ev") diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Util.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Util.scala index c06c2198..183bbe9f 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Util.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/macros/Util.scala @@ -6,14 +6,12 @@ object Util: def isSynthetic(using Quotes)(s: quotes.reflect.Symbol) = isSyntheticAlt(s) - def isSyntheticAlt(using Quotes)(s: quotes.reflect.Symbol) = { + def isSyntheticAlt(using Quotes)(s: quotes.reflect.Symbol) = import quotes.reflect.* s.flags.is(Flags.Synthetic) || s.isClassConstructor || s.isLocalDummy || isScala2Macro(s) || s.name.startsWith("x$proxy") - } - def isScala2Macro(using Quotes)(s: quotes.reflect.Symbol) = { + def isScala2Macro(using Quotes)(s: quotes.reflect.Symbol) = import quotes.reflect.* (s.flags.is(Flags.Macro) && s.owner.flags.is(Flags.Scala2x)) || (s.flags.is(Flags.Macro) && !s.flags.is(Flags.Inline)) - } def isSyntheticName(name: String) = name == "" || (name.startsWith("")) || name == "$anonfun" || name == "macro" def getName(using Quotes)(s: quotes.reflect.Symbol) = diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticsE2eTest.scala similarity index 100% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticsE2eTest.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsE2eTest.scala similarity index 100% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsE2eTest.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructE2eTest.scala similarity index 100% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructE2eTest.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GSeqTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala similarity index 97% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GSeqTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala index 8319614a..8b70999e 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GSeqTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala @@ -43,8 +43,7 @@ class GseqE2eTest extends munit.FunSuite: List .iterate(n, 10)(_ + 1) .takeWhile(_ <= 200) - .filter(_ % 2 == 0) - .size + .count(_ % 2 == 0) result .zip(expected) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ImageTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ImageTests.scala index 20aea0e4..7cf9a544 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ImageTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ImageTests.scala @@ -10,21 +10,19 @@ import java.io.File import javax.imageio.ImageIO object ImageTests: - def assertImagesEquals(result: File, expected: File) = { + def assertImagesEquals(result: File, expected: File) = val expectedImage = ImageIO.read(expected) val resultImage = ImageIO.read(result) // println("Got image:") // println(renderAsText(resultImage, 50, 50)) assertEquals(expectedImage.getWidth, resultImage.getWidth, "Width was different") assertEquals(expectedImage.getHeight, resultImage.getHeight, "Height was different") - for { + for x <- 0 until expectedImage.getWidth y <- 0 until expectedImage.getHeight - } { + do val equal = expectedImage.getRGB(x, y) == resultImage.getRGB(x, y) assert(equal, s"Pixel $x, $y was different. Output file: ${result.getAbsolutePath}") - } - } def renderAsText(bufferedImage: BufferedImage, w: Int, h: Int) = val downscaled = bufferedImage.getScaledInstance(w, h, Image.SCALE_SMOOTH) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenE2eTest.scala similarity index 100% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenTests.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenE2eTest.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala index ec607279..7431960d 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala @@ -21,7 +21,7 @@ import scala.concurrent.ExecutionContext.Implicits class JuliaSet extends FunSuite: given ExecutionContext = Implicits.global - def runJuliaSet(referenceImgName: String)(using GContext): Unit = { + def runJuliaSet(referenceImgName: String)(using GContext): Unit = val dim = 4096 val max = 1 val RECURSION_LIMIT = 1000 @@ -70,7 +70,6 @@ class JuliaSet extends FunSuite: ImageUtility.renderToImage(r, dim, outputTemp.toPath) val referenceImage = getClass.getResource(referenceImgName) ImageTests.assertImagesEquals(outputTemp, new File(referenceImage.getPath)) - } test("Render julia set"): given GContext = new GContext diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala index 7cc5dc1b..200e16a6 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala @@ -3,15 +3,12 @@ package io.computenode.samples.cyfra.foton import io.computenode.cyfra import io.computenode.cyfra.* import io.computenode.cyfra.dsl.collections.GSeq -import io.computenode.cyfra.foton.animation.AnimatedFunctionRenderer.Parameters -import io.computenode.cyfra.foton.animation.{AnimatedFunction, AnimatedFunctionRenderer} -import io.computenode.cyfra.given -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.library.Color.{InterpolationThemes, interpolate} import io.computenode.cyfra.dsl.library.Math3D.* -import io.computenode.cyfra.dsl.given +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.foton.animation.AnimatedFunctionRenderer.Parameters import io.computenode.cyfra.foton.animation.AnimationFunctions.* +import io.computenode.cyfra.foton.animation.{AnimatedFunction, AnimatedFunctionRenderer} import java.nio.file.Paths import scala.concurrent.duration.DurationInt diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala index fa6393a1..bd2c65de 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala @@ -1,16 +1,13 @@ package io.computenode.samples.cyfra.foton +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.dsl.library.Color.hex import io.computenode.cyfra.foton.* import io.computenode.cyfra.foton.animation.AnimationFunctions.smooth import io.computenode.cyfra.foton.rt.animation.{AnimatedScene, AnimationRtRenderer} import io.computenode.cyfra.foton.rt.shapes.{Plane, Shape, Sphere} import io.computenode.cyfra.foton.rt.{Camera, Material} import io.computenode.cyfra.utility.Units.Milliseconds -import io.computenode.cyfra.given -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.dsl.* -import io.computenode.cyfra.dsl.library.Color.hex -import io.computenode.cyfra.dsl.given import java.nio.file.Paths import scala.concurrent.duration.DurationInt diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala index e498ce3e..b9c2279d 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala @@ -1,23 +1,17 @@ package io.computenode.samples.cyfra.oldsamples -import java.awt.image.BufferedImage -import java.io.File -import java.nio.file.Paths -import javax.imageio.ImageIO -import scala.collection.mutable -import scala.compiletime.error -import scala.concurrent.ExecutionContext.Implicits -import scala.concurrent.duration.DurationInt -import scala.concurrent.{Await, ExecutionContext} -import io.computenode.cyfra.given -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.dsl.* import io.computenode.cyfra.dsl.collections.GSeq -import io.computenode.cyfra.dsl.given +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.runtime.* import io.computenode.cyfra.runtime.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility -import io.computenode.cyfra.runtime.mem.Vec4FloatMem + +import java.nio.file.Paths +import scala.annotation.tailrec +import scala.collection.mutable +import scala.concurrent.ExecutionContext +import scala.concurrent.ExecutionContext.Implicits given GContext = new GContext() given ExecutionContext = Implicits.global @@ -44,15 +38,13 @@ def main = def lessThan(f: Vec3[Float32], f2: Float32): Vec3[Float32] = (when(f.x < f2)(1.0f).otherwise(0.0f), when(f.y < f2)(1.0f).otherwise(0.0f), when(f.z < f2)(1.0f).otherwise(0.0f)) - def linearToSRGB(rgb: Vec3[Float32]): Vec3[Float32] = { + def linearToSRGB(rgb: Vec3[Float32]): Vec3[Float32] = val clampedRgb = vclamp(rgb, 0.0f, 1.0f) mix(pow(clampedRgb, vec3(1.0f / 2.4f)) * 1.055f - vec3(0.055f), clampedRgb * 12.92f, lessThan(clampedRgb, 0.0031308f)) - } - def SRGBToLinear(rgb: Vec3[Float32]): Vec3[Float32] = { + def SRGBToLinear(rgb: Vec3[Float32]): Vec3[Float32] = val clampedRgb = vclamp(rgb, 0.0f, 1.0f) mix(pow((clampedRgb + vec3(0.055f)) * (1.0f / 1.055f), vec3(2.4f)), clampedRgb * (1.0f / 12.92f), lessThan(clampedRgb, 0.04045f)) - } def ACESFilm(x: Vec3[Float32]): Vec3[Float32] = val a = 2.51f @@ -132,7 +124,8 @@ def main = dist < radiusA + radiusB val existingSpheres = mutable.Set.empty[((Float, Float, Float), Float)] - def randomSphere(iter: Int = 0): Sphere = { + @tailrec + def randomSphere(iter: Int = 0): Sphere = if iter > 1000 then throw new Exception("Could not find a non-intersecting sphere") def nextFloatAny = rd.nextFloat() * 2f - 1f @@ -141,7 +134,7 @@ def main = val center = (nextFloatAny * 10, nextFloatAny * 10, nextFloatPos * 10 + 8f) val radius = nextFloatPos + 1.5f if existingSpheres.exists(s => scalaTwoSpheresIntersect(s._1, s._2, center, radius)) then randomSphere(iter + 1) - else { + else existingSpheres.add((center, radius)) def color = (nextFloatPos * 0.5f + 0.5f, nextFloatPos * 0.5f + 0.5f, nextFloatPos * 0.5f + 0.5f) val emissive = (0f, 0f, 0f) @@ -158,19 +151,16 @@ def main = 0.1f, (nextFloatPos, nextFloatPos, nextFloatPos), ) - } - } def randomSpheres(n: Int) = List.fill(n)(randomSphere()) - val flash = { // flash + val flash = // flash val x = -10f val mX = -5f val y = -10f val mY = 0f val z = -5f Sphere((-7.5f, -12f, -5f), 3f, (1f, 1f, 1f), (20f, 20f, 20f)) - } val spheres = (flash :: randomSpheres(20)).map(sp => sp.copy(center = sp.center + sceneTranslation.xyz)) val walls = List( @@ -243,21 +233,19 @@ def main = def function(): GFunction[RaytracingIteration, Vec4[Float32], Vec4[Float32]] = GFunction.from2D(dim): case (RaytracingIteration(frame), (xi: Int32, yi: Int32), lastFrame) => - def wangHash(seed: UInt32): UInt32 = { + def wangHash(seed: UInt32): UInt32 = val s1 = (seed ^ 61) ^ (seed >> 16) val s2 = s1 * 9 val s3 = s2 ^ (s2 >> 4) val s4 = s3 * 0x27d4eb2d s4 ^ (s4 >> 15) - } - def randomFloat(seed: UInt32): Random[Float32] = { + def randomFloat(seed: UInt32): Random[Float32] = val nextSeed = wangHash(seed) val f = nextSeed.asFloat / 4294967296.0f Random(f, nextSeed) - } - def randomVector(seed: UInt32): Random[Vec3[Float32]] = { + def randomVector(seed: UInt32): Random[Vec3[Float32]] = val Random(z, seed1) = randomFloat(seed) val z2 = z * 2.0f - 1.0f val Random(a, seed2) = randomFloat(seed1) @@ -266,15 +254,17 @@ def main = val x = r * cos(a2) val y = r * sin(a2) Random((x, y, z2), seed2) - } def scalarTriple(u: Vec3[Float32], v: Vec3[Float32], w: Vec3[Float32]): Float32 = (u cross v) dot w def testQuadTrace(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo, quad: Quad): RayHitInfo = val normal = normalize((quad.c - quad.a) cross (quad.c - quad.b)) - val fixedQuad = when((normal dot rayDir) > 0f) { - Quad(quad.d, quad.c, quad.b, quad.a, quad.color, quad.emissive) - } otherwise quad + val fixedQuad = + when((normal dot rayDir) > 0f): + Quad(quad.d, quad.c, quad.b, quad.a, quad.color, quad.emissive) + .otherwise: + quad + val fixedNormal = when((normal dot rayDir) > 0f)(-normal).otherwise(normal) val p = rayPos val q = rayPos + rayDir @@ -286,14 +276,15 @@ def main = val v = pa dot m def checkHit(intersectPoint: Vec3[Float32]): RayHitInfo = - val dist = when(abs(rayDir.x) > 0.1f) { - (intersectPoint.x - rayPos.x) / rayDir.x - }.elseWhen(abs(rayDir.y) > 0.1f) { - (intersectPoint.y - rayPos.y) / rayDir.y - }.otherwise { - (intersectPoint.z - rayPos.z) / rayDir.z - } - when(dist > minRayHitTime && dist < currentHit.dist) { + val dist = + when(abs(rayDir.x) > 0.1f): + (intersectPoint.x - rayPos.x) / rayDir.x + .elseWhen(abs(rayDir.y) > 0.1f): + (intersectPoint.y - rayPos.y) / rayDir.y + .otherwise: + (intersectPoint.z - rayPos.z) / rayDir.z + + when(dist > minRayHitTime && dist < currentHit.dist): RayHitInfo( dist, fixedNormal, @@ -307,24 +298,26 @@ def main = quad.refractionRoughness, quad.refractionColor, ) - } otherwise currentHit + .otherwise: + currentHit - when(v >= 0f) { + when(v >= 0f): val u = -(pb dot m) val w = scalarTriple(pq, pb, pa) - when(u >= 0f && w >= 0f) { + when(u >= 0f && w >= 0f): val denom = 1f / (u + v + w) val uu = u * denom val vv = v * denom val ww = w * denom val intersectPos = fixedQuad.a * uu + fixedQuad.b * vv + fixedQuad.c * ww checkHit(intersectPos) - } otherwise currentHit - } otherwise { + .otherwise: + currentHit + .otherwise: val pd = fixedQuad.d - p val u = pd dot m val w = scalarTriple(pq, pa, pd) - when(u >= 0f && w >= 0f) { + when(u >= 0f && w >= 0f): val negV = -v val denom = 1f / (u + negV + w) val uu = u * denom @@ -332,24 +325,24 @@ def main = val ww = w * denom val intersectPos = fixedQuad.a * uu + fixedQuad.d * vv + fixedQuad.c * ww checkHit(intersectPos) - } otherwise currentHit - } + .otherwise: + currentHit def testSphereTrace(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo, sphere: Sphere): RayHitInfo = val toRay = rayPos - sphere.center val b = toRay dot rayDir val c = (toRay dot toRay) - (sphere.radius * sphere.radius) val notHit = currentHit - when(c > 0f && b > 0f) { + when(c > 0f && b > 0f): notHit - } otherwise { + .otherwise: val discr = b * b - c - when(discr > 0f) { + when(discr > 0f): val initDist = -b - sqrt(discr) val fromInside = initDist < 0f val dist = when(fromInside)(-b + sqrt(discr)).otherwise(initDist) - when(dist > minRayHitTime && dist < currentHit.dist) { - val normal = normalize((rayPos + rayDir * dist - sphere.center) * (when(fromInside)(-1f).otherwise(1f))) + when(dist > minRayHitTime && dist < currentHit.dist): + val normal = normalize((rayPos + rayDir * dist - sphere.center) * when(fromInside)(-1f).otherwise(1f)) RayHitInfo( dist, normal, @@ -364,9 +357,10 @@ def main = sphere.refractionColor, fromInside, ) - } otherwise notHit - } otherwise notHit - } + .otherwise: + notHit + .otherwise: + notHit def testScene(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo): RayHitInfo = @@ -384,22 +378,20 @@ def main = def fresnelReflectAmount(n1: Float32, n2: Float32, normal: Vec3[Float32], incident: Vec3[Float32], f0: Float32, f90: Float32): Float32 = val r0 = ((n1 - n2) / (n1 + n2)) * ((n1 - n2) / (n1 + n2)) val cosX = -(normal dot incident) - when(n1 > n2) { + when(n1 > n2): val n = n1 / n2 val sinT2 = n * n * (1f - cosX * cosX) - when(sinT2 > 1f) { + when(sinT2 > 1f): f90 - } otherwise { + .otherwise: val cosX2 = sqrt(1.0f - sinT2) val x = 1.0f - cosX2 val ret = r0 + ((1.0f - r0) * x * x * x * x * x) mix(f0, f90, ret) - } - } otherwise { + .otherwise: val x = 1.0f - cosX val ret = r0 + ((1.0f - r0) * x * x * x * x * x) mix(f0, f90, ret) - } val MaxBounces = 8 def getColorForRay(startRayPos: Vec3[Float32], startRayDir: Vec3[Float32], initRngState: UInt32): RayTraceState = @@ -407,96 +399,94 @@ def main = GSeq .gen[RayTraceState]( first = initState, - next = { case state @ RayTraceState(rayPos, rayDir, color, throughput, rngState, _) => - - val noHit = RayHitInfo(superFar, (0f, 0f, 0f), (0f, 0f, 0f), (0f, 0f, 0f)) - val testResult = testScene(rayPos, rayDir, noHit) - when(testResult.dist < superFar) { - - val throughput2 = when(testResult.fromInside) { - throughput mulV exp[Vec3[Float32]](-testResult.refractionColor * testResult.dist) - }.otherwise { - throughput - } - - val specularChance = when(testResult.percentSpecular > 0.0f) { - fresnelReflectAmount( - when(testResult.fromInside)(testResult.indexOfRefraction).otherwise(1.0f), - when(!testResult.fromInside)(testResult.indexOfRefraction).otherwise(1.0f), - rayDir, - testResult.normal, - testResult.percentSpecular, - 1.0f, - ) - }.otherwise { - 0f - } - - val refractionChance = when(specularChance > 0.0f) { - testResult.refractionChance * ((1.0f - specularChance) / (1.0f - testResult.percentSpecular)) - } otherwise testResult.refractionChance - - val Random(rayRoll, nextRngState1) = randomFloat(rngState) - val doSpecular = when(specularChance > 0.0f && rayRoll < specularChance) { - 1.0f - }.otherwise(0.0f) - - val doRefraction = when(refractionChance > 0.0f && doSpecular === 0.0f && rayRoll < specularChance + refractionChance) { - 1.0f - }.otherwise(0.0f) - - val rayProbability = when(doSpecular === 1.0f) { - specularChance - }.elseWhen(doRefraction === 1.0f) { - refractionChance - }.otherwise { - 1.0f - (specularChance + refractionChance) - } - - val rayProbabilityCorrected = max(rayProbability, 0.01f) - - val nextRayPos = when(doRefraction === 1.0f) { - (rayPos + rayDir * testResult.dist) - (testResult.normal * rayPosNormalNudge) - }.otherwise { - (rayPos + rayDir * testResult.dist) + (testResult.normal * rayPosNormalNudge) - } - - val Random(randomVec1, nextRngState2) = randomVector(nextRngState1) - val diffuseRayDir = normalize(testResult.normal + randomVec1) - val specularRayDirPerfect = reflect(rayDir, testResult.normal) - val specularRayDir = normalize(mix(specularRayDirPerfect, diffuseRayDir, testResult.roughness * testResult.roughness)) - - val Random(randomVec2, nextRngState3) = randomVector(nextRngState2) - val refractionRayDirPerfect = - refract( - rayDir, - testResult.normal, - when(testResult.fromInside)(testResult.indexOfRefraction).otherwise(1.0f / testResult.indexOfRefraction), - ) - val refractionRayDir = - normalize( - mix( - refractionRayDirPerfect, - normalize(-testResult.normal + randomVec2), - testResult.refractionRoughness * testResult.refractionRoughness, - ), - ) - - val rayDirSpecular = mix(diffuseRayDir, specularRayDir, doSpecular) - val rayDirRefracted = mix(rayDirSpecular, refractionRayDir, doRefraction) - - val nextColor = (throughput2 mulV testResult.emissive) addV color - - val nextThroughput = when(doRefraction === 0.0f) { - throughput2 mulV mix[Vec3[Float32]](testResult.albedo, testResult.specularColor, doSpecular); - }.otherwise(throughput2) - - val throughputRayProb = nextThroughput * (1.0f / rayProbabilityCorrected) - - RayTraceState(nextRayPos, rayDirRefracted, nextColor, throughputRayProb, nextRngState3) - } otherwise RayTraceState(rayPos, rayDir, color, throughput, rngState, true) - - }, + next = + case state @ RayTraceState(rayPos, rayDir, color, throughput, rngState, _) => + val noHit = RayHitInfo(superFar, (0f, 0f, 0f), (0f, 0f, 0f), (0f, 0f, 0f)) + val testResult = testScene(rayPos, rayDir, noHit) + when(testResult.dist < superFar): + val throughput2 = when(testResult.fromInside): + throughput mulV exp[Vec3[Float32]](-testResult.refractionColor * testResult.dist) + .otherwise: + throughput + + val specularChance = when(testResult.percentSpecular > 0.0f): + fresnelReflectAmount( + when(testResult.fromInside)(testResult.indexOfRefraction).otherwise(1.0f), + when(!testResult.fromInside)(testResult.indexOfRefraction).otherwise(1.0f), + rayDir, + testResult.normal, + testResult.percentSpecular, + 1.0f, + ) + .otherwise: + 0f + + val refractionChance = when(specularChance > 0.0f): + testResult.refractionChance * ((1.0f - specularChance) / (1.0f - testResult.percentSpecular)) + .otherwise: + testResult.refractionChance + + val Random(rayRoll, nextRngState1) = randomFloat(rngState) + val doSpecular = when(specularChance > 0.0f && rayRoll < specularChance): + 1.0f + .otherwise: + 0.0f + + val doRefraction = when(refractionChance > 0.0f && doSpecular === 0.0f && rayRoll < specularChance + refractionChance): + 1.0f + .otherwise: + 0.0f + + val rayProbability = when(doSpecular === 1.0f): + specularChance + .elseWhen(doRefraction === 1.0f): + refractionChance + .otherwise: + 1.0f - (specularChance + refractionChance) + + val rayProbabilityCorrected = max(rayProbability, 0.01f) + + val nextRayPos = when(doRefraction === 1.0f): + (rayPos + rayDir * testResult.dist) - (testResult.normal * rayPosNormalNudge) + .otherwise: + (rayPos + rayDir * testResult.dist) + (testResult.normal * rayPosNormalNudge) + + val Random(randomVec1, nextRngState2) = randomVector(nextRngState1) + val diffuseRayDir = normalize(testResult.normal + randomVec1) + val specularRayDirPerfect = reflect(rayDir, testResult.normal) + val specularRayDir = normalize(mix(specularRayDirPerfect, diffuseRayDir, testResult.roughness * testResult.roughness)) + + val Random(randomVec2, nextRngState3) = randomVector(nextRngState2) + val refractionRayDirPerfect = + refract( + rayDir, + testResult.normal, + when(testResult.fromInside)(testResult.indexOfRefraction).otherwise(1.0f / testResult.indexOfRefraction), + ) + val refractionRayDir = + normalize( + mix( + refractionRayDirPerfect, + normalize(-testResult.normal + randomVec2), + testResult.refractionRoughness * testResult.refractionRoughness, + ), + ) + + val rayDirSpecular = mix(diffuseRayDir, specularRayDir, doSpecular) + val rayDirRefracted = mix(rayDirSpecular, refractionRayDir, doRefraction) + + val nextColor = (throughput2 mulV testResult.emissive) addV color + + val nextThroughput = when(doRefraction === 0.0f): + throughput2 mulV mix[Vec3[Float32]](testResult.albedo, testResult.specularColor, doSpecular) + .otherwise: + throughput2 + + val throughputRayProb = nextThroughput * (1.0f / rayProbabilityCorrected) + + RayTraceState(nextRayPos, rayDirRefracted, nextColor, throughputRayProb, nextRngState3) + .otherwise: + RayTraceState(rayPos, rayDir, color, throughput, rngState, true), ) .limit(MaxBounces) .takeWhile(!_.finished) @@ -528,9 +518,10 @@ def main = .limit(pixelIterationsPerFrame) .fold((0f, 0f, 0f), { case (acc, RenderIteration(color, _)) => acc + (color * (1.0f / pixelIterationsPerFrame.toFloat)) }) - when(frame === 0) { + when(frame === 0): (color, 1.0f) - } otherwise mix(lastFrame.at(xi, yi), (color, 1.0f), vec4(1.0f / (frame.asFloat + 1f))) + .otherwise: + mix(lastFrame.at(xi, yi), (color, 1.0f), vec4(1.0f / (frame.asFloat + 1f))) val initialMem = Array.fill(dim * dim)((0.5f, 0.5f, 0.5f, 0.5f)) val renders = 100 diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/1sample.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/1sample.scala index 56d9dd11..518687d3 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/1sample.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/1sample.scala @@ -1,19 +1,13 @@ package io.computenode.samples.cyfra.slides -import io.computenode.cyfra.given - -import scala.concurrent.Await -import scala.concurrent.duration.given -import io.computenode.cyfra.given +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.dsl.* -import io.computenode.cyfra.dsl.given import io.computenode.cyfra.runtime.mem.FloatMem given GContext = new GContext() @main -def sample = +def sample() = val gpuFunction = GFunction: (value: Float32) => value * 2f diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala index c08855e9..6575bbaa 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala @@ -1,26 +1,16 @@ package io.computenode.samples.cyfra.slides -import java.awt.image.BufferedImage -import java.io.File -import java.nio.file.Paths -import javax.imageio.ImageIO -import scala.collection.mutable -import scala.compiletime.error -import scala.concurrent.ExecutionContext.Implicits -import scala.concurrent.duration.DurationInt -import scala.concurrent.{Await, ExecutionContext} -import io.computenode.cyfra.given -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.dsl.* +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.dsl.given import io.computenode.cyfra.dsl.struct.GStruct.Empty +import io.computenode.cyfra.runtime.* import io.computenode.cyfra.runtime.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility -import io.computenode.cyfra.runtime.mem.Vec4FloatMem + +import java.nio.file.Paths @main -def simpleray = +def simpleRay() = val dim = 1024 val fovDeg = 60 @@ -32,11 +22,10 @@ def simpleray = val toRay = rayPos - sphereCenter val b = toRay dot rayDirection val c = (toRay dot toRay) - (sphereRadius * sphereRadius) - when((c < 0f || b < 0f) && b * b - c > 0f) { + when((c < 0f || b < 0f) && b * b - c > 0f): (1f, 1f, 1f, 1f) - } otherwise { + .otherwise: (0f, 0f, 0f, 1f) - } val raytracing: GFunction[Empty, Vec4[Float32], Vec4[Float32]] = GFunction.from2D(dim): case (_, (xi: Int32, yi: Int32), _) => diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala index 70fdd546..7784be27 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala @@ -1,29 +1,18 @@ package io.computenode.samples.cyfra.slides import io.computenode.cyfra.* -import io.computenode.cyfra.dsl.given -import io.computenode.cyfra.dsl.* import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.struct.GStruct.Empty - -import java.awt.image.BufferedImage -import java.io.File -import java.nio.file.Paths -import javax.imageio.ImageIO -import scala.collection.mutable -import scala.compiletime.error -import scala.concurrent.ExecutionContext.Implicits -import scala.concurrent.duration.DurationInt -import scala.concurrent.{Await, ExecutionContext} -import io.computenode.cyfra.given import io.computenode.cyfra.runtime.* import io.computenode.cyfra.runtime.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility -import io.computenode.cyfra.runtime.mem.Vec4FloatMem + +import java.nio.file.Paths @main -def rays = +def rays() = val raysPerPixel = 10 val dim = 1024 val fovDeg = 60 @@ -49,26 +38,28 @@ def rays = val b = toRay dot rayDir val c = (toRay dot toRay) - (sphere.radius * sphere.radius) val notHit = currentHit - when(c > 0f && b > 0f) { + when(c > 0f && b > 0f): notHit - } otherwise { + .otherwise: val discr = b * b - c - when(discr > 0f) { + when(discr > 0f): val initDist = -b - sqrt(discr) val fromInside = initDist < 0f val dist = when(fromInside)(-b + sqrt(discr)).otherwise(initDist) - when(dist > minRayHitTime && dist < currentHit.dist) { + when(dist > minRayHitTime && dist < currentHit.dist): val normal = normalize(rayPos + rayDir * dist - sphere.center) RayHitInfo(dist, normal, sphere.color, sphere.emissive) - } otherwise notHit - } otherwise notHit - } + .otherwise: + notHit + .otherwise: + notHit def testQuadTrace(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo, quad: Quad): RayHitInfo = val normal = normalize((quad.c - quad.a) cross (quad.c - quad.b)) - val fixedQuad = when((normal dot rayDir) > 0f) { + val fixedQuad = when((normal dot rayDir) > 0f): Quad(quad.d, quad.c, quad.b, quad.a, quad.color, quad.emissive) - } otherwise quad + .otherwise: + quad val fixedNormal = when((normal dot rayDir) > 0f)(-normal).otherwise(normal) val p = rayPos val q = rayPos + rayDir @@ -80,33 +71,35 @@ def rays = val v = pa dot m def checkHit(intersectPoint: Vec3[Float32]): RayHitInfo = - val dist = when(abs(rayDir.x) > 0.1f) { + val dist = when(abs(rayDir.x) > 0.1f): (intersectPoint.x - rayPos.x) / rayDir.x - }.elseWhen(abs(rayDir.y) > 0.1f) { + .elseWhen(abs(rayDir.y) > 0.1f): (intersectPoint.y - rayPos.y) / rayDir.y - }.otherwise { + .otherwise: (intersectPoint.z - rayPos.z) / rayDir.z - } - when(dist > minRayHitTime && dist < currentHit.dist) { + + when(dist > minRayHitTime && dist < currentHit.dist): RayHitInfo(dist, fixedNormal, quad.color, quad.emissive) - } otherwise currentHit + .otherwise: + currentHit - when(v >= 0f) { + when(v >= 0f): val u = -(pb dot m) val w = scalarTriple(pq, pb, pa) - when(u >= 0f && w >= 0f) { + when(u >= 0f && w >= 0f): val denom = 1f / (u + v + w) val uu = u * denom val vv = v * denom val ww = w * denom val intersectPos = fixedQuad.a * uu + fixedQuad.b * vv + fixedQuad.c * ww checkHit(intersectPos) - } otherwise currentHit - } otherwise { + .otherwise: + currentHit + .otherwise: val pd = fixedQuad.d - p val u = pd dot m val w = scalarTriple(pq, pa, pd) - when(u >= 0f && w >= 0f) { + when(u >= 0f && w >= 0f): val negV = -v val denom = 1f / (u + negV + w) val uu = u * denom @@ -114,8 +107,8 @@ def rays = val ww = w * denom val intersectPos = fixedQuad.a * uu + fixedQuad.d * vv + fixedQuad.c * ww checkHit(intersectPos) - } otherwise currentHit - } + .otherwise: + currentHit val sphere = Sphere(center = (1.5f, 1.5f, 4f), radius = 0.5f, color = (1f, 1f, 1f), emissive = (3f, 3f, 3f)) diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala index 226ffab1..4ecd8e8b 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala +++ b/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala @@ -1,32 +1,30 @@ package io.computenode.samples.cyfra.slides -import java.nio.file.Paths -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.dsl.given -import io.computenode.cyfra.dsl.* import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.struct.GStruct.Empty +import io.computenode.cyfra.runtime.* import io.computenode.cyfra.runtime.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility -def wangHash(seed: UInt32): UInt32 = { +import java.nio.file.Paths + +def wangHash(seed: UInt32): UInt32 = val s1 = (seed ^ 61) ^ (seed >> 16) val s2 = s1 * 9 val s3 = s2 ^ (s2 >> 4) val s4 = s3 * 0x27d4eb2d s4 ^ (s4 >> 15) -} case class Random[T <: Value](value: T, nextSeed: UInt32) -def randomFloat(seed: UInt32): Random[Float32] = { +def randomFloat(seed: UInt32): Random[Float32] = val nextSeed = wangHash(seed) val f = nextSeed.asFloat / 4294967296.0f Random(f, nextSeed) -} -def randomVector(seed: UInt32): Random[Vec3[Float32]] = { +def randomVector(seed: UInt32): Random[Vec3[Float32]] = val Random(z, seed1) = randomFloat(seed) val z2 = z * 2.0f - 1.0f val Random(a, seed2) = randomFloat(seed1) @@ -35,10 +33,9 @@ def randomVector(seed: UInt32): Random[Vec3[Float32]] = { val x = r * cos(a2) val y = r * sin(a2) Random((x, y, z2), seed2) -} @main -def randomRays = +def randomRays() = val raysPerPixel = 10 val dim = 1024 val fovDeg = 80 @@ -71,26 +68,28 @@ def randomRays = val b = toRay dot rayDir val c = (toRay dot toRay) - (sphere.radius * sphere.radius) val notHit = currentHit - when(c > 0f && b > 0f) { + when(c > 0f && b > 0f): notHit - } otherwise { + .otherwise: val discr = b * b - c - when(discr > 0f) { + when(discr > 0f): val initDist = -b - sqrt(discr) val fromInside = initDist < 0f val dist = when(fromInside)(-b + sqrt(discr)).otherwise(initDist) - when(dist > minRayHitTime && dist < currentHit.dist) { + when(dist > minRayHitTime && dist < currentHit.dist): val normal = normalize(rayPos + rayDir * dist - sphere.center) RayHitInfo(dist, normal, sphere.color, sphere.emissive) - } otherwise notHit - } otherwise notHit - } + .otherwise: + notHit + .otherwise: + notHit def testQuadTrace(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo, quad: Quad): RayHitInfo = val normal = normalize((quad.c - quad.a) cross (quad.c - quad.b)) - val fixedQuad = when((normal dot rayDir) > 0f) { + val fixedQuad = when((normal dot rayDir) > 0f): Quad(quad.d, quad.c, quad.b, quad.a, quad.color, quad.emissive) - } otherwise quad + .otherwise: + quad val fixedNormal = when((normal dot rayDir) > 0f)(-normal).otherwise(normal) val p = rayPos val q = rayPos + rayDir @@ -102,33 +101,34 @@ def randomRays = val v = pa dot m def checkHit(intersectPoint: Vec3[Float32]): RayHitInfo = - val dist = when(abs(rayDir.x) > 0.1f) { + val dist = when(abs(rayDir.x) > 0.1f): (intersectPoint.x - rayPos.x) / rayDir.x - }.elseWhen(abs(rayDir.y) > 0.1f) { + .elseWhen(abs(rayDir.y) > 0.1f): (intersectPoint.y - rayPos.y) / rayDir.y - }.otherwise { + .otherwise: (intersectPoint.z - rayPos.z) / rayDir.z - } - when(dist > minRayHitTime && dist < currentHit.dist) { + when(dist > minRayHitTime && dist < currentHit.dist): RayHitInfo(dist, fixedNormal, quad.color, quad.emissive) - } otherwise currentHit + .otherwise: + currentHit - when(v >= 0f) { + when(v >= 0f): val u = -(pb dot m) val w = scalarTriple(pq, pb, pa) - when(u >= 0f && w >= 0f) { + when(u >= 0f && w >= 0f): val denom = 1f / (u + v + w) val uu = u * denom val vv = v * denom val ww = w * denom val intersectPos = fixedQuad.a * uu + fixedQuad.b * vv + fixedQuad.c * ww checkHit(intersectPos) - } otherwise currentHit - } otherwise { + .otherwise: + currentHit + .otherwise: val pd = fixedQuad.d - p val u = pd dot m val w = scalarTriple(pq, pa, pd) - when(u >= 0f && w >= 0f) { + when(u >= 0f && w >= 0f): val negV = -v val denom = 1f / (u + negV + w) val uu = u * denom @@ -136,8 +136,8 @@ def randomRays = val ww = w * denom val intersectPos = fixedQuad.a * uu + fixedQuad.d * vv + fixedQuad.c * ww checkHit(intersectPos) - } otherwise currentHit - } + .otherwise: + currentHit val sphere = Sphere(center = (0f, 1.5f, 2f), radius = 0.5f, color = (1f, 1f, 1f), emissive = (30f, 30f, 30f)) diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunction.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunction.scala index 2212e11b..e6772e07 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunction.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunction.scala @@ -1,23 +1,11 @@ package io.computenode.cyfra.foton.animation -import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.collections.GArray2D import io.computenode.cyfra.foton.animation.AnimatedFunction.FunctionArguments import io.computenode.cyfra.foton.animation.AnimationFunctions.AnimationInstant -import io.computenode.cyfra.foton.animation.AnimationRenderer -import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration -import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration -import io.computenode.cyfra.foton.rt.RtRenderer import io.computenode.cyfra.utility.Units.Milliseconds -import io.computenode.cyfra.utility.Utility.timed -import io.computenode.cyfra.{*, given} - -import java.nio.file.{Path, Paths} -import scala.annotation.targetName -import scala.concurrent.Await -import scala.concurrent.duration.DurationInt case class AnimatedFunction(fn: FunctionArguments => AnimationInstant ?=> Vec4[Float32], duration: Milliseconds) extends AnimationRenderer.Scene diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala index 61b05aee..d8d6dff5 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala @@ -1,26 +1,17 @@ package io.computenode.cyfra.foton.animation -import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra +import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.foton.animation.AnimatedFunctionRenderer.{AnimationIteration, RenderFn} import io.computenode.cyfra.foton.animation.AnimationFunctions.AnimationInstant -import io.computenode.cyfra.foton.animation.AnimationRenderer -import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration -import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration -import io.computenode.cyfra.foton.rt.RtRenderer -import io.computenode.cyfra.runtime.{GContext, GFunction, UniformContext} -import io.computenode.cyfra.utility.Units.Milliseconds -import io.computenode.cyfra.utility.Utility.timed import io.computenode.cyfra.runtime.mem.GMem.fRGBA import io.computenode.cyfra.runtime.mem.Vec4FloatMem +import io.computenode.cyfra.runtime.{GContext, GFunction, UniformContext} -import java.nio.file.{Path, Paths} +import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContext.Implicits -import scala.concurrent.{Await, ExecutionContext} -import scala.concurrent.duration.DurationInt class AnimatedFunctionRenderer(params: AnimatedFunctionRenderer.Parameters) extends AnimationRenderer[AnimatedFunction, AnimatedFunctionRenderer.RenderFn](params): diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationFunctions.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationFunctions.scala index 28c92809..e1aa34e4 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationFunctions.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationFunctions.scala @@ -1,15 +1,10 @@ package io.computenode.cyfra.foton.animation -import io.computenode.cyfra.given import io.computenode.cyfra -import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration import io.computenode.cyfra.* import io.computenode.cyfra.dsl.Value.Float32 -import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.utility.Units.Milliseconds -import io.computenode.cyfra.utility.Utility.timed -import io.computenode.cyfra.foton.rt.RtRenderer object AnimationFunctions: diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala index 72d0f032..df4ea7ca 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala @@ -2,21 +2,14 @@ package io.computenode.cyfra.foton.animation import io.computenode.cyfra import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration -import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration -import io.computenode.cyfra.foton.rt.RtRenderer -import io.computenode.cyfra.foton.rt.animation.AnimatedScene +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.runtime.GFunction +import io.computenode.cyfra.runtime.mem.GMem.fRGBA +import io.computenode.cyfra.utility.ImageUtility import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra.utility.Utility.timed -import io.computenode.cyfra.{*, given} -import io.computenode.cyfra.utility.ImageUtility -import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.runtime.mem.GMem.fRGBA -import java.nio.file.{Path, Paths} -import scala.concurrent.Await -import scala.concurrent.duration.DurationInt +import java.nio.file.Path trait AnimationRenderer[S <: AnimationRenderer.Scene, F <: GFunction[?, Vec4[Float32], Vec4[Float32]]](params: AnimationRenderer.Parameters): @@ -25,7 +18,7 @@ trait AnimationRenderer[S <: AnimationRenderer.Scene, F <: GFunction[?, Vec4[Flo def renderFramesToDir(scene: S, destinationPath: Path): Unit = destinationPath.toFile.mkdirs() val images = renderFrames(scene) - val totalFrames = Math.ceil(scene.duration.toFloat / msPerFrame).toInt + val totalFrames = Math.ceil(scene.duration / msPerFrame).toInt val requiredDigits = Math.ceil(Math.log10(totalFrames)).toInt images.zipWithIndex.foreach: case (image, i) => @@ -35,7 +28,7 @@ trait AnimationRenderer[S <: AnimationRenderer.Scene, F <: GFunction[?, Vec4[Flo def renderFrames(scene: S): LazyList[Array[fRGBA]] = val function = renderFunction(scene) - val totalFrames = Math.ceil(scene.duration.toFloat / msPerFrame).toInt + val totalFrames = Math.ceil(scene.duration / msPerFrame).toInt val timestamps = LazyList.range(0, totalFrames).map(_ * msPerFrame) timestamps.zipWithIndex.map { case (time, frame) => timed(s"Animated frame $frame/$totalFrames"): diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala index e65f94f1..6a314eb5 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala @@ -1,25 +1,18 @@ package io.computenode.cyfra.foton.rt import io.computenode.cyfra -import ImageRtRenderer.RaytracingIteration -import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo -import io.computenode.cyfra.utility.Utility.timed -import io.computenode.cyfra.foton.rt.ImageRtRenderer import io.computenode.cyfra.* import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.foton.rt.shapes.{Box, Sphere} -import io.computenode.cyfra.runtime.{GFunction, UniformContext} -import io.computenode.cyfra.runtime.mem.GMem.fRGBA -import io.computenode.cyfra.utility.ImageUtility -import io.computenode.cyfra.runtime.mem.Vec4FloatMem import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration +import io.computenode.cyfra.runtime.mem.GMem.fRGBA +import io.computenode.cyfra.runtime.mem.Vec4FloatMem +import io.computenode.cyfra.runtime.{GFunction, UniformContext} +import io.computenode.cyfra.utility.ImageUtility +import io.computenode.cyfra.utility.Utility.timed -import java.nio.file.{Path, Paths} -import scala.collection.mutable -import scala.concurrent.ExecutionContext.Implicits -import scala.concurrent.duration.DurationInt -import scala.concurrent.{Await, ExecutionContext} +import java.nio.file.Path class ImageRtRenderer(params: ImageRtRenderer.Parameters) extends RtRenderer(params): diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala index b35b37b2..1c591a71 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala @@ -1,25 +1,19 @@ package io.computenode.cyfra.foton.rt import io.computenode.cyfra -import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo -import io.computenode.cyfra.utility.Utility.timed -import io.computenode.cyfra.foton.rt.RtRenderer -import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.foton.rt.shapes.{Box, Sphere} +import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.collections.{GArray2D, GSeq} +import io.computenode.cyfra.dsl.control.Pure.pure import io.computenode.cyfra.dsl.library.Color.* import io.computenode.cyfra.dsl.library.Math3D.* +import io.computenode.cyfra.dsl.library.Random +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo import io.computenode.cyfra.runtime.GContext -import io.computenode.cyfra.dsl.control.Pure.pure -import java.nio.file.{Path, Paths} -import scala.collection.mutable +import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContext.Implicits -import scala.concurrent.duration.DurationInt -import scala.concurrent.{Await, ExecutionContext} -import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.collections.{GArray2D, GSeq} -import io.computenode.cyfra.dsl.library.Random -import io.computenode.cyfra.dsl.struct.GStruct class RtRenderer(params: RtRenderer.Parameters): @@ -37,14 +31,13 @@ class RtRenderer(params: RtRenderer.Parameters): ) extends GStruct[RayTraceState] private def applyRefractionThroughput(state: RayTraceState, testResult: RayHitInfo) = pure: - when(testResult.fromInside) { + when(testResult.fromInside): state.throughput mulV exp[Vec3[Float32]](-testResult.material.refractionColor * testResult.dist) - }.otherwise { + .otherwise: state.throughput - } private def calculateSpecularChance(state: RayTraceState, testResult: RayHitInfo) = pure: - when(testResult.material.percentSpecular > 0.0f) { + when(testResult.material.percentSpecular > 0.0f): val material = testResult.material fresnelReflectAmount( when(testResult.fromInside)(material.indexOfRefraction).otherwise(1.0f), @@ -54,44 +47,42 @@ class RtRenderer(params: RtRenderer.Parameters): material.percentSpecular, 1.0f, ) - }.otherwise { + .otherwise: 0f - } private def getRefractionChance(state: RayTraceState, testResult: RayHitInfo, specularChance: Float32) = pure: - when(specularChance > 0.0f) { + when(specularChance > 0.0f): testResult.material.refractionChance * ((1.0f - specularChance) / (1.0f - testResult.material.percentSpecular)) - } otherwise testResult.material.refractionChance + .otherwise: + testResult.material.refractionChance private case class RayAction(doSpecular: Float32, doRefraction: Float32, rayProbability: Float32) private def getRayAction(state: RayTraceState, testResult: RayHitInfo, random: Random): (RayAction, Random) = val specularChance = calculateSpecularChance(state, testResult) val refractionChance = getRefractionChance(state, testResult, specularChance) val (nextRandom, rayRoll) = random.next[Float32] - val doSpecular = when(specularChance > 0.0f && rayRoll < specularChance) { + val doSpecular = when(specularChance > 0.0f && rayRoll < specularChance): 1.0f - }.otherwise(0.0f) - val doRefraction = when(refractionChance > 0.0f && doSpecular === 0.0f && rayRoll < specularChance + refractionChance) { + .otherwise(0.0f) + val doRefraction = when(refractionChance > 0.0f && doSpecular === 0.0f && rayRoll < specularChance + refractionChance): 1.0f - }.otherwise(0.0f) + .otherwise(0.0f) - val rayProbability = when(doSpecular === 1.0f) { + val rayProbability = when(doSpecular === 1.0f): specularChance - }.elseWhen(doRefraction === 1.0f) { + .elseWhen(doRefraction === 1.0f): refractionChance - }.otherwise { + .otherwise: 1.0f - (specularChance + refractionChance) - } (RayAction(doSpecular, doRefraction, max(rayProbability, 0.01f)), nextRandom) private val rayPosNormalNudge = 0.01f private def getNextRayPos(rayPos: Vec3[Float32], rayDir: Vec3[Float32], testResult: RayHitInfo, doRefraction: Float32) = pure: - when(doRefraction =~= 1.0f) { + when(doRefraction =~= 1.0f): (rayPos + rayDir * testResult.dist) - (testResult.normal * rayPosNormalNudge) - }.otherwise { + .otherwise: (rayPos + rayDir * testResult.dist) + (testResult.normal * rayPosNormalNudge) - } private def getRefractionRayDir(rayDir: Vec3[Float32], testResult: RayHitInfo, random: Random) = val (random2, randomVec) = random.next[Vec3[Float32]] @@ -117,9 +108,10 @@ class RtRenderer(params: RtRenderer.Parameters): rayProbability: Float32, refractedThroughput: Vec3[Float32], ) = pure: - val nextThroughput = when(doRefraction === 0.0f) { - refractedThroughput mulV mix[Vec3[Float32]](testResult.material.color, testResult.material.specularColor, doSpecular); - }.otherwise(refractedThroughput) + val nextThroughput = when(doRefraction === 0.0f): + refractedThroughput mulV mix[Vec3[Float32]](testResult.material.color, testResult.material.specularColor, doSpecular) + .otherwise: + refractedThroughput nextThroughput * (1.0f / rayProbability) private def bounceRay(startRayPos: Vec3[Float32], startRayDir: Vec3[Float32], random: Random, scene: Scene): RayTraceState = @@ -127,35 +119,35 @@ class RtRenderer(params: RtRenderer.Parameters): GSeq .gen[RayTraceState]( first = initState, - next = { case state @ RayTraceState(rayPos, rayDir, color, throughput, random, _) => - - val noHit = RayHitInfo(params.superFar, vec3(0f), Material.Zero) - val testResult: RayHitInfo = scene.rayTest(rayPos, rayDir, noHit) + next = + case state @ RayTraceState(rayPos, rayDir, color, throughput, random, _) => + val noHit = RayHitInfo(params.superFar, vec3(0f), Material.Zero) + val testResult: RayHitInfo = scene.rayTest(rayPos, rayDir, noHit) - when(testResult.dist < params.superFar) { - val refractedThroughput = applyRefractionThroughput(state, testResult) + when(testResult.dist < params.superFar): + val refractedThroughput = applyRefractionThroughput(state, testResult) - val (RayAction(doSpecular, doRefraction, rayProbability), random2) = getRayAction(state, testResult, random) + val (RayAction(doSpecular, doRefraction, rayProbability), random2) = getRayAction(state, testResult, random) - val nextRayPos = getNextRayPos(rayPos, rayDir, testResult, doRefraction) + val nextRayPos = getNextRayPos(rayPos, rayDir, testResult, doRefraction) - val (random3, randomVec1) = random2.next[Vec3[Float32]] - val diffuseRayDir = normalize(testResult.normal + randomVec1) - val specularRayDirPerfect = reflect(rayDir, testResult.normal) - val specularRayDir = normalize(mix(specularRayDirPerfect, diffuseRayDir, testResult.material.roughness * testResult.material.roughness)) + val (random3, randomVec1) = random2.next[Vec3[Float32]] + val diffuseRayDir = normalize(testResult.normal + randomVec1) + val specularRayDirPerfect = reflect(rayDir, testResult.normal) + val specularRayDir = normalize(mix(specularRayDirPerfect, diffuseRayDir, testResult.material.roughness * testResult.material.roughness)) - val (refractionRayDir, random4) = getRefractionRayDir(rayDir, testResult, random3) + val (refractionRayDir, random4) = getRefractionRayDir(rayDir, testResult, random3) - val rayDirSpecular = mix(diffuseRayDir, specularRayDir, doSpecular) - val rayDirRefracted = mix(rayDirSpecular, refractionRayDir, doRefraction) + val rayDirSpecular = mix(diffuseRayDir, specularRayDir, doSpecular) + val rayDirRefracted = mix(rayDirSpecular, refractionRayDir, doRefraction) - val nextColor = (refractedThroughput mulV testResult.material.emissive) addV color + val nextColor = (refractedThroughput mulV testResult.material.emissive) addV color - val throughputRayProb = getThroughput(testResult, doSpecular, doRefraction, rayProbability, refractedThroughput) + val throughputRayProb = getThroughput(testResult, doSpecular, doRefraction, rayProbability, refractedThroughput) - RayTraceState(nextRayPos, rayDirRefracted, nextColor, throughputRayProb, random4) - } otherwise RayTraceState(rayPos, rayDir, color, throughput, random, true) - }, + RayTraceState(nextRayPos, rayDirRefracted, nextColor, throughputRayProb, random4) + .otherwise: + RayTraceState(rayPos, rayDir, color, throughput, random, true), ) .limit(params.maxBounces) .takeWhile(!_.finished) @@ -190,9 +182,10 @@ class RtRenderer(params: RtRenderer.Parameters): val colorCorrected = linearToSRGB(color) - when(frame === 0) { + when(frame === 0): (colorCorrected, 1.0f) - } otherwise mix(lastFrame.at(xi, yi), (colorCorrected, 1.0f), vec4(1.0f / (frame.asFloat + 1f))) + .otherwise: + mix(lastFrame.at(xi, yi), (colorCorrected, 1.0f), vec4(1.0f / (frame.asFloat + 1f))) object RtRenderer: trait Parameters: diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/Scene.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/Scene.scala index 46d47300..ef7a03b6 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/Scene.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/Scene.scala @@ -3,8 +3,7 @@ package io.computenode.cyfra.foton.rt import io.computenode.cyfra.dsl.Value.{Float32, Vec3} import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo import io.computenode.cyfra.foton.rt.shapes.{Shape, ShapeCollection} -import io.computenode.cyfra.{*, given} -import izumi.reflect.Tag +import io.computenode.cyfra.given import scala.util.chaining.* diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala index 5367f800..2674c237 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala @@ -2,22 +2,14 @@ package io.computenode.cyfra.foton.rt.animation import io.computenode.cyfra import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.animation.AnimationRenderer -import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration -import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration import io.computenode.cyfra.foton.rt.RtRenderer -import io.computenode.cyfra.runtime.{GFunction, UniformContext} +import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration import io.computenode.cyfra.runtime.mem.GMem.fRGBA -import io.computenode.cyfra.utility.Units.Milliseconds -import io.computenode.cyfra.utility.Utility.timed import io.computenode.cyfra.runtime.mem.Vec4FloatMem -import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.dsl.given - -import java.nio.file.{Path, Paths} -import scala.concurrent.Await -import scala.concurrent.duration.DurationInt +import io.computenode.cyfra.runtime.{GFunction, UniformContext} class AnimationRtRenderer(params: AnimationRtRenderer.Parameters) extends RtRenderer(params) diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Box.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Box.scala index 58ca8bf5..fe980b9e 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Box.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Box.scala @@ -30,16 +30,14 @@ object Box: val tEnter = max(tMinX, tMinY, tMinZ) val tExit = min(tMaxX, tMaxY, tMaxZ) - when(tEnter < tExit || tExit < 0.0f) { + when(tEnter < tExit || tExit < 0.0f): currentHit - } otherwise { + .otherwise: val hitDistance = when(tEnter > 0f)(tEnter).otherwise(tExit) - val hitNormal = when(tEnter =~= tMinX) { + val hitNormal = when(tEnter =~= tMinX): (when(rayDir.x > 0f)(-1f).otherwise(1f), 0f, 0f) - }.elseWhen(tEnter =~= tMinY) { + .elseWhen(tEnter =~= tMinY): (0f, when(rayDir.y > 0f)(-1f).otherwise(1f), 0f) - }.otherwise { + .otherwise: (0f, 0f, when(rayDir.z > 0f)(-1f).otherwise(1f)) - } RayHitInfo(hitDistance, hitNormal, box.material) - } diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Plane.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Plane.scala index b0188750..fd9e3eee 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Plane.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Plane.scala @@ -16,14 +16,13 @@ object Plane: def testRay(plane: Plane, rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo): RayHitInfo = pure: val denom = plane.normal dot rayDir given epsilon: Float32 = 0.1f - when(denom =~= 0.0f) { + when(denom =~= 0.0f): currentHit - } otherwise { + .otherwise: val t = ((plane.point - rayPos) dot plane.normal) / denom - when(t < 0.0f || t >= currentHit.dist) { + when(t < 0.0f || t >= currentHit.dist): currentHit - } otherwise { - val hitNormal = when(denom < 0.0f)(plane.normal).otherwise(-plane.normal) + .otherwise: + val hitNormal = when(denom < 0.0f)(plane.normal) + .otherwise(-plane.normal) RayHitInfo(t, hitNormal, plane.material) - } - } diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Quad.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Quad.scala index fbdcc1b7..58b2d641 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Quad.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Quad.scala @@ -21,9 +21,10 @@ object Quad: given TestRay[Quad] with def testRay(quad: Quad, rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo): RayHitInfo = pure: val normal = normalize((quad.c - quad.a) cross (quad.c - quad.b)) - val fixedQuad = when((normal dot rayDir) > 0f) { + val fixedQuad = when((normal dot rayDir) > 0f): Quad(quad.d, quad.c, quad.b, quad.a, quad.material) - } otherwise quad + .otherwise: + quad val fixedNormal = when((normal dot rayDir) > 0f)(-normal).otherwise(normal) val p = rayPos val q = rayPos + rayDir @@ -35,33 +36,34 @@ object Quad: val v = pa dot m def checkHit(intersectPoint: Vec3[Float32]): RayHitInfo = - val dist = when(abs(rayDir.x) > 0.1f) { + val dist = when(abs(rayDir.x) > 0.1f): (intersectPoint.x - rayPos.x) / rayDir.x - }.elseWhen(abs(rayDir.y) > 0.1f) { + .elseWhen(abs(rayDir.y) > 0.1f): (intersectPoint.y - rayPos.y) / rayDir.y - }.otherwise { + .otherwise: (intersectPoint.z - rayPos.z) / rayDir.z - } - when(dist > MinRayHitTime && dist < currentHit.dist) { + when(dist > MinRayHitTime && dist < currentHit.dist): RayHitInfo(dist, fixedNormal, quad.material) - } otherwise currentHit + .otherwise: + currentHit - when(v >= 0f) { + when(v >= 0f): val u = -(pb dot m) val w = scalarTriple(pq, pb, pa) - when(u >= 0f && w >= 0f) { + when(u >= 0f && w >= 0f): val denom = 1f / (u + v + w) val uu = u * denom val vv = v * denom val ww = w * denom val intersectPos = fixedQuad.a * uu + fixedQuad.b * vv + fixedQuad.c * ww checkHit(intersectPos) - } otherwise currentHit - } otherwise { + .otherwise: + currentHit + .otherwise: val pd = fixedQuad.d - p val u = pd dot m val w = scalarTriple(pq, pa, pd) - when(u >= 0f && w >= 0f) { + when(u >= 0f && w >= 0f): val negV = -v val denom = 1f / (u + negV + w) val uu = u * denom @@ -69,5 +71,5 @@ object Quad: val ww = w * denom val intersectPos = fixedQuad.a * uu + fixedQuad.d * vv + fixedQuad.c * ww checkHit(intersectPos) - } otherwise currentHit - } + .otherwise: + currentHit diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Shape.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Shape.scala index 9fb3f891..24af9919 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Shape.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Shape.scala @@ -1,9 +1,8 @@ package io.computenode.cyfra.foton.rt.shapes -import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo -import io.computenode.cyfra.dsl.library.Functions.* import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.dsl.given +import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo trait Shape diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala index e80ca655..efe2c76a 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala @@ -1,15 +1,15 @@ package io.computenode.cyfra.foton.rt.shapes -import io.computenode.cyfra.foton.rt.shapes.* -import io.computenode.cyfra.foton.rt.Material -import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo -import izumi.reflect.Tag -import io.computenode.cyfra.dsl.library.Functions.* -import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.given +import io.computenode.cyfra.dsl.library.Functions.* import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.foton.rt.Material +import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo +import io.computenode.cyfra.foton.rt.shapes.* import io.computenode.cyfra.foton.rt.shapes.Shape.TestRay +import izumi.reflect.Tag import scala.util.chaining.* diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Sphere.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Sphere.scala index 0328780b..0e0d556c 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Sphere.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/Sphere.scala @@ -1,17 +1,11 @@ package io.computenode.cyfra.foton.rt.shapes -import io.computenode.cyfra.foton.rt.Material -import io.computenode.cyfra.foton.rt.RtRenderer.{MinRayHitTime, RayHitInfo} - -import java.nio.file.Paths -import scala.collection.mutable -import scala.concurrent.ExecutionContext.Implicits -import scala.concurrent.duration.DurationInt -import scala.concurrent.{Await, ExecutionContext} import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.control.Pure.pure -import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.foton.rt.Material +import io.computenode.cyfra.foton.rt.RtRenderer.{MinRayHitTime, RayHitInfo} import io.computenode.cyfra.foton.rt.shapes.Shape.TestRay case class Sphere(center: Vec3[Float32], radius: Float32, material: Material) extends GStruct[Sphere] with Shape @@ -23,17 +17,18 @@ object Sphere: val b = toRay dot rayDir val c = (toRay dot toRay) - (sphere.radius * sphere.radius) val notHit = currentHit - when(c > 0f && b > 0f) { + when(c > 0f && b > 0f): notHit - } otherwise { + .otherwise: val discr = b * b - c - when(discr > 0f) { + when(discr > 0f): val initDist = -b - sqrt(discr) val fromInside = initDist < 0f val dist = when(fromInside)(-b + sqrt(discr)).otherwise(initDist) - when(dist > MinRayHitTime && dist < currentHit.dist) { - val normal = normalize((rayPos + rayDir * dist - sphere.center) * (when(fromInside)(-1f).otherwise(1f))) + when(dist > MinRayHitTime && dist < currentHit.dist): + val normal = normalize((rayPos + rayDir * dist - sphere.center) * when(fromInside)(-1f).otherwise(1f)) RayHitInfo(dist, normal, sphere.material, fromInside) - } otherwise notHit - } otherwise notHit - } + .otherwise: + notHit + .otherwise: + notHit diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala index 164458bf..b72be392 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala @@ -5,6 +5,5 @@ import io.computenode.cyfra.runtime.mem.{GMem, RamGMem} import scala.concurrent.Future -trait Executable[H <: Value, R <: Value] { +trait Executable[H <: Value, R <: Value]: def execute(input: GMem[H], output: RamGMem[R, ?]): Future[Unit] -} diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala index 90f0f91c..3ebd43d9 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala @@ -29,7 +29,7 @@ class GContext(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()): def compile[G <: GStruct[G]: Tag: GStructSchema, H <: Value: Tag: FromExpr, R <: Value: Tag: FromExpr]( function: GFunction[G, H, R], - ): ComputePipeline = { + ): ComputePipeline = val uniformStructSchema = summon[GStructSchema[G]] val uniformStruct = uniformStructSchema.fromTree(UniformStructRef) val tree = function.fn @@ -44,7 +44,6 @@ class GContext(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()): val shader = Shader(optimizedShaderCode, org.joml.Vector3i(256, 1, 1), layoutInfo, "main", vkContext.device) ComputePipeline(shader, vkContext) - } def execute[G <: GStruct[G]: Tag: GStructSchema, H <: Value, R <: Value](mem: GMem[H], fn: GFunction[G, H, R])(using uniformContext: UniformContext[G], diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala index 02a9e094..1c85b3fd 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala @@ -9,11 +9,10 @@ import izumi.reflect.Tag case class GFunction[G <: GStruct[G]: GStructSchema: Tag, H <: Value: Tag: FromExpr, R <: Value: Tag: FromExpr](fn: (G, Int32, GArray[H]) => R)( implicit context: GContext, -) { +): def arrayInputs: List[Tag[?]] = List(summon[Tag[H]]) def arrayOutputs: List[Tag[?]] = List(summon[Tag[R]]) val pipeline: ComputePipeline = context.compile(this) -} object GFunction: def apply[H <: Value: Tag: FromExpr, R <: Value: Tag: FromExpr](fn: H => R)(using context: GContext): GFunction[GStruct.Empty, H, R] = diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/FloatMem.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/FloatMem.scala index a0c6078f..4264233d 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/FloatMem.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/FloatMem.scala @@ -4,7 +4,6 @@ import io.computenode.cyfra.dsl.Value.Float32 import org.lwjgl.BufferUtils import java.nio.ByteBuffer -import org.lwjgl.system.MemoryUtil class FloatMem(val size: Int, protected val data: ByteBuffer) extends RamGMem[Float32, Float]: def toArray: Array[Float] = @@ -13,7 +12,7 @@ class FloatMem(val size: Int, protected val data: ByteBuffer) extends RamGMem[Fl res.get(result) result -object FloatMem { +object FloatMem: val FloatSize = 4 def apply(floats: Array[Float]): FloatMem = @@ -26,4 +25,3 @@ object FloatMem { def apply(size: Int): FloatMem = val data = BufferUtils.createByteBuffer(size * FloatSize) new FloatMem(size, data) -} diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala index 42246671..a6efd211 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala @@ -1,14 +1,12 @@ package io.computenode.cyfra.runtime.mem -import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.Value.FromExpr -import io.computenode.cyfra.spirv.SpirvTypes.typeStride -import io.computenode.cyfra.runtime.{GContext, GFunction} import io.computenode.cyfra.dsl.struct.* +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.runtime.{GContext, GFunction, UniformContext} +import io.computenode.cyfra.spirv.SpirvTypes.typeStride import izumi.reflect.Tag import org.lwjgl.BufferUtils -import org.lwjgl.system.MemoryUtil -import io.computenode.cyfra.runtime.UniformContext import java.nio.ByteBuffer @@ -31,9 +29,9 @@ object GMem: typeStride(t) }.sum - def serializeUniform(g: GStruct[?]): ByteBuffer = { + def serializeUniform(g: GStruct[?]): ByteBuffer = val data = BufferUtils.createByteBuffer(totalStride(g.schema)) - g.productIterator.foreach { + g.productIterator.foreach: case Int32(ConstInt32(i)) => data.putInt(i) case Float32(ConstFloat32(f)) => data.putFloat(f) case Vec4(ComposeVec4(Float32(ConstFloat32(x)), Float32(ConstFloat32(y)), Float32(ConstFloat32(z)), Float32(ConstFloat32(a)))) => @@ -50,7 +48,5 @@ object GMem: data.putFloat(y) case illegal => throw new IllegalArgumentException(s"Uniform must be constructed from constants (got field $illegal)") - } data.rewind() data - } diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/IntMem.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/IntMem.scala index 2c246aab..72d12a82 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/IntMem.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/IntMem.scala @@ -4,7 +4,6 @@ import io.computenode.cyfra.dsl.Value.Int32 import org.lwjgl.BufferUtils import java.nio.ByteBuffer -import org.lwjgl.system.MemoryUtil class IntMem(val size: Int, protected val data: ByteBuffer) extends RamGMem[Int32, Int]: def toArray: Array[Int] = diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala index 710781ea..ff48aa6b 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala @@ -3,22 +3,20 @@ package io.computenode.cyfra.runtime.mem import io.computenode.cyfra.dsl.Value.{Float32, Vec4} import io.computenode.cyfra.runtime.mem.GMem.fRGBA import org.lwjgl.BufferUtils -import org.lwjgl.system.MemoryUtil import java.nio.ByteBuffer class Vec4FloatMem(val size: Int, protected val data: ByteBuffer) extends RamGMem[Vec4[Float32], fRGBA]: - def toArray: Array[fRGBA] = { + def toArray: Array[fRGBA] = val res = data.asFloatBuffer() val result = new Array[fRGBA](size) for i <- 0 until size do result(i) = (res.get(), res.get(), res.get(), res.get()) result - } object Vec4FloatMem: val Vec4FloatSize = 16 - def apply(vecs: Array[fRGBA]): Vec4FloatMem = { + def apply(vecs: Array[fRGBA]): Vec4FloatMem = val size = vecs.length val data = BufferUtils.createByteBuffer(size * Vec4FloatSize) vecs.foreach { case (x, y, z, a) => @@ -29,7 +27,6 @@ object Vec4FloatMem: } data.rewind() new Vec4FloatMem(size, data) - } def apply(size: Int): Vec4FloatMem = val data = BufferUtils.createByteBuffer(size * Vec4FloatSize) diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala index e845adde..f0c7c38f 100644 --- a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala @@ -4,8 +4,6 @@ import io.computenode.cyfra.spirvtools.SpirvTool.{Ignore, Param, ToFile, ToLogge import io.computenode.cyfra.utility.Logger.logger import java.nio.ByteBuffer -import java.nio.charset.StandardCharsets -import java.nio.file.Files object SpirvDisassembler extends SpirvTool("spirv-dis"): diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvCrossTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvCrossTest.scala index 6a21f550..5ce14f10 100644 --- a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvCrossTest.scala +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvCrossTest.scala @@ -3,17 +3,14 @@ package io.computenode.cyfra.spirvtools import io.computenode.cyfra.spirvtools.SpirvCross.Enable import munit.FunSuite -class SpirvCrossTest extends FunSuite { +class SpirvCrossTest extends FunSuite: - test("SPIR-V cross compilation succeeded") { + test("SPIR-V cross compilation succeeded"): val shaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") - val glslShader = SpirvCross.crossCompileSpirv(shaderCode, crossCompilation = Enable(throwOnFail = true)) match { + val glslShader = SpirvCross.crossCompileSpirv(shaderCode, crossCompilation = Enable(throwOnFail = true)) match case None => fail("Failed to disassemble shader.") case Some(assembly) => assembly - } val referenceGlsl = SpirvTestUtils.loadResourceAsString("optimized.glsl") assertEquals(glslShader, referenceGlsl) - } -} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvDisassemblerTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvDisassemblerTest.scala index 0138b0cd..1918285b 100644 --- a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvDisassemblerTest.scala +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvDisassemblerTest.scala @@ -3,17 +3,14 @@ package io.computenode.cyfra.spirvtools import io.computenode.cyfra.spirvtools.SpirvDisassembler.Enable import munit.FunSuite -class SpirvDisassemblerTest extends FunSuite { +class SpirvDisassemblerTest extends FunSuite: - test("SPIR-V disassembly succeeded") { + test("SPIR-V disassembly succeeded"): val shaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") - val assembly = SpirvDisassembler.disassembleSpirv(shaderCode, disassembly = Enable(throwOnFail = true)) match { + val assembly = SpirvDisassembler.disassembleSpirv(shaderCode, disassembly = Enable(throwOnFail = true)) match case None => fail("Failed to disassemble shader.") case Some(assembly) => assembly - } val referenceAssembly = SpirvTestUtils.loadResourceAsString("optimized.spvasm") assertEquals(assembly, referenceAssembly) - } -} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvOptimizerTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvOptimizerTest.scala index 5557cfe0..a10925f8 100644 --- a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvOptimizerTest.scala +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvOptimizerTest.scala @@ -6,19 +6,16 @@ import munit.FunSuite import java.nio.ByteBuffer -class SpirvOptimizerTest extends FunSuite { +class SpirvOptimizerTest extends FunSuite: - test("SPIR-V optimization succeeded") { + test("SPIR-V optimization succeeded"): val shaderCode = SpirvTestUtils.loadShaderFromResources("original.spv") - val optimizedShaderCode = SpirvOptimizer.optimizeSpirv(shaderCode, SpirvOptimizer.Enable(throwOnFail = true, settings = Seq(Param("-O")))) match { + val optimizedShaderCode = SpirvOptimizer.optimizeSpirv(shaderCode, SpirvOptimizer.Enable(throwOnFail = true, settings = Seq(Param("-O")))) match case None => fail("Failed to optimize shader code.") case Some(optimizedShaderCode) => optimizedShaderCode - } val optimizedAssembly = SpirvDisassembler.disassembleSpirv(optimizedShaderCode, disassembly = Enable(throwOnFail = true)) val referenceOptimizedShaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") val referenceAssembly = SpirvDisassembler.disassembleSpirv(referenceOptimizedShaderCode, disassembly = Enable(throwOnFail = true)) assertEquals(optimizedAssembly, referenceAssembly) - } -} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvTestUtils.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvTestUtils.scala index ccb74760..201b6f73 100644 --- a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvTestUtils.scala +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvTestUtils.scala @@ -4,21 +4,19 @@ import java.nio.ByteBuffer import java.nio.file.{Files, Paths} import scala.io.Source -object SpirvTestUtils { - def loadShaderFromResources(path: String): ByteBuffer = { +object SpirvTestUtils: + def loadShaderFromResources(path: String): ByteBuffer = val resourceUrl = getClass.getClassLoader.getResource(path) require(resourceUrl != null, s"Resource not found: $path") val bytes = Files.readAllBytes(Paths.get(resourceUrl.toURI)) ByteBuffer.wrap(bytes) - } - def loadResourceAsString(path: String): String = { + def loadResourceAsString(path: String): String = val source = Source.fromResource(path) try source.mkString finally source.close() - } - def corruptMagicNumber(original: ByteBuffer): ByteBuffer = { + def corruptMagicNumber(original: ByteBuffer): ByteBuffer = val corrupted = ByteBuffer.allocate(original.capacity()) original.rewind() corrupted.put(original) @@ -27,5 +25,3 @@ object SpirvTestUtils { corrupted.rewind() corrupted - } -} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvToolTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvToolTest.scala index b819aec0..2fd2b8c5 100644 --- a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvToolTest.scala +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvToolTest.scala @@ -6,17 +6,16 @@ import java.io.{ByteArrayOutputStream, File} import java.nio.ByteBuffer import java.nio.file.Files -class SpirvToolTest extends FunSuite { +class SpirvToolTest extends FunSuite: private def isWindows: Boolean = System.getProperty("os.name").toLowerCase.contains("win") - class TestSpirvTool(toolName: String) extends SpirvTool(toolName) { + class TestSpirvTool(toolName: String) extends SpirvTool(toolName): def runExecuteCmd(input: ByteBuffer, cmd: Seq[String]): Either[SpirvToolError, (ByteArrayOutputStream, ByteArrayOutputStream, Int)] = executeSpirvCmd(input, cmd) - } if !isWindows then - test("executeSpirvCmd returns exit code and output streams on valid command") { + test("executeSpirvCmd returns exit code and output streams on valid command"): val tool = new TestSpirvTool("cat") val inputBytes = "hello SPIR-V".getBytes("UTF-8") @@ -33,9 +32,8 @@ class SpirvToolTest extends FunSuite { assertEquals(exitCode, 0) assert(outputString == "hello SPIR-V") assertEquals(errStream.size(), 0) - } - test("executeSpirvCmd returns non-zero exit code on invalid command") { + test("executeSpirvCmd returns non-zero exit code on invalid command"): val tool = new TestSpirvTool("invalid-cmd") val byteBuffer = ByteBuffer.wrap("".getBytes("UTF-8")) @@ -45,9 +43,8 @@ class SpirvToolTest extends FunSuite { assert(result.isLeft) val error = result.left.getOrElse(fail("Should have error")) assert(error.getMessage.contains("Failed to execute SPIR-V command")) - } - test("dumpSpvToFile writes ByteBuffer content to file") { + test("dumpSpvToFile writes ByteBuffer content to file"): val tmpFile = Files.createTempFile("spirv-dump-test", ".spv") val data = "SPIRV binary data".getBytes("UTF-8") @@ -62,10 +59,7 @@ class SpirvToolTest extends FunSuite { assert(buffer.position() == 0) Files.deleteIfExists(tmpFile) - } - test("Param.asStringParam returns correct string") { + test("Param.asStringParam returns correct string"): val param = SpirvTool.Param("test-value") assertEquals(param.asStringParam, "test-value") - } -} diff --git a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvValidatorTest.scala b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvValidatorTest.scala index df49b5c3..a857e5fb 100644 --- a/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvValidatorTest.scala +++ b/cyfra-spirv-tools/src/test/scala/io/computenode/cyfra/spirvtools/SpirvValidatorTest.scala @@ -3,31 +3,26 @@ package io.computenode.cyfra.spirvtools import io.computenode.cyfra.spirvtools.SpirvValidator.Enable import munit.FunSuite -class SpirvValidatorTest extends FunSuite { +class SpirvValidatorTest extends FunSuite: - test("SPIR-V validation succeeded") { + test("SPIR-V validation succeeded"): val shaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") - try { + try SpirvValidator.validateSpirv(shaderCode, validation = Enable(throwOnFail = true)) assert(true) - } catch { + catch case e: Throwable => fail(s"Validation unexpectedly failed: ${e.getMessage}") - } - } - test("SPIR-V validation fail") { + test("SPIR-V validation fail"): val shaderCode = SpirvTestUtils.loadShaderFromResources("optimized.spv") val corruptedShaderCode = SpirvTestUtils.corruptMagicNumber(shaderCode) - try { + try SpirvValidator.validateSpirv(corruptedShaderCode, validation = Enable(throwOnFail = true)) fail(s"Validation was supposed to fail.") - } catch { + catch case e: Throwable => val result = e.getMessage assertEquals(result, "SPIR-V validation failed with exit code 1.\nValidation errors:\nerror: line 0: Invalid SPIR-V magic number.\n") - } - } -} diff --git a/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/ImageUtility.scala b/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/ImageUtility.scala index 81478b63..77b8532a 100644 --- a/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/ImageUtility.scala +++ b/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/ImageUtility.scala @@ -5,20 +5,16 @@ import java.io.File import java.nio.file.Path import javax.imageio.ImageIO -object ImageUtility { +object ImageUtility: def renderToImage(arr: Array[(Float, Float, Float, Float)], n: Int, location: Path): Unit = renderToImage(arr, n, n, location) - def renderToImage(arr: Array[(Float, Float, Float, Float)], w: Int, h: Int, location: Path): Unit = { + def renderToImage(arr: Array[(Float, Float, Float, Float)], w: Int, h: Int, location: Path): Unit = val image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB) for y <- 0 until h do - for x <- 0 until w do { + for x <- 0 until w do val (r, g, b, _) = arr(y * w + x) def clip(f: Float) = Math.min(1.0f, Math.max(0.0f, f)) val (iR, iG, iB) = ((clip(r) * 255).toInt, (clip(g) * 255).toInt, (clip(b) * 255).toInt) image.setRGB(x, y, (iR << 16) | (iG << 8) | iB) - } val outputFile = location.toFile ImageIO.write(image, "png", outputFile) - } - -} diff --git a/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/Utility.scala b/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/Utility.scala index 31a98b8b..a081d60a 100644 --- a/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/Utility.scala +++ b/cyfra-utility/src/main/scala/io/computenode/cyfra/utility/Utility.scala @@ -1,7 +1,6 @@ package io.computenode.cyfra.utility import io.computenode.cyfra.utility.Logger.logger -import org.slf4j.LoggerFactory object Utility: diff --git a/cyfra-vscode/src/main/scala/io/computenode/vscode'/VscodeConnection.scala b/cyfra-vscode/src/main/scala/io/computenode/cyfra/vscode/VscodeConnection.scala similarity index 95% rename from cyfra-vscode/src/main/scala/io/computenode/vscode'/VscodeConnection.scala rename to cyfra-vscode/src/main/scala/io/computenode/cyfra/vscode/VscodeConnection.scala index cf994b47..f85e2fd6 100644 --- a/cyfra-vscode/src/main/scala/io/computenode/vscode'/VscodeConnection.scala +++ b/cyfra-vscode/src/main/scala/io/computenode/cyfra/vscode/VscodeConnection.scala @@ -4,7 +4,7 @@ import io.computenode.cyfra.vscode.VscodeConnection.Message import java.net.http.{HttpClient, WebSocket} -class VscodeConnection(host: String, port: Int) { +class VscodeConnection(host: String, port: Int): val ws = HttpClient .newHttpClient() .newWebSocketBuilder() @@ -13,7 +13,6 @@ class VscodeConnection(host: String, port: Int) { def send(message: Message): Unit = ws.sendText(message.toJson, true) -} object VscodeConnection: trait Message: diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala index a12e1c7e..7b3231cd 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala @@ -9,13 +9,12 @@ import io.computenode.cyfra.vulkan.memory.{Allocator, DescriptorPool} /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] object VulkanContext { +private[cyfra] object VulkanContext: val ValidationLayer: String = "VK_LAYER_KHRONOS_validation" val SyncLayer: String = "VK_LAYER_KHRONOS_synchronization2" private val ValidationLayers: Boolean = System.getProperty("io.computenode.cyfra.vulkan.validation", "false").toBoolean -} -private[cyfra] class VulkanContext { +private[cyfra] class VulkanContext: val instance: Instance = new Instance(ValidationLayers) val debugCallback: Option[DebugCallback] = if ValidationLayers then Some(new DebugCallback(instance)) else None val device: Device = new Device(instance) @@ -27,7 +26,7 @@ private[cyfra] class VulkanContext { logger.debug("Vulkan context created") logger.debug("Running on device: " + device.physicalDeviceName) - def destroy(): Unit = { + def destroy(): Unit = commandPool.destroy() descriptorPool.destroy() allocator.destroy() @@ -35,5 +34,3 @@ private[cyfra] class VulkanContext { device.destroy() debugCallback.foreach(_.destroy()) instance.destroy() - } -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala index fd43daa2..e595b0ec 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala @@ -1,20 +1,16 @@ package io.computenode.cyfra.vulkan.command -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.core.Device -import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryStack.stackPush +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.vulkan.* import org.lwjgl.vulkan.VK10.* -import scala.util.Using - /** @author * MarconZet Created 13.04.2020 Copied from Wrap */ -private[cyfra] abstract class CommandPool(device: Device, queue: Queue) extends VulkanObjectHandle { - protected val handle: Long = pushStack { stack => +private[cyfra] abstract class CommandPool(device: Device, queue: Queue) extends VulkanObjectHandle: + protected val handle: Long = pushStack: stack => val createInfo = VkCommandPoolCreateInfo .calloc(stack) .sType$Default() @@ -25,12 +21,11 @@ private[cyfra] abstract class CommandPool(device: Device, queue: Queue) extends val pCommandPoll = stack.callocLong(1) check(vkCreateCommandPool(device.get, createInfo, null, pCommandPoll), "Failed to create command pool") pCommandPoll.get() - } private val commandPool = handle def beginSingleTimeCommands(): VkCommandBuffer = - pushStack { stack => + pushStack: stack => val commandBuffer = this.createCommandBuffer() val beginInfo = VkCommandBufferBeginInfo @@ -40,12 +35,11 @@ private[cyfra] abstract class CommandPool(device: Device, queue: Queue) extends check(vkBeginCommandBuffer(commandBuffer, beginInfo), "Failed to begin single time command buffer") commandBuffer - } def createCommandBuffer(): VkCommandBuffer = createCommandBuffers(1).head - def createCommandBuffers(n: Int): Seq[VkCommandBuffer] = pushStack { stack => + def createCommandBuffers(n: Int): Seq[VkCommandBuffer] = pushStack: stack => val allocateInfo = VkCommandBufferAllocateInfo .calloc(stack) .sType$Default() @@ -56,33 +50,27 @@ private[cyfra] abstract class CommandPool(device: Device, queue: Queue) extends val pointerBuffer = stack.callocPointer(n) check(vkAllocateCommandBuffers(device.get, allocateInfo, pointerBuffer), "Failed to allocate command buffers") 0 until n map (i => pointerBuffer.get(i)) map (new VkCommandBuffer(_, device.get)) - } def endSingleTimeCommands(commandBuffer: VkCommandBuffer): Fence = - pushStack { stack => + pushStack: stack => vkEndCommandBuffer(commandBuffer) - val pointerBuffer = stack.callocPointer(1).put(0, commandBuffer) val submitInfo = VkSubmitInfo .calloc(stack) .sType$Default() .pCommandBuffers(pointerBuffer) - val fence = new Fence(device, 0, () => freeCommandBuffer(commandBuffer)) queue.submit(submitInfo, fence) fence - } def freeCommandBuffer(commandBuffer: VkCommandBuffer*): Unit = - pushStack { stack => + pushStack: stack => val pointerBuffer = stack.callocPointer(commandBuffer.length) commandBuffer.foreach(pointerBuffer.put) pointerBuffer.flip() vkFreeCommandBuffers(device.get, commandPool, pointerBuffer) - } protected def close(): Unit = vkDestroyCommandPool(device.get, commandPool, null) protected def getFlags: Int -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala index 85c4ac96..31f16d8c 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala @@ -1,21 +1,16 @@ package io.computenode.cyfra.vulkan.command -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.core.Device +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryStack.stackPush import org.lwjgl.vulkan.VK10.* import org.lwjgl.vulkan.VkFenceCreateInfo -import java.nio.LongBuffer -import scala.util.Using - /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] class Fence(device: Device, flags: Int = 0, onDestroy: () => Unit = () => ()) extends VulkanObjectHandle { - protected val handle: Long = pushStack { stack => +private[cyfra] class Fence(device: Device, flags: Int = 0, onDestroy: () => Unit = () => ()) extends VulkanObjectHandle: + protected val handle: Long = pushStack(stack => val fenceInfo = VkFenceCreateInfo .calloc(stack) .sType$Default() @@ -24,33 +19,27 @@ private[cyfra] class Fence(device: Device, flags: Int = 0, onDestroy: () => Unit val pFence = stack.callocLong(1) check(vkCreateFence(device.get, fenceInfo, null, pFence), "Failed to create fence") - pFence.get() - } + pFence.get(), + ) - override def close(): Unit = { + override def close(): Unit = onDestroy.apply() vkDestroyFence(device.get, handle, null) - } - def isSignaled: Boolean = { + def isSignaled: Boolean = val result = vkGetFenceStatus(device.get, handle) if !(result == VK_SUCCESS || result == VK_NOT_READY) then throw new VulkanAssertionError("Failed to get fence status", result) result == VK_SUCCESS - } - def reset(): Fence = { + def reset(): Fence = vkResetFences(device.get, handle) this - } - def block(): Fence = { + def block(): Fence = block(Long.MaxValue) this - } - def block(timeout: Long): Boolean = { - val err = vkWaitForFences(device.get, handle, true, timeout); - if err != VK_SUCCESS && err != VK_TIMEOUT then throw new VulkanAssertionError("Failed to wait for fences", err); + def block(timeout: Long): Boolean = + val err = vkWaitForFences(device.get, handle, true, timeout) + if err != VK_SUCCESS && err != VK_TIMEOUT then throw new VulkanAssertionError("Failed to wait for fences", err) err == VK_SUCCESS; - } -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/OneTimeCommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/OneTimeCommandPool.scala index a6db2fe2..67621756 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/OneTimeCommandPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/OneTimeCommandPool.scala @@ -6,7 +6,5 @@ import org.lwjgl.vulkan.VK10.VK_COMMAND_POOL_CREATE_TRANSIENT_BIT /** @author * MarconZet Created 13.04.2020 Copied from Wrap */ -private[cyfra] class OneTimeCommandPool(device: Device, queue: Queue) extends CommandPool(device, queue) { +private[cyfra] class OneTimeCommandPool(device: Device, queue: Queue) extends CommandPool(device, queue): protected def getFlags: Int = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT - -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Queue.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Queue.scala index bbc5ce70..506ee37c 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Queue.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Queue.scala @@ -1,31 +1,23 @@ package io.computenode.cyfra.vulkan.command -import io.computenode.cyfra.vulkan.util.Util.pushStack import io.computenode.cyfra.vulkan.core.Device +import io.computenode.cyfra.vulkan.util.Util.pushStack import io.computenode.cyfra.vulkan.util.VulkanObject -import org.lwjgl.PointerBuffer -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryStack.stackPush import org.lwjgl.vulkan.VK10.{vkGetDeviceQueue, vkQueueSubmit} import org.lwjgl.vulkan.{VkQueue, VkSubmitInfo} -import scala.util.Using - /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] class Queue(val familyIndex: Int, queueIndex: Int, device: Device) extends VulkanObject { - private val queue: VkQueue = pushStack { stack => +private[cyfra] class Queue(val familyIndex: Int, queueIndex: Int, device: Device) extends VulkanObject: + private val queue: VkQueue = pushStack: stack => val pQueue = stack.callocPointer(1) vkGetDeviceQueue(device.get, familyIndex, queueIndex, pQueue) new VkQueue(pQueue.get(0), device.get) - } - def submit(submitInfo: VkSubmitInfo, fence: Fence): Int = this.synchronized { + def submit(submitInfo: VkSubmitInfo, fence: Fence): Int = this.synchronized: vkQueueSubmit(queue, submitInfo, fence.get) - } def get: VkQueue = queue protected def close(): Unit = () -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala index a1777d2a..e65b145a 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala @@ -1,29 +1,22 @@ package io.computenode.cyfra.vulkan.command -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.core.Device -import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryStack.stackPush +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.vulkan.VK10.* import org.lwjgl.vulkan.VkSemaphoreCreateInfo -import scala.util.Using - /** @author * MarconZet Created 30.10.2019 */ -private[cyfra] class Semaphore(device: Device) extends VulkanObjectHandle { - protected val handle: Long = pushStack { stack => +private[cyfra] class Semaphore(device: Device) extends VulkanObjectHandle: + protected val handle: Long = pushStack: stack => val semaphoreCreateInfo = VkSemaphoreCreateInfo .calloc(stack) .sType$Default() val pointer = stack.callocLong(1) check(vkCreateSemaphore(device.get, semaphoreCreateInfo, null, pointer), "Failed to create semaphore") pointer.get() - } def close(): Unit = vkDestroySemaphore(device.get, handle, null) - -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/StandardCommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/StandardCommandPool.scala index e2eb7bad..a7127f4a 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/StandardCommandPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/StandardCommandPool.scala @@ -5,6 +5,5 @@ import io.computenode.cyfra.vulkan.core.Device /** @author * MarconZet Created 13.04.2020 Copied from Wrap */ -private[cyfra] class StandardCommandPool(device: Device, queue: Queue) extends CommandPool(device, queue) { +private[cyfra] class StandardCommandPool(device: Device, queue: Queue) extends CommandPool(device, queue): protected def getFlags: Int = 0 -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala index ca2456de..d452b13f 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala @@ -1,24 +1,20 @@ package io.computenode.cyfra.vulkan.compute -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.VulkanContext import io.computenode.cyfra.vulkan.core.Device -import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryStack.stackPush +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.vulkan.* import org.lwjgl.vulkan.VK10.* -import scala.util.Using - /** @author * MarconZet Created 14.04.2020 */ -private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanContext) extends VulkanObjectHandle { +private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanContext) extends VulkanObjectHandle: private val device: Device = context.device val descriptorSetLayouts: Seq[(Long, LayoutSet)] = computeShader.layoutInfo.sets.map(x => (createDescriptorSetLayout(x), x)) - val pipelineLayout: Long = pushStack { stack => + val pipelineLayout: Long = pushStack: stack => val pipelineLayoutCreateInfo = VkPipelineLayoutCreateInfo .calloc(stack) .sType$Default() @@ -30,8 +26,8 @@ private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanC val pPipelineLayout = stack.callocLong(1) check(vkCreatePipelineLayout(device.get, pipelineLayoutCreateInfo, null, pPipelineLayout), "Failed to create pipeline layout") pPipelineLayout.get(0) - } - protected val handle: Long = pushStack { stack => + + protected val handle: Long = pushStack: stack => val pipelineShaderStageCreateInfo = VkPipelineShaderStageCreateInfo .calloc(stack) .sType$Default() @@ -55,17 +51,15 @@ private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanC val pPipeline = stack.callocLong(1) check(vkCreateComputePipelines(device.get, 0, computePipelineCreateInfo, null, pPipeline), "Failed to create compute pipeline") pPipeline.get(0) - } - protected def close(): Unit = { + protected def close(): Unit = vkDestroyPipeline(device.get, handle, null) vkDestroyPipelineLayout(device.get, pipelineLayout, null) descriptorSetLayouts.map(_._1).foreach(vkDestroyDescriptorSetLayout(device.get, _, null)) - } - private def createDescriptorSetLayout(set: LayoutSet): Long = pushStack { stack => + private def createDescriptorSetLayout(set: LayoutSet): Long = pushStack: stack => val descriptorSetLayoutBindings = VkDescriptorSetLayoutBinding.calloc(set.bindings.length, stack) - set.bindings.foreach { binding => + set.bindings.foreach: binding => descriptorSetLayoutBindings .get() .binding(binding.id) @@ -75,7 +69,7 @@ private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanC .descriptorCount(1) .stageFlags(VK_SHADER_STAGE_COMPUTE_BIT) .pImmutableSamplers(null) - } + descriptorSetLayoutBindings.flip() val descriptorSetLayoutCreateInfo = VkDescriptorSetLayoutCreateInfo @@ -88,5 +82,3 @@ private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanC val pDescriptorSetLayout = stack.callocLong(1) check(vkCreateDescriptorSetLayout(device.get, descriptorSetLayoutCreateInfo, null, pDescriptorSetLayout), "Failed to create descriptor set layout") pDescriptorSetLayout.get(0) - } -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/Shader.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/Shader.scala index ac3924b7..6032e37f 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/Shader.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/Shader.scala @@ -1,20 +1,16 @@ package io.computenode.cyfra.vulkan.compute -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.core.Device -import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.joml.Vector3ic -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryStack.stackPush import org.lwjgl.vulkan.VK10.* import org.lwjgl.vulkan.VkShaderModuleCreateInfo import java.io.{File, FileInputStream, IOException} +import java.nio.ByteBuffer import java.nio.channels.FileChannel -import java.nio.{ByteBuffer, LongBuffer} -import java.util.stream.Collectors -import java.util.{List, Objects} -import scala.util.Using +import java.util.Objects /** @author * MarconZet Created 25.04.2020 @@ -25,9 +21,9 @@ private[cyfra] class Shader( val layoutInfo: LayoutInfo, val functionName: String, device: Device, -) extends VulkanObjectHandle { +) extends VulkanObjectHandle: - protected val handle: Long = pushStack { stack => + protected val handle: Long = pushStack: stack => val shaderModuleCreateInfo = VkShaderModuleCreateInfo .calloc(stack) .sType$Default() @@ -38,25 +34,21 @@ private[cyfra] class Shader( val pShaderModule = stack.callocLong(1) check(vkCreateShaderModule(device.get, shaderModuleCreateInfo, null, pShaderModule), "Failed to create shader module") pShaderModule.get() - } protected def close(): Unit = vkDestroyShaderModule(device.get, handle, null) -} -object Shader { +object Shader: def loadShader(path: String): ByteBuffer = loadShader(path, getClass.getClassLoader) private def loadShader(path: String, classLoader: ClassLoader): ByteBuffer = - try { + try val file = new File(Objects.requireNonNull(classLoader.getResource(path)).getFile) val fis = new FileInputStream(file) val fc = fis.getChannel fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()) - } catch + catch case e: IOException => throw new RuntimeException(e) - -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala index c09a1e7a..4c2c37ca 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala @@ -1,29 +1,25 @@ package io.computenode.cyfra.vulkan.core -import DebugCallback.DEBUG_REPORT import io.computenode.cyfra.utility.Logger.logger -import io.computenode.cyfra.vulkan.util.Util.check +import io.computenode.cyfra.vulkan.core.DebugCallback.DEBUG_REPORT import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil.NULL import org.lwjgl.vulkan.EXTDebugReport.* import org.lwjgl.vulkan.VK10.VK_SUCCESS import org.lwjgl.vulkan.{VkDebugReportCallbackCreateInfoEXT, VkDebugReportCallbackEXT} -import org.slf4j.{Logger, LoggerFactory} import java.lang.Integer.highestOneBit -import java.nio.LongBuffer /** @author * MarconZet Created 13.04.2020 */ -object DebugCallback { +object DebugCallback: val DEBUG_REPORT = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT -} -private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandle { - override protected val handle: Long = { - val debugCallback = new VkDebugReportCallbackEXT() { +private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandle: + override protected val handle: Long = + val debugCallback = new VkDebugReportCallbackEXT(): def invoke( flags: Int, objectType: Int, @@ -33,9 +29,9 @@ private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandl pLayerPrefix: Long, pMessage: Long, pUserData: Long, - ): Int = { + ): Int = val decodedMessage = VkDebugReportCallbackEXT.getString(pMessage) - highestOneBit(flags) match { + highestOneBit(flags) match case VK_DEBUG_REPORT_DEBUG_BIT_EXT => logger.debug(decodedMessage) case VK_DEBUG_REPORT_ERROR_BIT_EXT => @@ -45,17 +41,13 @@ private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandl case VK_DEBUG_REPORT_INFORMATION_BIT_EXT => logger.info(decodedMessage) case x => logger.error(s"Unexpected value: x, message: $decodedMessage") - } 0 - } - } setupDebugging(DEBUG_REPORT, debugCallback) - } override protected def close(): Unit = vkDestroyDebugReportCallbackEXT(instance.get, handle, null) - private def setupDebugging(flags: Int, callback: VkDebugReportCallbackEXT): Long = { + private def setupDebugging(flags: Int, callback: VkDebugReportCallbackEXT): Long = val dbgCreateInfo = VkDebugReportCallbackCreateInfoEXT .create() .sType$Default() @@ -68,5 +60,3 @@ private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandl val callbackHandle = pCallback.get(0) if err != VK_SUCCESS then throw new VulkanAssertionError("Failed to create DebugCallback", err) callbackHandle - } -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala index fe3e519c..e23ea52e 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala @@ -17,33 +17,27 @@ import scala.jdk.CollectionConverters.given * MarconZet Created 13.04.2020 */ -object Device { +object Device: final val MacOsExtension = VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME final val SyncExtension = VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME -} -private[cyfra] class Device(instance: Instance) extends VulkanObject { - - val physicalDevice: VkPhysicalDevice = pushStack { stack => +private[cyfra] class Device(instance: Instance) extends VulkanObject: + val physicalDevice: VkPhysicalDevice = pushStack: stack => val pPhysicalDeviceCount = stack.callocInt(1) check(vkEnumeratePhysicalDevices(instance.get, pPhysicalDeviceCount, null), "Failed to get number of physical devices") val deviceCount = pPhysicalDeviceCount.get(0) if deviceCount == 0 then throw new AssertionError("Failed to find GPUs with Vulkan support") - val pPhysicalDevices = stack.callocPointer(deviceCount) check(vkEnumeratePhysicalDevices(instance.get, pPhysicalDeviceCount, pPhysicalDevices), "Failed to get physical devices") - new VkPhysicalDevice(pPhysicalDevices.get(), instance.get) - } - val physicalDeviceName: String = pushStack { stack => + val physicalDeviceName: String = pushStack: stack => val pProperties = VkPhysicalDeviceProperties.calloc(stack) vkGetPhysicalDeviceProperties(physicalDevice, pProperties) pProperties.deviceNameString() - } - val computeQueueFamily: Int = pushStack { stack => + val computeQueueFamily: Int = pushStack: stack => val pQueueFamilyCount = stack.callocInt(1) vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyCount, null) val queueFamilyCount = pQueueFamilyCount.get(0) @@ -64,87 +58,82 @@ private[cyfra] class Device(instance: Instance) extends VulkanObject { (VK_QUEUE_COMPUTE_BIT & maskedFlags) > 0 }) .getOrElse(throw new AssertionError("No suitable queue family found for computing")) - } - - private val device: VkDevice = - pushStack { stack => - val pPropertiesCount = stack.callocInt(1) - check( - vkEnumerateDeviceExtensionProperties(physicalDevice, null.asInstanceOf[ByteBuffer], pPropertiesCount, null), - "Failed to get number of properties extension", - ) - val propertiesCount = pPropertiesCount.get(0) - - val pProperties = VkExtensionProperties.calloc(propertiesCount, stack) - check( - vkEnumerateDeviceExtensionProperties(physicalDevice, null.asInstanceOf[ByteBuffer], pPropertiesCount, pProperties), - "Failed to get extension properties", - ) - - val deviceExtensions = pProperties.iterator().asScala.map(_.extensionNameString()) - val deviceExtensionsSet = deviceExtensions.toSet - - val vulkan12Features = VkPhysicalDeviceVulkan12Features - .calloc(stack) - .sType$Default() - - val vulkan13Features = VkPhysicalDeviceVulkan13Features - .calloc(stack) - .sType$Default() - - val physicalDeviceFeatures = VkPhysicalDeviceFeatures2 - .calloc(stack) - .sType$Default() - .pNext(vulkan12Features) - .pNext(vulkan13Features) - - vkGetPhysicalDeviceFeatures2(physicalDevice, physicalDeviceFeatures) - - val additionalExtension = pProperties.stream().anyMatch(x => x.extensionNameString().equals(MacOsExtension)) - - val pQueuePriorities = stack.callocFloat(1).put(1.0f) - pQueuePriorities.flip() - - val pQueueCreateInfo = VkDeviceQueueCreateInfo.calloc(1, stack) - pQueueCreateInfo - .get(0) - .sType$Default() - .pNext(0) - .flags(0) - .queueFamilyIndex(computeQueueFamily) - .pQueuePriorities(pQueuePriorities) - - val extensions = Seq(MacOsExtension, SyncExtension).filter(deviceExtensionsSet) - val ppExtensionNames = stack.callocPointer(extensions.length) - extensions.foreach(extension => ppExtensionNames.put(stack.ASCII(extension))) - ppExtensionNames.flip() - - val sync2 = VkPhysicalDeviceSynchronization2Features - .calloc(stack) - .sType$Default() - .synchronization2(true) - - val pCreateInfo = VkDeviceCreateInfo - .create() - .sType$Default() - .pNext(sync2) - .pQueueCreateInfos(pQueueCreateInfo) - .ppEnabledExtensionNames(ppExtensionNames) - - if instance.enabledLayers.contains(ValidationLayer) then { - val ppValidationLayers = stack.callocPointer(1).put(stack.ASCII(ValidationLayer)) - pCreateInfo.ppEnabledLayerNames(ppValidationLayers.flip()) - } - - assert(vulkan13Features.synchronization2() || extensions.contains(SyncExtension)) - val pDevice = stack.callocPointer(1) - check(vkCreateDevice(physicalDevice, pCreateInfo, null, pDevice), "Failed to create device") - new VkDevice(pDevice.get(0), physicalDevice, pCreateInfo) - } + private val device: VkDevice = pushStack: stack => + val pPropertiesCount = stack.callocInt(1) + check( + vkEnumerateDeviceExtensionProperties(physicalDevice, null.asInstanceOf[ByteBuffer], pPropertiesCount, null), + "Failed to get number of properties extension", + ) + val propertiesCount = pPropertiesCount.get(0) + + val pProperties = VkExtensionProperties.calloc(propertiesCount, stack) + check( + vkEnumerateDeviceExtensionProperties(physicalDevice, null.asInstanceOf[ByteBuffer], pPropertiesCount, pProperties), + "Failed to get extension properties", + ) + + val deviceExtensions = pProperties.iterator().asScala.map(_.extensionNameString()) + val deviceExtensionsSet = deviceExtensions.toSet + + val vulkan12Features = VkPhysicalDeviceVulkan12Features + .calloc(stack) + .sType$Default() + + val vulkan13Features = VkPhysicalDeviceVulkan13Features + .calloc(stack) + .sType$Default() + + val physicalDeviceFeatures = VkPhysicalDeviceFeatures2 + .calloc(stack) + .sType$Default() + .pNext(vulkan12Features) + .pNext(vulkan13Features) + + vkGetPhysicalDeviceFeatures2(physicalDevice, physicalDeviceFeatures) + + val additionalExtension = pProperties.stream().anyMatch(x => x.extensionNameString().equals(MacOsExtension)) + + val pQueuePriorities = stack.callocFloat(1).put(1.0f) + pQueuePriorities.flip() + + val pQueueCreateInfo = VkDeviceQueueCreateInfo.calloc(1, stack) + pQueueCreateInfo + .get(0) + .sType$Default() + .pNext(0) + .flags(0) + .queueFamilyIndex(computeQueueFamily) + .pQueuePriorities(pQueuePriorities) + + val extensions = Seq(MacOsExtension, SyncExtension).filter(deviceExtensionsSet) + val ppExtensionNames = stack.callocPointer(extensions.length) + extensions.foreach(extension => ppExtensionNames.put(stack.ASCII(extension))) + ppExtensionNames.flip() + + val sync2 = VkPhysicalDeviceSynchronization2Features + .calloc(stack) + .sType$Default() + .synchronization2(true) + + val pCreateInfo = VkDeviceCreateInfo + .create() + .sType$Default() + .pNext(sync2) + .pQueueCreateInfos(pQueueCreateInfo) + .ppEnabledExtensionNames(ppExtensionNames) + + if instance.enabledLayers.contains(ValidationLayer) then + val ppValidationLayers = stack.callocPointer(1).put(stack.ASCII(ValidationLayer)) + pCreateInfo.ppEnabledLayerNames(ppValidationLayers.flip()) + + assert(vulkan13Features.synchronization2() || extensions.contains(SyncExtension)) + + val pDevice = stack.callocPointer(1) + check(vkCreateDevice(physicalDevice, pCreateInfo, null, pDevice), "Failed to create device") + new VkDevice(pDevice.get(0), physicalDevice, pCreateInfo) def get: VkDevice = device override protected def close(): Unit = vkDestroyDevice(device, null) -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala index 3d1e8da4..4f7479e3 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala @@ -1,7 +1,7 @@ package io.computenode.cyfra.vulkan.core import io.computenode.cyfra.utility.Logger.logger -import io.computenode.cyfra.vulkan.VulkanContext.{SyncLayer, ValidationLayer} +import io.computenode.cyfra.vulkan.VulkanContext.ValidationLayer import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObject import org.lwjgl.system.MemoryStack @@ -10,8 +10,6 @@ import org.lwjgl.vulkan.* import org.lwjgl.vulkan.EXTDebugReport.VK_EXT_DEBUG_REPORT_EXTENSION_NAME import org.lwjgl.vulkan.KHRPortabilityEnumeration.{VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME} import org.lwjgl.vulkan.VK10.* -import org.lwjgl.vulkan.VK13.* -import org.slf4j.LoggerFactory import java.nio.ByteBuffer import scala.collection.mutable @@ -21,11 +19,11 @@ import scala.util.chaining.* /** @author * MarconZet Created 13.04.2020 */ -object Instance { +object Instance: val ValidationLayersExtensions: Seq[String] = List(VK_EXT_DEBUG_REPORT_EXTENSION_NAME) val MoltenVkExtensions: Seq[String] = List(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) - lazy val (extensions, layers): (Seq[String], Seq[String]) = pushStack { stack => + lazy val (extensions, layers): (Seq[String], Seq[String]) = pushStack: stack => val ip = stack.ints(1) vkEnumerateInstanceLayerProperties(ip, null) val availableLayers = VkLayerProperties.malloc(ip.get(0), stack) @@ -38,16 +36,12 @@ object Instance { val extensions = instance_extensions.iterator().asScala.map(_.extensionNameString()) val layers = availableLayers.iterator().asScala.map(_.layerNameString()) (extensions.toSeq, layers.toSeq) - } lazy val version: Int = VK.getInstanceVersionSupported -} - -private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObject { - - private val instance: VkInstance = pushStack { stack => +private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObject: + private val instance: VkInstance = pushStack: stack => val appInfo = VkApplicationInfo .calloc(stack) .sType$Default() @@ -59,12 +53,11 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj .apiVersion(Instance.version) val ppEnabledExtensionNames = getInstanceExtensions(stack) - val ppEnabledLayerNames = { + val ppEnabledLayerNames = val layers = enabledLayers val pointer = stack.callocPointer(layers.length) layers.foreach(x => pointer.put(stack.ASCII(x))) pointer.flip() - } val pCreateInfo = VkInstanceCreateInfo .calloc(stack) @@ -77,7 +70,6 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj val pInstance = stack.mallocPointer(1) check(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance") new VkInstance(pInstance.get(0), pCreateInfo) - } lazy val enabledLayers: Seq[String] = List .empty[String] @@ -94,19 +86,18 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj override protected def close(): Unit = vkDestroyInstance(instance, null) - private def getInstanceExtensions(stack: MemoryStack) = { + private def getInstanceExtensions(stack: MemoryStack) = val n = stack.callocInt(1) check(vkEnumerateInstanceExtensionProperties(null.asInstanceOf[ByteBuffer], n, null)) val buffer = VkExtensionProperties.calloc(n.get(0), stack) check(vkEnumerateInstanceExtensionProperties(null.asInstanceOf[ByteBuffer], n, buffer)) - val availableExtensions = { + val availableExtensions = val buf = mutable.Buffer[String]() buffer.forEach { ext => buf.addOne(ext.extensionNameString()) } buf.toSet - } val extensions = mutable.Buffer.from(Instance.MoltenVkExtensions) if enableValidationLayers then extensions.addAll(Instance.ValidationLayersExtensions) @@ -120,5 +111,3 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj val ppEnabledExtensionNames = stack.callocPointer(extensions.size) filteredExtensions.foreach(x => ppEnabledExtensionNames.put(stack.ASCII(x))) ppEnabledExtensionNames.flip() - } -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala index a55e4a36..823f129e 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala @@ -12,7 +12,7 @@ import org.lwjgl.vulkan.VK10.* import java.nio.ByteBuffer -private[cyfra] abstract class AbstractExecutor(dataLength: Int, val bufferActions: Seq[BufferAction], context: VulkanContext) { +private[cyfra] abstract class AbstractExecutor(dataLength: Int, val bufferActions: Seq[BufferAction], context: VulkanContext): protected val device: Device = context.device protected val queue: Queue = context.computeQueue protected val allocator: Allocator = context.allocator @@ -20,24 +20,21 @@ private[cyfra] abstract class AbstractExecutor(dataLength: Int, val bufferAction protected val commandPool: CommandPool = context.commandPool protected val (descriptorSets, buffers) = setupBuffers() - private val commandBuffer: VkCommandBuffer = - pushStack { stack => - val commandBuffer = commandPool.createCommandBuffer() + private val commandBuffer: VkCommandBuffer = pushStack: stack => + val commandBuffer = commandPool.createCommandBuffer() + val commandBufferBeginInfo = VkCommandBufferBeginInfo + .calloc(stack) + .sType$Default() + .flags(0) - val commandBufferBeginInfo = VkCommandBufferBeginInfo - .calloc(stack) - .sType$Default() - .flags(0) - - check(vkBeginCommandBuffer(commandBuffer, commandBufferBeginInfo), "Failed to begin recording command buffer") + check(vkBeginCommandBuffer(commandBuffer, commandBufferBeginInfo), "Failed to begin recording command buffer") - recordCommandBuffer(commandBuffer) + recordCommandBuffer(commandBuffer) - check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") - commandBuffer - } + check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") + commandBuffer - def execute(input: Seq[ByteBuffer]): Seq[ByteBuffer] = { + def execute(input: Seq[ByteBuffer]): Seq[ByteBuffer] = val stagingBuffer = new Buffer( getBiggestTransportData * dataLength, @@ -46,13 +43,12 @@ private[cyfra] abstract class AbstractExecutor(dataLength: Int, val bufferAction VMA_MEMORY_USAGE_UNKNOWN, allocator, ) - for i <- bufferActions.indices if bufferActions(i) == BufferAction.LoadTo do { + for i <- bufferActions.indices if bufferActions(i) == BufferAction.LoadTo do val buffer = input(i) Buffer.copyBuffer(buffer, stagingBuffer, buffer.remaining()) Buffer.copyBuffer(stagingBuffer, buffers(i), buffer.remaining(), commandPool).block().destroy() - } - pushStack { stack => + pushStack: stack => val fence = new Fence(device) val pCommandBuffer = stack.callocPointer(1).put(0, commandBuffer) val submitInfo = VkSubmitInfo @@ -62,29 +58,24 @@ private[cyfra] abstract class AbstractExecutor(dataLength: Int, val bufferAction check(VK10.vkQueueSubmit(queue.get, submitInfo, fence.get), "Failed to submit command buffer to queue") fence.block().destroy() - } - val output = for (i <- bufferActions.indices if bufferActions(i) == BufferAction.LoadFrom) yield { + val output = for i <- bufferActions.indices if bufferActions(i) == BufferAction.LoadFrom yield val fence = Buffer.copyBuffer(buffers(i), stagingBuffer, buffers(i).size, commandPool) val outBuffer = BufferUtils.createByteBuffer(buffers(i).size) fence.block().destroy() Buffer.copyBuffer(stagingBuffer, outBuffer, outBuffer.remaining()) outBuffer - } stagingBuffer.destroy() output - } - def destroy(): Unit = { + def destroy(): Unit = commandPool.freeCommandBuffer(commandBuffer) descriptorSets.foreach(_.destroy()) buffers.foreach(_.destroy()) - } protected def setupBuffers(): (Seq[DescriptorSet], Seq[Buffer]) protected def recordCommandBuffer(commandBuffer: VkCommandBuffer): Unit protected def getBiggestTransportData: Int -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala index 0d88ff41..e287a04b 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala @@ -1,24 +1,20 @@ package io.computenode.cyfra.vulkan.executor -import io.computenode.cyfra.vulkan.compute.* import io.computenode.cyfra.vulkan.VulkanContext -import io.computenode.cyfra.vulkan.compute.{Binding, ComputePipeline, InputBufferSize, Shader, UniformSize} +import io.computenode.cyfra.vulkan.compute.* import io.computenode.cyfra.vulkan.memory.{Buffer, DescriptorSet} -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryStack.stackPush +import io.computenode.cyfra.vulkan.util.Util.pushStack import org.lwjgl.util.vma.Vma.* import org.lwjgl.vulkan.* import org.lwjgl.vulkan.VK10.* import scala.collection.mutable -import scala.util.Using /** @author * MarconZet Created 15.04.2020 */ private[cyfra] class MapExecutor(dataLength: Int, bufferActions: Seq[BufferAction], computePipeline: ComputePipeline, context: VulkanContext) - extends AbstractExecutor(dataLength, bufferActions, context) { + extends AbstractExecutor(dataLength, bufferActions, context): private lazy val shader: Shader = computePipeline.computeShader protected def getBiggestTransportData: Int = shader.layoutInfo.sets @@ -28,30 +24,27 @@ private[cyfra] class MapExecutor(dataLength: Int, bufferActions: Seq[BufferActio } .max - protected def setupBuffers(): (Seq[DescriptorSet], Seq[Buffer]) = pushStack { stack => + protected def setupBuffers(): (Seq[DescriptorSet], Seq[Buffer]) = pushStack: stack => val bindings = shader.layoutInfo.sets.flatMap(_.bindings) val buffers = bindings.zipWithIndex.map { case (binding, i) => - val bufferSize = binding.size match { + val bufferSize = binding.size match case InputBufferSize(n) => n * dataLength case UniformSize(n) => n - } new Buffer(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | bufferActions(i).action, 0, VMA_MEMORY_USAGE_GPU_ONLY, allocator) } val bufferDeque = mutable.ArrayDeque.from(buffers) val descriptorSetLayouts = computePipeline.descriptorSetLayouts - val descriptorSets = for (i <- descriptorSetLayouts.indices) yield { + val descriptorSets = for i <- descriptorSetLayouts.indices yield val descriptorSet = new DescriptorSet(device, descriptorSetLayouts(i)._1, descriptorSetLayouts(i)._2.bindings, descriptorPool) val size = descriptorSetLayouts(i)._2.bindings.size descriptorSet.update(bufferDeque.take(size).toSeq) bufferDeque.drop(size) descriptorSet - } (descriptorSets, buffers) - } protected def recordCommandBuffer(commandBuffer: VkCommandBuffer): Unit = - pushStack { stack => + pushStack: stack => vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get) val pDescriptorSets = stack.longs(descriptorSets.map(_.get)*) @@ -59,6 +52,3 @@ private[cyfra] class MapExecutor(dataLength: Int, bufferActions: Seq[BufferActio val workgroup = shader.workgroupDimensions vkCmdDispatch(commandBuffer, dataLength / workgroup.x(), 1 / workgroup.y(), 1 / workgroup.z()) - } - -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala index 86126ebd..1edacb32 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala @@ -1,17 +1,13 @@ package io.computenode.cyfra.vulkan.executor +import io.computenode.cyfra.utility.Utility.timed +import io.computenode.cyfra.vulkan.VulkanContext import io.computenode.cyfra.vulkan.command.* import io.computenode.cyfra.vulkan.compute.* import io.computenode.cyfra.vulkan.core.* -import SequenceExecutor.* -import io.computenode.cyfra.utility.Utility.timed +import io.computenode.cyfra.vulkan.executor.SequenceExecutor.* import io.computenode.cyfra.vulkan.memory.* -import io.computenode.cyfra.vulkan.VulkanContext -import io.computenode.cyfra.vulkan.command.{CommandPool, Fence, Queue} -import io.computenode.cyfra.vulkan.compute.{ComputePipeline, InputBufferSize, LayoutSet, UniformSize} import io.computenode.cyfra.vulkan.util.Util.* -import io.computenode.cyfra.vulkan.core.Device -import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer, DescriptorPool, DescriptorSet} import org.lwjgl.BufferUtils import org.lwjgl.util.vma.Vma.* import org.lwjgl.vulkan.* @@ -24,15 +20,16 @@ import java.nio.ByteBuffer /** @author * MarconZet Created 15.04.2020 */ -private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, context: VulkanContext) { +private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, context: VulkanContext): private val device: Device = context.device private val queue: Queue = context.computeQueue private val allocator: Allocator = context.allocator private val descriptorPool: DescriptorPool = context.descriptorPool private val commandPool: CommandPool = context.commandPool - private val pipelineToDescriptorSets: Map[ComputePipeline, Seq[DescriptorSet]] = pushStack { stack => - val pipelines = computeSequence.sequence.collect { case Compute(pipeline, _) => pipeline } + private val pipelineToDescriptorSets: Map[ComputePipeline, Seq[DescriptorSet]] = pushStack: stack => + val pipelines = computeSequence.sequence.collect: + case Compute(pipeline, _) => pipeline val rawSets = pipelines.map(_.computeShader.layoutInfo.sets) val numbered = rawSets.flatten.zipWithIndex @@ -71,11 +68,10 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont .toMap pipelines.zip(resolvedSets.map(_.map(descriptorSetMap(_)))).toMap - } private val descriptorSets = pipelineToDescriptorSets.toSeq.flatMap(_._2).distinctBy(_.get) - private def recordCommandBuffer(dataLength: Int): VkCommandBuffer = pushStack { stack => + private def recordCommandBuffer(dataLength: Int): VkCommandBuffer = pushStack: stack => val pipelinesHasDependencies = computeSequence.dependencies.map(_.to).toSet val commandBuffer = commandPool.createCommandBuffer() @@ -114,9 +110,8 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") commandBuffer - } - private def createBuffers(dataLength: Int): Map[DescriptorSet, Seq[Buffer]] = { + private def createBuffers(dataLength: Int): Map[DescriptorSet, Seq[Buffer]] = val setToActions = computeSequence.sequence .collect { case Compute(pipeline, bufferActions) => @@ -147,17 +142,19 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont .toMap setToBuffers - } - def execute(inputs: Seq[ByteBuffer], dataLength: Int): Seq[ByteBuffer] = pushStack { stack => + def execute(inputs: Seq[ByteBuffer], dataLength: Int): Seq[ByteBuffer] = pushStack: stack => timed("Vulkan full execute"): val setToBuffers = createBuffers(dataLength) def buffersWithAction(bufferAction: BufferAction): Seq[Buffer] = computeSequence.sequence.collect { case x: Compute => - pipelineToDescriptorSets(x.pipeline).map(setToBuffers).zip(x.pumpLayoutLocations).flatMap(x => x._1.zip(x._2)).collect { - case (buffer, action) if (action.action & bufferAction.action) != 0 => buffer - } + pipelineToDescriptorSets(x.pipeline) + .map(setToBuffers) + .zip(x.pumpLayoutLocations) + .flatMap(x => x._1.zip(x._2)) + .collect: + case (buffer, action) if (action.action & bufferAction.action) != 0 => buffer }.flatten val stagingBuffer = @@ -199,14 +196,11 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont setToBuffers.flatMap(_._2).foreach(_.destroy()) output - } def destroy(): Unit = descriptorSets.foreach(_.destroy()) -} - -object SequenceExecutor { +object SequenceExecutor: private[cyfra] case class ComputationSequence(sequence: Seq[ComputationStep], dependencies: Seq[Dependency]) private[cyfra] sealed trait ComputationStep @@ -218,5 +212,3 @@ object SequenceExecutor { case class LayoutLocation(set: Int, binding: Int) case class Dependency(from: ComputePipeline, fromSet: Int, to: ComputePipeline, toSet: Int) - -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Allocator.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Allocator.scala index 20b0b85e..147e1eda 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Allocator.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Allocator.scala @@ -3,16 +3,15 @@ package io.computenode.cyfra.vulkan.memory import io.computenode.cyfra.vulkan.core.{Device, Instance} import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObjectHandle -import org.lwjgl.system.MemoryStack import org.lwjgl.util.vma.Vma.{vmaCreateAllocator, vmaDestroyAllocator} import org.lwjgl.util.vma.{VmaAllocatorCreateInfo, VmaVulkanFunctions} /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] class Allocator(instance: Instance, device: Device) extends VulkanObjectHandle { +private[cyfra] class Allocator(instance: Instance, device: Device) extends VulkanObjectHandle: - protected val handle: Long = pushStack { stack => + protected val handle: Long = pushStack: stack => val functions = VmaVulkanFunctions.calloc(stack) functions.set(instance.get, device.get) val allocatorInfo = VmaAllocatorCreateInfo @@ -25,8 +24,6 @@ private[cyfra] class Allocator(instance: Instance, device: Device) extends Vulka val pAllocator = stack.callocPointer(1) check(vmaCreateAllocator(allocatorInfo, pAllocator), "Failed to create allocator") pAllocator.get(0) - } def close(): Unit = vmaDestroyAllocator(handle) -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala index 91c27ec1..53b364a7 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala @@ -1,26 +1,22 @@ package io.computenode.cyfra.vulkan.memory -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.command.{CommandPool, Fence} -import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} -import org.lwjgl.PointerBuffer -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryStack.stackPush +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.system.MemoryUtil.* import org.lwjgl.util.vma.Vma.* import org.lwjgl.util.vma.VmaAllocationCreateInfo import org.lwjgl.vulkan.VK10.* -import org.lwjgl.vulkan.{VkBufferCopy, VkBufferCreateInfo, VkCommandBuffer} +import org.lwjgl.vulkan.{VkBufferCopy, VkBufferCreateInfo} -import java.nio.{ByteBuffer, LongBuffer} -import scala.util.Using +import java.nio.ByteBuffer /** @author * MarconZet Created 11.05.2019 */ -private[cyfra] class Buffer(val size: Int, val usage: Int, flags: Int, memUsage: Int, val allocator: Allocator) extends VulkanObjectHandle { +private[cyfra] class Buffer(val size: Int, val usage: Int, flags: Int, memUsage: Int, val allocator: Allocator) extends VulkanObjectHandle: - val (handle, allocation) = pushStack { stack => + val (handle, allocation) = pushStack: stack => val bufferInfo = VkBufferCreateInfo .calloc(stack) .sType$Default() @@ -39,42 +35,37 @@ private[cyfra] class Buffer(val size: Int, val usage: Int, flags: Int, memUsage: val pAllocation = stack.callocPointer(1) check(vmaCreateBuffer(allocator.get, bufferInfo, allocInfo, pBuffer, pAllocation, null), "Failed to create buffer") (pBuffer.get(), pAllocation.get()) - } - def get(dst: Array[Byte]): Unit = { + def get(dst: Array[Byte]): Unit = val len = Math.min(dst.length, size) val byteBuffer = memCalloc(len) Buffer.copyBuffer(this, byteBuffer, len) byteBuffer.get(dst) memFree(byteBuffer) - } protected def close(): Unit = vmaDestroyBuffer(allocator.get, handle, allocation) -} -object Buffer { +object Buffer: def copyBuffer(src: ByteBuffer, dst: Buffer, bytes: Long): Unit = - pushStack { stack => + pushStack: stack => val pData = stack.callocPointer(1) check(vmaMapMemory(dst.allocator.get, dst.allocation, pData), "Failed to map destination buffer memory") val data = pData.get() memCopy(memAddress(src), data, bytes) vmaFlushAllocation(dst.allocator.get, dst.allocation, 0, bytes) vmaUnmapMemory(dst.allocator.get, dst.allocation) - } def copyBuffer(src: Buffer, dst: ByteBuffer, bytes: Long): Unit = - pushStack { stack => + pushStack: stack => val pData = stack.callocPointer(1) check(vmaMapMemory(src.allocator.get, src.allocation, pData), "Failed to map destination buffer memory") val data = pData.get() memCopy(data, memAddress(dst), bytes) vmaUnmapMemory(src.allocator.get, src.allocation) - } def copyBuffer(src: Buffer, dst: Buffer, bytes: Long, commandPool: CommandPool): Fence = - pushStack { stack => + pushStack: stack => val commandBuffer = commandPool.beginSingleTimeCommands() val copyRegion = VkBufferCopy @@ -85,6 +76,3 @@ object Buffer { vkCmdCopyBuffer(commandBuffer, src.get, dst.get, copyRegion) commandPool.endSingleTimeCommands(commandBuffer) - } - -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala index b8c83398..f6ceced3 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala @@ -1,25 +1,19 @@ package io.computenode.cyfra.vulkan.memory -import DescriptorPool.MAX_SETS -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.core.Device -import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} -import org.lwjgl.system.MemoryStack -import org.lwjgl.system.MemoryStack.stackPush +import io.computenode.cyfra.vulkan.memory.DescriptorPool.MAX_SETS +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.vulkan.VK10.* import org.lwjgl.vulkan.{VkDescriptorPoolCreateInfo, VkDescriptorPoolSize} -import java.nio.LongBuffer -import scala.util.Using - /** @author * MarconZet Created 14.04.2019 */ -object DescriptorPool { +object DescriptorPool: val MAX_SETS = 100 -} -private[cyfra] class DescriptorPool(device: Device) extends VulkanObjectHandle { - protected val handle: Long = pushStack { stack => +private[cyfra] class DescriptorPool(device: Device) extends VulkanObjectHandle: + protected val handle: Long = pushStack: stack => val descriptorPoolSize = VkDescriptorPoolSize.calloc(1, stack) descriptorPoolSize .get(0) @@ -36,8 +30,6 @@ private[cyfra] class DescriptorPool(device: Device) extends VulkanObjectHandle { val pDescriptorPool = stack.callocLong(1) check(vkCreateDescriptorPool(device.get, descriptorPoolCreateInfo, null, pDescriptorPool), "Failed to create descriptor pool") pDescriptorPool.get() - } override protected def close(): Unit = vkDestroyDescriptorPool(device.get, handle, null) -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala index ef91eed4..e9f49d4d 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala @@ -1,10 +1,9 @@ package io.computenode.cyfra.vulkan.memory -import io.computenode.cyfra.vulkan.compute.{Binding, LayoutSet} -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.compute.Binding import io.computenode.cyfra.vulkan.core.Device +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObjectHandle -import org.lwjgl.system.MemoryStack import org.lwjgl.vulkan.VK10.* import org.lwjgl.vulkan.{VkDescriptorBufferInfo, VkDescriptorSetAllocateInfo, VkWriteDescriptorSet} @@ -12,9 +11,9 @@ import org.lwjgl.vulkan.{VkDescriptorBufferInfo, VkDescriptorSetAllocateInfo, Vk * MarconZet Created 15.04.2020 */ private[cyfra] class DescriptorSet(device: Device, descriptorSetLayout: Long, val bindings: Seq[Binding], descriptorPool: DescriptorPool) - extends VulkanObjectHandle { + extends VulkanObjectHandle: - protected val handle: Long = pushStack { stack => + protected val handle: Long = pushStack: stack => val pSetLayout = stack.callocLong(1).put(0, descriptorSetLayout) val descriptorSetAllocateInfo = VkDescriptorSetAllocateInfo .calloc(stack) @@ -25,9 +24,8 @@ private[cyfra] class DescriptorSet(device: Device, descriptorSetLayout: Long, va val pDescriptorSet = stack.callocLong(1) check(vkAllocateDescriptorSets(device.get, descriptorSetAllocateInfo, pDescriptorSet), "Failed to allocate descriptor set") pDescriptorSet.get() - } - def update(buffers: Seq[Buffer]): Unit = pushStack { stack => + def update(buffers: Seq[Buffer]): Unit = pushStack: stack => val writeDescriptorSet = VkWriteDescriptorSet.calloc(buffers.length, stack) buffers.indices foreach { i => val descriptorBufferInfo = VkDescriptorBufferInfo @@ -48,8 +46,6 @@ private[cyfra] class DescriptorSet(device: Device, descriptorSetLayout: Long, va .pBufferInfo(descriptorBufferInfo) } vkUpdateDescriptorSets(device.get, writeDescriptorSet, null) - } override protected def close(): Unit = vkFreeDescriptorSets(device.get, descriptorPool.get, handle) -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/Util.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/Util.scala index 9065f490..fcdb71aa 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/Util.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/Util.scala @@ -5,7 +5,6 @@ import org.lwjgl.vulkan.VK10.VK_SUCCESS import scala.util.Using -object Util { +object Util: def pushStack[T](f: MemoryStack => T): T = Using(MemoryStack.stackPush())(f).get def check(err: Int, message: String = ""): Unit = if err != VK_SUCCESS then throw new VulkanAssertionError(message, err) -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanAssertionError.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanAssertionError.scala index 3326bf0d..df8a75a0 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanAssertionError.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanAssertionError.scala @@ -12,7 +12,7 @@ import org.lwjgl.vulkan.VK10.* private[cyfra] class VulkanAssertionError(msg: String, result: Int) extends AssertionError(s"$msg: ${VulkanAssertionError.translateVulkanResult(result)}") -object VulkanAssertionError { +object VulkanAssertionError: def translateVulkanResult(result: Int): String = result match // Success codes @@ -69,4 +69,3 @@ object VulkanAssertionError { "A validation layer found an error." case x => s"Unknown $x" -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala index efecc480..b896706b 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala @@ -3,15 +3,12 @@ package io.computenode.cyfra.vulkan.util /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] abstract class VulkanObject { +private[cyfra] abstract class VulkanObject: protected var alive: Boolean = true - def destroy(): Unit = { + def destroy(): Unit = if !alive then throw new IllegalStateException() close() alive = false - } protected def close(): Unit - -} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala index 9ea98538..acc448c7 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala @@ -3,10 +3,9 @@ package io.computenode.cyfra.vulkan.util /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] abstract class VulkanObjectHandle extends VulkanObject { +private[cyfra] abstract class VulkanObjectHandle extends VulkanObject: protected val handle: Long def get: Long = if !alive then throw new IllegalStateException() else handle -} From 83e3070953ab95852cecc7aa1a4df5381d64ece8 Mon Sep 17 00:00:00 2001 From: Simon R Date: Sun, 6 Jul 2025 15:05:20 +0200 Subject: [PATCH 08/59] New cyfra core (#53) * Init work on new cyfra * Scaffold ready * Some formatting * Added Execution Result * Construction works in progress * another version * More review fixes. * Rename package * Make ExecLayout invariant * allocation fixes * more fixes * changed program * ignore redunctant cast * fmt * fixed sth * LF! --------- Co-authored-by: MarconZet <25779550+MarconZet@users.noreply.github.com> --- build.sbt | 8 +- .../computenode/cyfra/core/Allocation.scala | 28 +++++ .../computenode/cyfra/core/CyfraRuntime.scala | 7 ++ .../cyfra/core/GBufferRegion.scala | 47 ++++++++ .../computenode/cyfra/core/GExecution.scala | 62 ++++++++++ .../io/computenode/cyfra/core/GProgram.scala | 70 +++++++++++ .../cyfra/core/archive}/Executable.scala | 4 +- .../cyfra/core/archive}/GContext.scala | 11 +- .../cyfra/core/archive}/GFunction.scala | 13 ++- .../cyfra/core/archive/UniformContext.scala | 13 +++ .../cyfra/core/archive}/mem/FloatMem.scala | 2 +- .../cyfra/core/archive}/mem/GMem.scala | 6 +- .../cyfra/core/archive}/mem/IntMem.scala | 2 +- .../cyfra/core/archive}/mem/RamGMem.scala | 2 +- .../core/archive}/mem/Vec4FloatMem.scala | 4 +- .../cyfra/core/binding/BufferRef.scala | 9 ++ .../cyfra/core/binding/UniformRef.scala | 10 ++ .../cyfra/core/layout/Layout.scala | 6 + .../cyfra/core/layout/LayoutStruct.scala | 80 +++++++++++++ .../io/computenode/cyfra/dsl/Expression.scala | 3 +- .../io/computenode/cyfra/dsl/Value.scala | 4 + .../cyfra/dsl/algebra/ScalarAlgebra.scala | 36 +++--- .../cyfra/dsl/algebra/VectorAlgebra.scala | 34 +++--- .../cyfra/dsl/binding/GBinding.scala | 7 ++ .../cyfra/dsl/binding/GBuffer.scala | 13 +++ .../cyfra/dsl/binding/GUniform.scala | 19 +++ .../cyfra/dsl/binding/ReadBuffer.scala | 7 ++ .../cyfra/dsl/binding/ReadUniform.scala | 6 + .../cyfra/dsl/binding/WriteBuffer.scala | 8 ++ .../cyfra/dsl/binding/WriteUniform.scala | 9 ++ .../cyfra/dsl/collections/GArray.scala | 2 +- .../cyfra/dsl/collections/GArray2D.scala | 2 +- .../cyfra/dsl/collections/GSeq.scala | 14 +-- .../computenode/cyfra/dsl/control/Pure.scala | 2 +- .../computenode/cyfra/dsl/control/When.scala | 10 +- .../io/computenode/cyfra/dsl/gio/GIO.scala | 45 ++++++++ .../cyfra/dsl/library/Functions.scala | 26 ++--- .../cyfra/dsl/struct/GStruct.scala | 2 +- .../cyfra/e2e/ArithmeticsE2eTest.scala | 2 +- .../cyfra/e2e/FunctionsE2eTest.scala | 2 +- .../cyfra/e2e/GStructE2eTest.scala | 2 +- .../computenode/cyfra/e2e/GseqE2eTest.scala | 2 +- .../computenode/cyfra/e2e/WhenE2eTest.scala | 2 +- .../cyfra/e2e/juliaset/JuliaSet.scala | 4 +- cyfra-examples/src/main/resources/gio.scala | 12 ++ .../cyfra/samples/TestingStuff.scala | 109 ++++++++++++++++++ .../samples}/foton/AnimatedJulia.scala | 2 +- .../samples}/foton/AnimatedRaytrace.scala | 2 +- .../samples}/oldsamples/Raytracing.scala | 6 +- .../samples}/slides/1sample.scala | 6 +- .../samples}/slides/2simpleray.scala | 6 +- .../samples}/slides/3rays.scala | 6 +- .../samples}/slides/4random.scala | 6 +- .../animation/AnimatedFunctionRenderer.scala | 6 +- .../foton/animation/AnimationRenderer.scala | 4 +- .../cyfra/foton/rt/ImageRtRenderer.scala | 6 +- .../cyfra/foton/rt/RtRenderer.scala | 2 +- .../rt/animation/AnimationRtRenderer.scala | 6 +- .../foton/rt/shapes/ShapeCollection.scala | 2 +- .../cyfra/runtime/ExecutionHandler.scala | 11 ++ .../cyfra/runtime/UniformContext.scala | 12 -- .../cyfra/runtime/VkAllocation.scala | 29 +++++ .../cyfra/runtime/VkCyfraRuntime.scala | 8 ++ 63 files changed, 754 insertions(+), 134 deletions(-) create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/CyfraRuntime.scala create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala rename {cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime => cyfra-core/src/main/scala/io/computenode/cyfra/core/archive}/Executable.scala (63%) rename {cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime => cyfra-core/src/main/scala/io/computenode/cyfra/core/archive}/GContext.scala (86%) rename {cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime => cyfra-core/src/main/scala/io/computenode/cyfra/core/archive}/GFunction.scala (64%) create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/UniformContext.scala rename {cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime => cyfra-core/src/main/scala/io/computenode/cyfra/core/archive}/mem/FloatMem.scala (94%) rename {cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime => cyfra-core/src/main/scala/io/computenode/cyfra/core/archive}/mem/GMem.scala (89%) rename {cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime => cyfra-core/src/main/scala/io/computenode/cyfra/core/archive}/mem/IntMem.scala (93%) rename {cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime => cyfra-core/src/main/scala/io/computenode/cyfra/core/archive}/mem/RamGMem.scala (81%) rename {cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime => cyfra-core/src/main/scala/io/computenode/cyfra/core/archive}/mem/Vec4FloatMem.scala (90%) create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/BufferRef.scala create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/UniformRef.scala create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/Layout.scala create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBuffer.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GUniform.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadBuffer.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadUniform.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteBuffer.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala create mode 100644 cyfra-examples/src/main/resources/gio.scala create mode 100644 cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala rename cyfra-examples/src/main/scala/io/computenode/{samples/cyfra => cyfra/samples}/foton/AnimatedJulia.scala (97%) rename cyfra-examples/src/main/scala/io/computenode/{samples/cyfra => cyfra/samples}/foton/AnimatedRaytrace.scala (98%) rename cyfra-examples/src/main/scala/io/computenode/{samples/cyfra => cyfra/samples}/oldsamples/Raytracing.scala (99%) rename cyfra-examples/src/main/scala/io/computenode/{samples/cyfra => cyfra/samples}/slides/1sample.scala (69%) rename cyfra-examples/src/main/scala/io/computenode/{samples/cyfra => cyfra/samples}/slides/2simpleray.scala (91%) rename cyfra-examples/src/main/scala/io/computenode/{samples/cyfra => cyfra/samples}/slides/3rays.scala (97%) rename cyfra-examples/src/main/scala/io/computenode/{samples/cyfra => cyfra/samples}/slides/4random.scala (98%) create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala delete mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/UniformContext.scala create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala diff --git a/build.sbt b/build.sbt index 8005cccd..a36c04dc 100644 --- a/build.sbt +++ b/build.sbt @@ -76,10 +76,14 @@ lazy val compiler = (project in file("cyfra-compiler")) .settings(commonSettings) .dependsOn(dsl, utility) -lazy val runtime = (project in file("cyfra-runtime")) +lazy val core = (project in file("cyfra-core")) .settings(commonSettings) .dependsOn(compiler, dsl, vulkan, utility, spirvTools) +lazy val runtime = (project in file("cyfra-runtime")) + .settings(commonSettings) + .dependsOn(core) + lazy val foton = (project in file("cyfra-foton")) .settings(commonSettings) .dependsOn(compiler, dsl, runtime, utility) @@ -98,7 +102,7 @@ lazy val e2eTest = (project in file("cyfra-e2e-test")) lazy val root = (project in file(".")) .settings(name := "Cyfra") - .aggregate(compiler, dsl, foton, runtime, vulkan, examples) + .aggregate(compiler, dsl, foton, core, runtime, vulkan, examples) e2eTest / Test / javaOptions ++= Seq("-Dorg.lwjgl.system.stackSize=1024", "-DuniqueLibraryNames=true") diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala new file mode 100644 index 00000000..194b3a2f --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala @@ -0,0 +1,28 @@ +package io.computenode.cyfra.core + +import io.computenode.cyfra.core.layout.{Layout, LayoutStruct} +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} +import io.computenode.cyfra.dsl.struct.GStruct +import izumi.reflect.Tag + +import java.nio.ByteBuffer + +trait Allocation: + extension (buffer: GBinding[?]) + def read(bb: ByteBuffer, offset: Int = 0, length: Int = -1): Unit + + def write(bb: ByteBuffer, offset: Int = 0, length: Int = -1): Unit + + extension [Params, L <: Layout, RL <: Layout: LayoutStruct](execution: GExecution[Params, L, RL]) def execute(params: Params, layout: L): RL + + extension (buffers: GBuffer.type) + def apply[T <: Value: {Tag, FromExpr}](size: Int): GBuffer[T] + + def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] + + extension (buffers: GUniform.type) + def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GUniform[T] + + def apply[T <: Value: {Tag, FromExpr}](): GUniform[T] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/CyfraRuntime.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/CyfraRuntime.scala new file mode 100644 index 00000000..a7c029e4 --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/CyfraRuntime.scala @@ -0,0 +1,7 @@ +package io.computenode.cyfra.core + +import io.computenode.cyfra.core.Allocation + +trait CyfraRuntime: + + def allocation(): Allocation diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala new file mode 100644 index 00000000..2aec9159 --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala @@ -0,0 +1,47 @@ +package io.computenode.cyfra.core + +import io.computenode.cyfra.core.Allocation +import io.computenode.cyfra.core.GProgram.BufferSizeSpec +import io.computenode.cyfra.core.layout.{Layout, LayoutStruct} +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.GBuffer +import izumi.reflect.Tag + +import java.nio.ByteBuffer + +sealed trait GBufferRegion[ReqAlloc <: Layout: LayoutStruct, ResAlloc <: Layout: LayoutStruct]: + val initAlloc: ReqAlloc + +object GBufferRegion: + + def allocate[Alloc <: Layout: LayoutStruct]: GBufferRegion[Alloc, Alloc] = + AllocRegion(summon[LayoutStruct[Alloc]].layoutRef) + + case class AllocRegion[Alloc <: Layout: LayoutStruct](l: Alloc) extends GBufferRegion[Alloc, Alloc]: + val initAlloc: Alloc = l + + case class MapRegion[ReqAlloc <: Layout: LayoutStruct, BodyAlloc <: Layout: LayoutStruct, ResAlloc <: Layout: LayoutStruct]( + reqRegion: GBufferRegion[ReqAlloc, BodyAlloc], + f: Allocation => BodyAlloc => ResAlloc, + ) extends GBufferRegion[ReqAlloc, ResAlloc]: + val initAlloc: ReqAlloc = reqRegion.initAlloc + + extension [ReqAlloc <: Layout: LayoutStruct, ResAlloc <: Layout: LayoutStruct](region: GBufferRegion[ReqAlloc, ResAlloc]) + def map[NewAlloc <: Layout: LayoutStruct](f: Allocation ?=> ResAlloc => NewAlloc): GBufferRegion[ReqAlloc, NewAlloc] = + MapRegion(region, (alloc: Allocation) => (resAlloc: ResAlloc) => f(using alloc)(resAlloc)) + + def runUnsafe(init: Allocation ?=> ReqAlloc, onDone: Allocation ?=> ResAlloc => Unit)(using cyfraRuntime: CyfraRuntime): Unit = + val allocation = cyfraRuntime.allocation() + init(using allocation) + + // noinspection ScalaRedundantCast + val steps: Seq[Allocation => Layout => Layout] = Seq.unfold(region: GBufferRegion[?, ?]): + case _: AllocRegion[?] => None + case MapRegion(req, f) => + Some((f.asInstanceOf[Allocation => Layout => Layout], req)) + + val bodyAlloc = steps.foldLeft[Layout](region.initAlloc): (acc, step) => + step(allocation)(acc) + + onDone(using allocation)(bodyAlloc.asInstanceOf[ResAlloc]) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala new file mode 100644 index 00000000..0caabec6 --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala @@ -0,0 +1,62 @@ +package io.computenode.cyfra.core + +import io.computenode.cyfra.core.GExecution.* +import io.computenode.cyfra.core.archive.GContext +import io.computenode.cyfra.core.layout.* +import io.computenode.cyfra.dsl.binding.GBuffer +import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} +import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.UniformStructRef +import izumi.reflect.Tag +import GExecution.* + +trait GExecution[-Params, ExecLayout <: Layout, +ResLayout <: Layout]: + + def flatMap[NRL <: Layout, NP <: Params](f: ResLayout => GExecution[NP, ExecLayout, NRL]): GExecution[NP, ExecLayout, NRL] = + FlatMap(this, (p, r) => f(r)) + + def map[NRL <: Layout](f: ResLayout => NRL): GExecution[Params, ExecLayout, NRL] = + Map(this, f, identity, identity) + + def contramap[NL <: Layout](f: NL => ExecLayout): GExecution[Params, NL, ResLayout] = + Map(this, identity, f, identity) + + def contramapParams[NP](f: NP => Params): GExecution[NP, ExecLayout, ResLayout] = + Map(this, identity, identity, f) + + def addProgram[ProgramParams, PP <: Params, ProgramLayout <: Layout, P <: GProgram[ProgramParams, ProgramLayout]]( + program: P, + )(mapParams: PP => ProgramParams, mapLayout: ExecLayout => ProgramLayout): GExecution[PP, ExecLayout, ResLayout] = + val adapted = program.contramapParams(mapParams).contramap(mapLayout) + flatMap(r => adapted.map(_ => r)) + +object GExecution: + + def apply[Params, L <: Layout]() = + Pure[Params, L, L]() + + def forParams[Params, L <: Layout, RL <: Layout](f: Params => GExecution[Params, L, RL]): GExecution[Params, L, RL] = + FlatMap[Params, L, RL, RL](Pure[Params, L, RL](), (params: Params, _: RL) => f(params)) + + case class Pure[Params, L <: Layout, RL <: Layout]() extends GExecution[Params, L, RL] + + case class FlatMap[Params, L <: Layout, RL <: Layout, NRL <: Layout]( + execution: GExecution[Params, L, RL], + f: (Params, RL) => GExecution[Params, L, NRL], + ) extends GExecution[Params, L, NRL] + + case class Map[P, NP, L <: Layout, NL <: Layout, RL <: Layout, NRL <: Layout]( + execution: GExecution[P, L, RL], + mapResult: RL => NRL, + contramapLayout: NL => L, + contramapParams: NP => P, + ) extends GExecution[NP, NL, NRL]: + + override def map[NNRL <: Layout](f: NRL => NNRL): GExecution[NP, NL, NNRL] = + Map(execution, mapResult andThen f, contramapLayout, contramapParams) + + override def contramapParams[NNP](f: NNP => NP): GExecution[NNP, NL, NRL] = + Map(execution, mapResult, contramapLayout, f andThen contramapParams) + + override def contramap[NNL <: Layout](f: NNL => NL): GExecution[NP, NNL, NRL] = + Map(execution, mapResult, f andThen contramapLayout, contramapParams) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala new file mode 100644 index 00000000..77586f5e --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala @@ -0,0 +1,70 @@ +package io.computenode.cyfra.core + +import io.computenode.cyfra.core.layout.LayoutStruct +import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.core.layout.Layout + +import java.nio.ByteBuffer +import GProgram.* +import io.computenode.cyfra.dsl.{Expression, Value} +import io.computenode.cyfra.dsl.Value.{FromExpr, Int32} +import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.GStruct.Empty +import izumi.reflect.Tag + +sealed trait GProgram[Params, L <: Layout: LayoutStruct] extends GExecution[Params, L, L]: + val layout: InitProgramLayout => Params => L + val dispatch: (L, Params) => ProgramDispatch + val workgroupSize: WorkDimensions + +object GProgram: + + class GioProgram[Params, L <: Layout: LayoutStruct]( + val body: L => GIO[?], + val layout: InitProgramLayout => Params => L, + val dispatch: (L, Params) => ProgramDispatch, + val workgroupSize: WorkDimensions, + ) extends GProgram[Params, L]: + private[cyfra] def layoutStruct: LayoutStruct[L] = summon[LayoutStruct[L]] + + class SpirvProgram[Params, L <: Layout: LayoutStruct]( + val code: ByteBuffer, + val layout: InitProgramLayout => Params => L, + val dispatch: (L, Params) => ProgramDispatch, + val workgroupSize: WorkDimensions, + ) extends GProgram[Params, L]: + private[cyfra] def layoutStruct: LayoutStruct[L] = summon[LayoutStruct[L]] + + type WorkDimensions = (Int, Int, Int) + + sealed trait ProgramDispatch + + case class DynamicDispatch[L <: Layout](buffer: GBinding[?], offset: Int) extends ProgramDispatch + + case class StaticDispatch(size: WorkDimensions) extends ProgramDispatch + + private[cyfra] case class BufferSizeSpec[T <: Value: {Tag, FromExpr}](size: Int) extends GBuffer[T] + + private[cyfra] case class ParamUniform[T <: GStruct[T]: {Tag, FromExpr}](value: T) extends GUniform[T] + + private[cyfra] case class DynamicUniform[T <: GStruct[T]: {Tag, FromExpr}]() extends GUniform[T] + + trait InitProgramLayout: + extension (buffers: GBuffer.type) + def apply[T <: Value: {Tag, FromExpr}](size: Int): GBuffer[T] = + BufferSizeSpec[T](size) + + extension (uniforms: GUniform.type) + def apply[T <: GStruct[T]: {Tag, FromExpr}](value: T): GUniform[T] = + ParamUniform[T](value) + + def apply[T <: GStruct[T]: {Tag, FromExpr}](): GUniform[T] = + DynamicUniform[T]() + + def apply[Params, L <: Layout: LayoutStruct]( + layout: InitProgramLayout ?=> Params => L, + dispatch: (L, Params) => ProgramDispatch, + workgroupSize: WorkDimensions = (128, 1, 1), + )(body: L => GIO[?]): GProgram[Params, L] = + new GioProgram[Params, L](body, s => layout(using s), dispatch, workgroupSize) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/Executable.scala similarity index 63% rename from cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala rename to cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/Executable.scala index b72be392..68e0b273 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/Executable.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/Executable.scala @@ -1,7 +1,7 @@ -package io.computenode.cyfra.runtime +package io.computenode.cyfra.core.archive +import io.computenode.cyfra.core.archive.mem.{GMem, RamGMem} import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.runtime.mem.{GMem, RamGMem} import scala.concurrent.Future diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala similarity index 86% rename from cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala rename to cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala index 3ebd43d9..c9f32763 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GContext.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala @@ -1,11 +1,12 @@ -package io.computenode.cyfra.runtime +package io.computenode.cyfra.core.archive +import io.computenode.cyfra.core.archive.mem.GMem.totalStride +import io.computenode.cyfra.core.archive.mem.{FloatMem, GMem, IntMem, Vec4FloatMem} +import io.computenode.cyfra.core.archive.{GFunction, UniformContext} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.{Float32, FromExpr, Int32, Vec4} import io.computenode.cyfra.dsl.collections.GArray import io.computenode.cyfra.dsl.struct.* -import io.computenode.cyfra.runtime.mem.GMem.totalStride -import io.computenode.cyfra.runtime.mem.{FloatMem, GMem, IntMem, Vec4FloatMem} import io.computenode.cyfra.spirv.SpirvTypes.typeStride import io.computenode.cyfra.spirv.compilers.DSLCompiler import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.{UniformStructRef, WorkerIndex} @@ -27,7 +28,7 @@ class GContext(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()): implicit val ec: ExecutionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(16)) - def compile[G <: GStruct[G]: Tag: GStructSchema, H <: Value: Tag: FromExpr, R <: Value: Tag: FromExpr]( + def compile[G <: GStruct[G]: {Tag, GStructSchema}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( function: GFunction[G, H, R], ): ComputePipeline = val uniformStructSchema = summon[GStructSchema[G]] @@ -45,7 +46,7 @@ class GContext(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()): val shader = Shader(optimizedShaderCode, org.joml.Vector3i(256, 1, 1), layoutInfo, "main", vkContext.device) ComputePipeline(shader, vkContext) - def execute[G <: GStruct[G]: Tag: GStructSchema, H <: Value, R <: Value](mem: GMem[H], fn: GFunction[G, H, R])(using + def execute[G <: GStruct[G]: {Tag, GStructSchema}, H <: Value, R <: Value](mem: GMem[H], fn: GFunction[G, H, R])(using uniformContext: UniformContext[G], ): GMem[R] = val isUniformEmpty = uniformContext.uniform.schema.fields.isEmpty diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala similarity index 64% rename from cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala rename to cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala index 1c85b3fd..c633f909 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/GFunction.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala @@ -1,13 +1,14 @@ -package io.computenode.cyfra.runtime +package io.computenode.cyfra.core.archive -import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.core.archive.GFunction import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.struct.* import io.computenode.cyfra.dsl.collections.{GArray, GArray2D} +import io.computenode.cyfra.dsl.struct.* +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.vulkan.compute.ComputePipeline import izumi.reflect.Tag -case class GFunction[G <: GStruct[G]: GStructSchema: Tag, H <: Value: Tag: FromExpr, R <: Value: Tag: FromExpr](fn: (G, Int32, GArray[H]) => R)( +case class GFunction[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: (G, Int32, GArray[H]) => R)( implicit context: GContext, ): def arrayInputs: List[Tag[?]] = List(summon[Tag[H]]) @@ -15,10 +16,10 @@ case class GFunction[G <: GStruct[G]: GStructSchema: Tag, H <: Value: Tag: FromE val pipeline: ComputePipeline = context.compile(this) object GFunction: - def apply[H <: Value: Tag: FromExpr, R <: Value: Tag: FromExpr](fn: H => R)(using context: GContext): GFunction[GStruct.Empty, H, R] = + def apply[H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: H => R)(using context: GContext): GFunction[GStruct.Empty, H, R] = new GFunction[GStruct.Empty, H, R]((_, index: Int32, gArray: GArray[H]) => fn(gArray.at(index))) - def from2D[G <: GStruct[G]: GStructSchema: Tag, H <: Value: Tag: FromExpr, R <: Value: Tag: FromExpr]( + def from2D[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( width: Int, )(fn: (G, (Int32, Int32), GArray2D[H]) => R)(using context: GContext): GFunction[G, H, R] = GFunction[G, H, R]((g: G, index: Int32, a: GArray[H]) => diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/UniformContext.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/UniformContext.scala new file mode 100644 index 00000000..093698ae --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/UniformContext.scala @@ -0,0 +1,13 @@ +package io.computenode.cyfra.core.archive + +import io.computenode.cyfra.core.archive.UniformContext +import io.computenode.cyfra.dsl.struct.* +import io.computenode.cyfra.dsl.struct.GStruct.Empty +import izumi.reflect.Tag + +class UniformContext[G <: GStruct[G]: {Tag, GStructSchema}](val uniform: G) + +object UniformContext: + def withUniform[G <: GStruct[G]: {Tag, GStructSchema}, T](uniform: G)(fn: UniformContext[G] ?=> T): T = + fn(using UniformContext(uniform)) + given empty: UniformContext[Empty] = new UniformContext(Empty()) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/FloatMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/FloatMem.scala similarity index 94% rename from cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/FloatMem.scala rename to cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/FloatMem.scala index 4264233d..2e51f2ee 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/FloatMem.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/FloatMem.scala @@ -1,4 +1,4 @@ -package io.computenode.cyfra.runtime.mem +package io.computenode.cyfra.core.archive.mem import io.computenode.cyfra.dsl.Value.Float32 import org.lwjgl.BufferUtils diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/GMem.scala similarity index 89% rename from cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala rename to cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/GMem.scala index a6efd211..41961aa4 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/GMem.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/GMem.scala @@ -1,9 +1,9 @@ -package io.computenode.cyfra.runtime.mem +package io.computenode.cyfra.core.archive.mem +import io.computenode.cyfra.core.archive.{GContext, GFunction, UniformContext} import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.struct.* import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.runtime.{GContext, GFunction, UniformContext} import io.computenode.cyfra.spirv.SpirvTypes.typeStride import izumi.reflect.Tag import org.lwjgl.BufferUtils @@ -13,7 +13,7 @@ import java.nio.ByteBuffer trait GMem[H <: Value]: def size: Int def toReadOnlyBuffer: ByteBuffer - def map[G <: GStruct[G]: Tag: GStructSchema, R <: Value: FromExpr: Tag]( + def map[G <: GStruct[G]: {Tag, GStructSchema}, R <: Value: {FromExpr, Tag}]( fn: GFunction[G, H, R], )(using context: GContext, uc: UniformContext[G]): GMem[R] = context.execute(this, fn) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/IntMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/IntMem.scala similarity index 93% rename from cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/IntMem.scala rename to cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/IntMem.scala index 72d12a82..ee9e61e8 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/IntMem.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/IntMem.scala @@ -1,4 +1,4 @@ -package io.computenode.cyfra.runtime.mem +package io.computenode.cyfra.core.archive.mem import io.computenode.cyfra.dsl.Value.Int32 import org.lwjgl.BufferUtils diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/RamGMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/RamGMem.scala similarity index 81% rename from cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/RamGMem.scala rename to cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/RamGMem.scala index 43e45f30..a136d7d4 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/RamGMem.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/RamGMem.scala @@ -1,4 +1,4 @@ -package io.computenode.cyfra.runtime.mem +package io.computenode.cyfra.core.archive.mem import io.computenode.cyfra.dsl.Value diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/Vec4FloatMem.scala similarity index 90% rename from cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala rename to cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/Vec4FloatMem.scala index ff48aa6b..0fdb63cb 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/mem/Vec4FloatMem.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/Vec4FloatMem.scala @@ -1,7 +1,7 @@ -package io.computenode.cyfra.runtime.mem +package io.computenode.cyfra.core.archive.mem +import io.computenode.cyfra.core.archive.mem.GMem.fRGBA import io.computenode.cyfra.dsl.Value.{Float32, Vec4} -import io.computenode.cyfra.runtime.mem.GMem.fRGBA import org.lwjgl.BufferUtils import java.nio.ByteBuffer diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/BufferRef.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/BufferRef.scala new file mode 100644 index 00000000..1ad1c3af --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/BufferRef.scala @@ -0,0 +1,9 @@ +package io.computenode.cyfra.core.binding + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.GBuffer +import izumi.reflect.Tag +import izumi.reflect.macrortti.LightTypeTag + +case class BufferRef[T <: Value: {Tag, FromExpr}](layoutOffset: Int, valueTag: Tag[T]) extends GBuffer[T] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/UniformRef.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/UniformRef.scala new file mode 100644 index 00000000..d7c3b308 --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/UniformRef.scala @@ -0,0 +1,10 @@ +package io.computenode.cyfra.core.binding + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} +import io.computenode.cyfra.dsl.struct.GStruct +import izumi.reflect.Tag +import izumi.reflect.macrortti.LightTypeTag + +case class UniformRef[T <: Value: {Tag, FromExpr}](layoutOffset: Int, valueTag: Tag[T]) extends GUniform[T] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/Layout.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/Layout.scala new file mode 100644 index 00000000..d03d858f --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/Layout.scala @@ -0,0 +1,6 @@ +package io.computenode.cyfra.core.layout + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.binding.GBuffer + +trait Layout diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala new file mode 100644 index 00000000..3d79b409 --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala @@ -0,0 +1,80 @@ +package io.computenode.cyfra.core.layout + +import io.computenode.cyfra.core.binding.{BufferRef, UniformRef} +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} +import izumi.reflect.Tag +import izumi.reflect.macrortti.LightTypeTag + +import scala.compiletime.{error, summonAll} +import scala.deriving.Mirror +import scala.quoted.{Expr, Quotes, Type} + +case class LayoutStruct[T <: Layout: Tag](private[cyfra] val layoutRef: T, private[cyfra] val elementTypes: List[Tag[? <: Value]]) + +object LayoutStruct: + + inline given derived[T <: Layout: Tag]: LayoutStruct[T] = ${ derivedImpl } + + def derivedImpl[T <: Layout: Type](using quotes: Quotes): Expr[LayoutStruct[T]] = + import quotes.reflect.* + + val tpe = TypeRepr.of[T] + val sym = tpe.typeSymbol + + if !sym.isClassDef || !sym.flags.is(Flags.Case) then report.errorAndAbort("LayoutStruct can only be derived for case classes") + + val fieldTypes = sym.caseFields + .map(_.tree) + .map: + case ValDef(_, tpt, _) => tpt.tpe + case _ => report.errorAndAbort("Unexpected field type in case class") + + if !fieldTypes.forall(_ <:< TypeRepr.of[GBinding[?]]) then + report.errorAndAbort("LayoutStruct can only be derived for case classes with GBinding elements") + + val valueTypes = fieldTypes.map: ftype => + (ftype, ftype.typeArgs.headOption.getOrElse(report.errorAndAbort("GBuffer must have a value type"))) + + // summon izumi tags + val typeGivens = valueTypes.map: + case (ftype, farg) => + farg.asType match + case '[type t <: Value; t] => + ( + ftype.asType, + farg.asType, + Expr.summon[Tag[t]] match + case Some(tagExpr) => tagExpr + case None => report.errorAndAbort(s"Cannot summon Tag for type ${tpe.show}"), + Expr.summon[FromExpr[t]] match + case Some(fromExpr) => fromExpr + case None => report.errorAndAbort(s"Cannot summon FromExpr for type ${tpe.show}"), + ) + + val buffers = typeGivens.zipWithIndex.map: + case ((ftype, tpe, tag, fromExpr), i) => + tpe match + case '[type t <: Value; t] => + ftype match + case '[type tg <: GBuffer[?]; tg] => + '{ + BufferRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }) + } + case '[type tg <: GUniform[?]; tg] => + '{ + UniformRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }) + } + + val constructor = sym.primaryConstructor + + val layoutInstance = Apply(Select(New(TypeIdent(sym)), constructor), buffers.map(_.asTerm)) + + val layoutRef = layoutInstance.asExprOf[T] + + val soleTags = typeGivens.map(_._3.asExprOf[Tag[? <: Value]]).toList + + '{ + LayoutStruct[T]($layoutRef, ${ Expr.ofList(soleTags) }) + } diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala index 52b8b844..18f81033 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala @@ -1,5 +1,5 @@ package io.computenode.cyfra.dsl -import io.computenode.cyfra.dsl.Expression + import Expression.{Const, treeidState} import io.computenode.cyfra.dsl.library.Functions.* import io.computenode.cyfra.dsl.Value.* @@ -107,6 +107,7 @@ object Expression: case class ExtFunctionCall[R <: Value: Tag](fn: FunctionName, args: List[Value]) extends Expression[R] case class FunctionCall[R <: Value: Tag](fn: FnIdentifier, body: Scope[R], args: List[Value]) extends E[R] + case object InvocationId extends E[Int32] case class Pass[T <: Value: Tag](value: T) extends E[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala index 03754998..985357e7 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala @@ -18,6 +18,10 @@ object Value: trait FromExpr[T <: Value]: def fromExpr(expr: E[T])(using name: Source): T + object FromExpr: + def fromExpr[T <: Value](expr: E[T])(using f: FromExpr[T]): T = + f.fromExpr(expr) + sealed trait Scalar extends Value trait FloatType extends Scalar diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala index 4684c61d..92cbe6ae 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/ScalarAlgebra.scala @@ -11,7 +11,7 @@ import scala.annotation.targetName object ScalarAlgebra: - trait BasicScalarAlgebra[T <: Scalar: FromExpr: Tag] + trait BasicScalarAlgebra[T <: Scalar: {FromExpr, Tag}] extends ScalarSummable[T] with ScalarDiffable[T] with ScalarMulable[T] @@ -20,54 +20,54 @@ object ScalarAlgebra: with Comparable[T] with ScalarNegatable[T] - trait BasicScalarIntAlgebra[T <: Scalar: FromExpr: Tag] extends BasicScalarAlgebra[T] with BitwiseOperable[T] + trait BasicScalarIntAlgebra[T <: Scalar: {FromExpr, Tag}] extends BasicScalarAlgebra[T] with BitwiseOperable[T] given BasicScalarAlgebra[Float32] = new BasicScalarAlgebra[Float32] {} given BasicScalarIntAlgebra[Int32] = new BasicScalarIntAlgebra[Int32] {} given BasicScalarIntAlgebra[UInt32] = new BasicScalarIntAlgebra[UInt32] {} - trait ScalarSummable[T <: Scalar: FromExpr: Tag]: + trait ScalarSummable[T <: Scalar: {FromExpr, Tag}]: def sum(a: T, b: T)(using name: Source): T = summon[FromExpr[T]].fromExpr(Sum(a, b)) - extension [T <: Scalar: ScalarSummable: Tag](a: T) + extension [T <: Scalar: {ScalarSummable, Tag}](a: T) @targetName("add") inline def +(b: T)(using Source): T = summon[ScalarSummable[T]].sum(a, b) - trait ScalarDiffable[T <: Scalar: FromExpr: Tag]: + trait ScalarDiffable[T <: Scalar: {FromExpr, Tag}]: def diff(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Diff(a, b)) - extension [T <: Scalar: ScalarDiffable: Tag](a: T) + extension [T <: Scalar: {ScalarDiffable, Tag}](a: T) @targetName("sub") inline def -(b: T)(using Source): T = summon[ScalarDiffable[T]].diff(a, b) // T and S ??? so two - trait ScalarMulable[T <: Scalar: FromExpr: Tag]: + trait ScalarMulable[T <: Scalar: {FromExpr, Tag}]: def mul(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Mul(a, b)) - extension [T <: Scalar: ScalarMulable: Tag](a: T) + extension [T <: Scalar: {ScalarMulable, Tag}](a: T) @targetName("mul") inline def *(b: T)(using Source): T = summon[ScalarMulable[T]].mul(a, b) - trait ScalarDivable[T <: Scalar: FromExpr: Tag]: + trait ScalarDivable[T <: Scalar: {FromExpr, Tag}]: def div(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Div(a, b)) - extension [T <: Scalar: ScalarDivable: Tag](a: T) + extension [T <: Scalar: {ScalarDivable, Tag}](a: T) @targetName("div") inline def /(b: T)(using Source): T = summon[ScalarDivable[T]].div(a, b) - trait ScalarNegatable[T <: Scalar: FromExpr: Tag]: + trait ScalarNegatable[T <: Scalar: {FromExpr, Tag}]: def negate(a: T)(using Source): T = summon[FromExpr[T]].fromExpr(Negate(a)) - extension [T <: Scalar: ScalarNegatable: Tag](a: T) + extension [T <: Scalar: {ScalarNegatable, Tag}](a: T) @targetName("negate") inline def unary_-(using Source): T = summon[ScalarNegatable[T]].negate(a) - trait ScalarModable[T <: Scalar: FromExpr: Tag]: + trait ScalarModable[T <: Scalar: {FromExpr, Tag}]: def mod(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(Mod(a, b)) - extension [T <: Scalar: ScalarModable: Tag](a: T) inline infix def mod(b: T)(using Source): T = summon[ScalarModable[T]].mod(a, b) + extension [T <: Scalar: {ScalarModable, Tag}](a: T) inline infix def mod(b: T)(using Source): T = summon[ScalarModable[T]].mod(a, b) - trait Comparable[T <: Scalar: FromExpr: Tag]: + trait Comparable[T <: Scalar: {FromExpr, Tag}]: def greaterThan(a: T, b: T)(using Source): GBoolean = GBoolean(GreaterThan(a, b)) def lessThan(a: T, b: T)(using Source): GBoolean = GBoolean(LessThan(a, b)) @@ -78,7 +78,7 @@ object ScalarAlgebra: def equal(a: T, b: T)(using Source): GBoolean = GBoolean(Equal(a, b)) - extension [T <: Scalar: Comparable: Tag](a: T) + extension [T <: Scalar: {Comparable, Tag}](a: T) inline def >(b: T)(using Source): GBoolean = summon[Comparable[T]].greaterThan(a, b) inline def <(b: T)(using Source): GBoolean = summon[Comparable[T]].lessThan(a, b) inline def >=(b: T)(using Source): GBoolean = summon[Comparable[T]].greaterThanEqual(a, b) @@ -102,7 +102,7 @@ object ScalarAlgebra: inline def asFloat(using Source): Float32 = Float32(ToFloat32(u32)) inline def signed(using Source): Int32 = Int32(ToInt32(u32)) - trait BitwiseOperable[T <: Scalar: FromExpr: Tag]: + trait BitwiseOperable[T <: Scalar: {FromExpr, Tag}]: def bitwiseAnd(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseAnd(a, b)) def bitwiseOr(a: T, b: T)(using Source): T = summon[FromExpr[T]].fromExpr(BitwiseOr(a, b)) @@ -115,7 +115,7 @@ object ScalarAlgebra: def shiftRight(a: T, by: UInt32)(using Source): T = summon[FromExpr[T]].fromExpr(ShiftRight(a, by)) - extension [T <: Scalar: BitwiseOperable: Tag](a: T) + extension [T <: Scalar: {BitwiseOperable, Tag}](a: T) inline def &(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseAnd(a, b) inline def |(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseOr(a, b) inline def ^(b: T)(using Source): T = summon[BitwiseOperable[T]].bitwiseXor(a, b) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala index f307f9b5..1f82a539 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/algebra/VectorAlgebra.scala @@ -11,7 +11,7 @@ import scala.annotation.targetName object VectorAlgebra: - trait BasicVectorAlgebra[S <: Scalar, V <: Vec[S]: FromExpr: Tag] + trait BasicVectorAlgebra[S <: Scalar, V <: Vec[S]: {FromExpr, Tag}] extends VectorSummable[V] with VectorDiffable[V] with VectorDotable[S, V] @@ -19,36 +19,36 @@ object VectorAlgebra: with VectorScalarMulable[S, V] with VectorNegatable[V] - given [T <: Scalar: FromExpr: Tag]: BasicVectorAlgebra[T, Vec2[T]] = new BasicVectorAlgebra[T, Vec2[T]] {} - given [T <: Scalar: FromExpr: Tag]: BasicVectorAlgebra[T, Vec3[T]] = new BasicVectorAlgebra[T, Vec3[T]] {} - given [T <: Scalar: FromExpr: Tag]: BasicVectorAlgebra[T, Vec4[T]] = new BasicVectorAlgebra[T, Vec4[T]] {} + given [T <: Scalar: {FromExpr, Tag}]: BasicVectorAlgebra[T, Vec2[T]] = new BasicVectorAlgebra[T, Vec2[T]] {} + given [T <: Scalar: {FromExpr, Tag}]: BasicVectorAlgebra[T, Vec3[T]] = new BasicVectorAlgebra[T, Vec3[T]] {} + given [T <: Scalar: {FromExpr, Tag}]: BasicVectorAlgebra[T, Vec4[T]] = new BasicVectorAlgebra[T, Vec4[T]] {} - trait VectorSummable[V <: Vec[?]: FromExpr: Tag]: + trait VectorSummable[V <: Vec[?]: {FromExpr, Tag}]: def sum(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Sum(a, b)) - extension [V <: Vec[?]: VectorSummable: Tag](a: V) + extension [V <: Vec[?]: {VectorSummable, Tag}](a: V) @targetName("addVector") inline def +(b: V)(using Source): V = summon[VectorSummable[V]].sum(a, b) - trait VectorDiffable[V <: Vec[?]: FromExpr: Tag]: + trait VectorDiffable[V <: Vec[?]: {FromExpr, Tag}]: def diff(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(Diff(a, b)) - extension [V <: Vec[?]: VectorDiffable: Tag](a: V) + extension [V <: Vec[?]: {VectorDiffable, Tag}](a: V) @targetName("subVector") inline def -(b: V)(using Source): V = summon[VectorDiffable[V]].diff(a, b) - trait VectorDotable[S <: Scalar: FromExpr: Tag, V <: Vec[S]: Tag]: + trait VectorDotable[S <: Scalar: {FromExpr, Tag}, V <: Vec[S]: Tag]: def dot(a: V, b: V)(using Source): S = summon[FromExpr[S]].fromExpr(DotProd[S, V](a, b)) extension [S <: Scalar: Tag, V <: Vec[S]: Tag](a: V)(using VectorDotable[S, V]) infix def dot(b: V)(using Source): S = summon[VectorDotable[S, V]].dot(a, b) - trait VectorCrossable[V <: Vec[?]: FromExpr: Tag]: + trait VectorCrossable[V <: Vec[?]: {FromExpr, Tag}]: def cross(a: V, b: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Cross, List(a, b))) - extension [V <: Vec[?]: VectorCrossable: Tag](a: V) infix def cross(b: V)(using Source): V = summon[VectorCrossable[V]].cross(a, b) + extension [V <: Vec[?]: {VectorCrossable, Tag}](a: V) infix def cross(b: V)(using Source): V = summon[VectorCrossable[V]].cross(a, b) - trait VectorScalarMulable[S <: Scalar: Tag, V <: Vec[S]: FromExpr: Tag]: + trait VectorScalarMulable[S <: Scalar: Tag, V <: Vec[S]: {FromExpr, Tag}]: def mul(a: V, b: S)(using Source): V = summon[FromExpr[V]].fromExpr(ScalarProd[S, V](a, b)) extension [S <: Scalar: Tag, V <: Vec[S]: Tag](a: V)(using VectorScalarMulable[S, V]) @@ -56,10 +56,10 @@ object VectorAlgebra: extension [S <: Scalar: Tag, V <: Vec[S]: Tag](s: S)(using VectorScalarMulable[S, V]) def *(v: V)(using Source): V = summon[VectorScalarMulable[S, V]].mul(v, s) - trait VectorNegatable[V <: Vec[?]: FromExpr: Tag]: + trait VectorNegatable[V <: Vec[?]: {FromExpr, Tag}]: def negate(a: V)(using Source): V = summon[FromExpr[V]].fromExpr(Negate(a)) - extension [V <: Vec[?]: VectorNegatable: Tag](a: V) + extension [V <: Vec[?]: {VectorNegatable, Tag}](a: V) @targetName("negateVector") def unary_-(using Source): V = summon[VectorNegatable[V]].negate(a) @@ -92,11 +92,11 @@ object VectorAlgebra: inline def vclamp(v: Vec3[Float32], min: Float32, max: Float32)(using Source): Vec3[Float32] = (clamp(v.x, min, max), clamp(v.y, min, max), clamp(v.z, min, max)) - extension [T <: Scalar: FromExpr: Tag](v2: Vec2[T]) + extension [T <: Scalar: {FromExpr, Tag}](v2: Vec2[T]) inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v2, Int32(ConstInt32(0)))) inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v2, Int32(ConstInt32(1)))) - extension [T <: Scalar: FromExpr: Tag](v3: Vec3[T]) + extension [T <: Scalar: {FromExpr, Tag}](v3: Vec3[T]) inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(0)))) inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(1)))) inline def z(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v3, Int32(ConstInt32(2)))) @@ -104,7 +104,7 @@ object VectorAlgebra: inline def g(using Source): T = y inline def b(using Source): T = z - extension [T <: Scalar: FromExpr: Tag](v4: Vec4[T]) + extension [T <: Scalar: {FromExpr, Tag}](v4: Vec4[T]) inline def x(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(0)))) inline def y(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(1)))) inline def z(using Source): T = summon[FromExpr[T]].fromExpr(ExtractScalar(v4, Int32(ConstInt32(2)))) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala new file mode 100644 index 00000000..d9006d69 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala @@ -0,0 +1,7 @@ +package io.computenode.cyfra.dsl.binding + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import izumi.reflect.Tag + +trait GBinding[T <: Value: {Tag, FromExpr}] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBuffer.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBuffer.scala new file mode 100644 index 00000000..b9f849cf --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBuffer.scala @@ -0,0 +1,13 @@ +package io.computenode.cyfra.dsl.binding + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.{FromExpr, Int32} +import io.computenode.cyfra.dsl.gio.GIO +import izumi.reflect.Tag + +trait GBuffer[T <: Value: {FromExpr, Tag}] extends GBinding[T]: + def read(index: Int32): T = FromExpr.fromExpr(ReadBuffer(this, index)) + + def write(index: Int32, value: T): GIO[Unit] = GIO.write(this, index, value) + +object GBuffer diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GUniform.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GUniform.scala new file mode 100644 index 00000000..9e753e77 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GUniform.scala @@ -0,0 +1,19 @@ +package io.computenode.cyfra.dsl.binding + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.Value.FromExpr.fromExpr +import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.dsl.struct.GStruct +import izumi.reflect.Tag + +trait GUniform[T <: Value: {Tag, FromExpr}] extends GBinding[T]: + def read: T = fromExpr(ReadUniform(this)) + + def write(value: T): GIO[Unit] = WriteUniform(this, value) + +object GUniform: + + case class ParamUniform[T <: GStruct[T]: {Tag, FromExpr}]() extends GUniform[T] + + def fromParams[T <: GStruct[T]: {Tag, FromExpr}] = ParamUniform[T]() diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadBuffer.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadBuffer.scala new file mode 100644 index 00000000..e0057720 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadBuffer.scala @@ -0,0 +1,7 @@ +package io.computenode.cyfra.dsl.binding + +import io.computenode.cyfra.dsl.Value.Int32 +import io.computenode.cyfra.dsl.{Expression, Value} +import izumi.reflect.Tag + +case class ReadBuffer[T <: Value: Tag](buffer: GBuffer[T], index: Int32) extends Expression[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadUniform.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadUniform.scala new file mode 100644 index 00000000..9f75a278 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadUniform.scala @@ -0,0 +1,6 @@ +package io.computenode.cyfra.dsl.binding + +import io.computenode.cyfra.dsl.{Expression, Value} +import izumi.reflect.Tag + +case class ReadUniform[T <: Value: Tag](uniform: GUniform[T]) extends Expression[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteBuffer.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteBuffer.scala new file mode 100644 index 00000000..53b0abf9 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteBuffer.scala @@ -0,0 +1,8 @@ +package io.computenode.cyfra.dsl.binding + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.Int32 +import io.computenode.cyfra.dsl.gio.GIO + +case class WriteBuffer[T <: Value](buffer: GBuffer[T], index: Int32, value: T) extends GIO[Unit]: + override def underlying: Unit = () diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala new file mode 100644 index 00000000..240aa643 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala @@ -0,0 +1,9 @@ +package io.computenode.cyfra.dsl.binding + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.dsl.struct.GStruct +import izumi.reflect.Tag + +case class WriteUniform[T <: Value: Tag](uniform: GUniform[T], value: T) extends GIO[Unit]: + override def underlying: Unit = () diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala index f91383a0..6e9daf13 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala @@ -6,7 +6,7 @@ import io.computenode.cyfra.dsl.macros.Source import io.computenode.cyfra.dsl.{Expression, Value} import izumi.reflect.Tag -case class GArray[T <: Value: Tag: FromExpr](index: Int): +case class GArray[T <: Value: {Tag, FromExpr}](index: Int): def at(i: Int32)(using Source): T = summon[FromExpr[T]].fromExpr(GArrayElem(index, i.tree)) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala index 090797bf..70d6df19 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala @@ -7,6 +7,6 @@ import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag import io.computenode.cyfra.dsl.Value.FromExpr -class GArray2D[T <: Value: Tag: FromExpr](width: Int, val arr: GArray[T]): +class GArray2D[T <: Value: {Tag, FromExpr}](width: Int, val arr: GArray[T]): def at(x: Int32, y: Int32)(using Source): T = arr.at(y * width + x) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala index 103c5050..b4265a1b 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GSeq.scala @@ -10,7 +10,7 @@ import io.computenode.cyfra.dsl.macros.Source import io.computenode.cyfra.dsl.{Expression, Value} import izumi.reflect.Tag -class GSeq[T <: Value: Tag: FromExpr]( +class GSeq[T <: Value: {Tag, FromExpr}]( val uninitSource: Expression[?] => GSeqStream[?], val elemOps: List[GSeq.ElemOp[?]], val limit: Option[Int], @@ -19,7 +19,7 @@ class GSeq[T <: Value: Tag: FromExpr]( val aggregateElemExprTreeId: Int = treeidState.getAndIncrement(), ): - def copyWithDynamicTrees[R <: Value: Tag: FromExpr]( + def copyWithDynamicTrees[R <: Value: {Tag, FromExpr}]( elemOps: List[GSeq.ElemOp[?]] = elemOps, limit: Option[Int] = limit, currentElemExprTreeId: Int = currentElemExprTreeId, @@ -29,9 +29,9 @@ class GSeq[T <: Value: Tag: FromExpr]( private val currentElemExpr = CurrentElem[T](currentElemExprTreeId) val source = uninitSource(currentElemExpr) private def currentElem: T = summon[FromExpr[T]].fromExpr(currentElemExpr) - private def aggregateElem[R <: Value: Tag: FromExpr]: R = summon[FromExpr[R]].fromExpr(AggregateElem[R](aggregateElemExprTreeId)) + private def aggregateElem[R <: Value: {Tag, FromExpr}]: R = summon[FromExpr[R]].fromExpr(AggregateElem[R](aggregateElemExprTreeId)) - def map[R <: Value: Tag: FromExpr](fn: T => R): GSeq[R] = + def map[R <: Value: {Tag, FromExpr}](fn: T => R): GSeq[R] = this.copyWithDynamicTrees[R](elemOps = elemOps :+ GSeq.MapOp[T, R](fn(currentElem).tree)) def filter(fn: T => GBoolean): GSeq[T] = @@ -43,7 +43,7 @@ class GSeq[T <: Value: Tag: FromExpr]( def limit(n: Int): GSeq[T] = this.copyWithDynamicTrees(limit = Some(n)) - def fold[R <: Value: Tag: FromExpr](zero: R, fn: (R, T) => R): R = + def fold[R <: Value: {Tag, FromExpr}](zero: R, fn: (R, T) => R): R = summon[FromExpr[R]].fromExpr(GSeq.FoldSeq(zero, fn(aggregateElem, currentElem).tree, this)) def count: Int32 = @@ -54,11 +54,11 @@ class GSeq[T <: Value: Tag: FromExpr]( object GSeq: - def gen[T <: Value: Tag: FromExpr](first: T, next: T => T)(using name: Source) = + def gen[T <: Value: {Tag, FromExpr}](first: T, next: T => T)(using name: Source) = GSeq(ce => GSeqStream(first, next(summon[FromExpr[T]].fromExpr(ce.asInstanceOf[E[T]])).tree), Nil, None, name) // REALLY naive implementation, should be replaced with dynamic array (O(1)) access - def of[T <: Value: Tag: FromExpr](xs: List[T]) = + def of[T <: Value: {Tag, FromExpr}](xs: List[T]) = GSeq .gen[Int32](0, _ + 1) .map: i => diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Pure.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Pure.scala index 6f0bd5ff..2e517641 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Pure.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/Pure.scala @@ -7,6 +7,6 @@ import io.computenode.cyfra.dsl.{Expression, Value} import izumi.reflect.Tag object Pure: - def pure[V <: Value: FromExpr: Tag](f: => V)(using fnCall: FnCall): V = + def pure[V <: Value: {FromExpr, Tag}](f: => V)(using fnCall: FnCall): V = val call = FunctionCall[V](fnCall.identifier, Scope(f.tree.asInstanceOf[Expression[V]], isDetached = true), fnCall.params) summon[FromExpr[V]].fromExpr(call) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala index 33df3207..9e7be3ad 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/control/When.scala @@ -7,7 +7,13 @@ import io.computenode.cyfra.dsl.Value.{FromExpr, GBoolean} import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag -case class When[T <: Value: Tag: FromExpr](when: GBoolean, thenCode: T, otherConds: List[Scope[GBoolean]], otherCases: List[Scope[T]], name: Source): +case class When[T <: Value: {Tag, FromExpr}]( + when: GBoolean, + thenCode: T, + otherConds: List[Scope[GBoolean]], + otherCases: List[Scope[T]], + name: Source, +): def elseWhen(cond: GBoolean)(t: T): When[T] = When(when, thenCode, otherConds :+ Scope(cond.tree), otherCases :+ Scope(t.tree.asInstanceOf[E[T]]), name) infix def otherwise(t: T): T = @@ -24,5 +30,5 @@ object When: otherwise: Scope[T], ) extends Expression[T] - def when[T <: Value: Tag: FromExpr](cond: GBoolean)(fn: T)(using name: Source): When[T] = + def when[T <: Value: {Tag, FromExpr}](cond: GBoolean)(fn: T)(using name: Source): When[T] = When(cond, fn, Nil, Nil, name) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala new file mode 100644 index 00000000..02a018f8 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala @@ -0,0 +1,45 @@ +package io.computenode.cyfra.dsl.gio + +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.dsl.Value.{FromExpr, Int32} +import io.computenode.cyfra.dsl.Value.FromExpr.fromExpr +import io.computenode.cyfra.dsl.binding.{GBuffer, ReadBuffer, WriteBuffer} +import io.computenode.cyfra.dsl.collections.GSeq +import io.computenode.cyfra.dsl.gio.GIO.* +import izumi.reflect.Tag + +trait GIO[T]: + + def flatMap[U](f: T => GIO[U]): GIO[U] = FlatMap(this, f(this.underlying)) + + def map[U](f: T => U): GIO[U] = flatMap(t => GIO.pure(f(t))) + + private[cyfra] def underlying: T + +object GIO: + + case class Pure[T](value: T) extends GIO[T]: + override def underlying: T = value + + case class FlatMap[T, U](gio: GIO[T], next: GIO[U]) extends GIO[U]: + override def underlying: U = next.underlying + + // TODO repeat that collects results + case class Repeat(n: Int32, f: Int32 => GIO[?]) extends GIO[Unit]: + override def underlying: Unit = () + + def pure[T](value: T): GIO[T] = Pure(value) + + def value[T](value: T): GIO[T] = Pure(value) + + def repeat(n: Int32)(f: Int32 => GIO[?]): GIO[Unit] = + Repeat(n, f) + + def write[T <: Value](buffer: GBuffer[T], index: Int32, value: T): GIO[Unit] = + WriteBuffer(buffer, index, value) + + def read[T <: Value: {FromExpr, Tag}](buffer: GBuffer[T], index: Int32): T = + fromExpr(ReadBuffer(buffer, index)) + + def invocationId: Int32 = + fromExpr(InvocationId) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala index 0de27564..26b4a970 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/library/Functions.scala @@ -16,7 +16,7 @@ object Functions: case object Cos extends FunctionName def cos(v: Float32)(using Source): Float32 = Float32(ExtFunctionCall(Cos, List(v))) - def cos[V <: Vec[Float32]: Tag: FromExpr](v: V)(using Source): V = + def cos[V <: Vec[Float32]: {Tag, FromExpr}](v: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Cos, List(v))) case object Tan extends FunctionName @@ -43,7 +43,7 @@ object Functions: case object Pow extends FunctionName def pow(v: Float32, p: Float32)(using Source): Float32 = Float32(ExtFunctionCall(Pow, List(v, p))) - def pow[V <: Vec[?]: Tag: FromExpr](v: V, p: V)(using Source): V = + def pow[V <: Vec[?]: {Tag, FromExpr}](v: V, p: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Pow, List(v, p))) case object Smoothstep extends FunctionName @@ -61,48 +61,48 @@ object Functions: case object Exp extends FunctionName def exp(f: Float32)(using Source): Float32 = Float32(ExtFunctionCall(Exp, List(f))) - def exp[V <: Vec[Float32]: Tag: FromExpr](v: V)(using Source): V = + def exp[V <: Vec[Float32]: {Tag, FromExpr}](v: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Exp, List(v))) case object Max extends FunctionName def max(f1: Float32, f2: Float32)(using Source): Float32 = Float32(ExtFunctionCall(Max, List(f1, f2))) def max(f1: Float32, f2: Float32, fx: Float32*)(using Source): Float32 = fx.foldLeft(max(f1, f2))((a, b) => max(a, b)) - def max[V <: Vec[Float32]: Tag: FromExpr](v1: V, v2: V)(using Source): V = + def max[V <: Vec[Float32]: {Tag, FromExpr}](v1: V, v2: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Max, List(v1, v2))) - def max[V <: Vec[Float32]: Tag: FromExpr](v1: V, v2: V, vx: V*)(using Source): V = + def max[V <: Vec[Float32]: {Tag, FromExpr}](v1: V, v2: V, vx: V*)(using Source): V = vx.foldLeft(max(v1, v2))((a, b) => max(a, b)) case object Min extends FunctionName def min(f1: Float32, f2: Float32)(using Source): Float32 = Float32(ExtFunctionCall(Min, List(f1, f2))) def min(f1: Float32, f2: Float32, fx: Float32*)(using Source): Float32 = fx.foldLeft(min(f1, f2))((a, b) => min(a, b)) - def min[V <: Vec[Float32]: Tag: FromExpr](v1: V, v2: V)(using Source): V = + def min[V <: Vec[Float32]: {Tag, FromExpr}](v1: V, v2: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Min, List(v1, v2))) - def min[V <: Vec[Float32]: Tag: FromExpr](v1: V, v2: V, vx: V*)(using Source): V = + def min[V <: Vec[Float32]: {Tag, FromExpr}](v1: V, v2: V, vx: V*)(using Source): V = vx.foldLeft(min(v1, v2))((a, b) => min(a, b)) // todo add F/U/S to all functions that need it case object Abs extends FunctionName def abs(f: Float32)(using Source): Float32 = Float32(ExtFunctionCall(Abs, List(f))) - def abs[V <: Vec[Float32]: Tag: FromExpr](v: V)(using Source): V = + def abs[V <: Vec[Float32]: {Tag, FromExpr}](v: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Abs, List(v))) case object Mix extends FunctionName - def mix[V <: Vec[Float32]: Tag: FromExpr](a: V, b: V, t: V)(using Source) = + def mix[V <: Vec[Float32]: {Tag, FromExpr}](a: V, b: V, t: V)(using Source) = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Mix, List(a, b, t))) def mix(a: Float32, b: Float32, t: Float32)(using Source) = Float32(ExtFunctionCall(Mix, List(a, b, t))) - def mix[V <: Vec[Float32]: Tag: FromExpr](a: V, b: V, t: Float32)(using Source) = + def mix[V <: Vec[Float32]: {Tag, FromExpr}](a: V, b: V, t: Float32)(using Source) = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Mix, List(a, b, vec3(t)))) case object Reflect extends FunctionName - def reflect[I <: Vec[Float32]: Tag: FromExpr, N <: Vec[Float32]: Tag: FromExpr](I: I, N: N)(using Source): I = + def reflect[I <: Vec[Float32]: {Tag, FromExpr}, N <: Vec[Float32]: {Tag, FromExpr}](I: I, N: N)(using Source): I = summon[FromExpr[I]].fromExpr(ExtFunctionCall(Reflect, List(I, N))) case object Refract extends FunctionName - def refract[V <: Vec[Float32]: Tag: FromExpr](I: V, N: V, eta: Float32)(using Source): V = + def refract[V <: Vec[Float32]: {Tag, FromExpr}](I: V, N: V, eta: Float32)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Refract, List(I, N, eta))) case object Normalize extends FunctionName - def normalize[V <: Vec[Float32]: Tag: FromExpr](v: V)(using Source): V = + def normalize[V <: Vec[Float32]: {Tag, FromExpr}](v: V)(using Source): V = summon[FromExpr[V]].fromExpr(ExtFunctionCall(Normalize, List(v))) case object Log extends FunctionName diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala index 6ed56ab0..9ec4199b 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala @@ -10,7 +10,7 @@ import izumi.reflect.Tag import scala.compiletime.* import scala.deriving.Mirror -abstract class GStruct[T <: GStruct[T]: Tag: GStructSchema] extends Value with Product: +abstract class GStruct[T <: GStruct[T]: {Tag, GStructSchema}] extends Value with Product: self: T => private[cyfra] var _schema: GStructSchema[T] = summon[GStructSchema[T]] // a nasty hack def schema: GStructSchema[T] = _schema diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticsE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticsE2eTest.scala index 3ffd6b71..17797a77 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticsE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticsE2eTest.scala @@ -1,6 +1,6 @@ package io.computenode.cyfra.e2e -import io.computenode.cyfra.runtime.* +import io.computenode.cyfra.core.archive.* import mem.* import GMem.fRGBA import io.computenode.cyfra.dsl.algebra.VectorAlgebra diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsE2eTest.scala index 6a332ac8..31966edf 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsE2eTest.scala @@ -1,6 +1,6 @@ package io.computenode.cyfra.e2e -import io.computenode.cyfra.runtime.*, mem.* +import io.computenode.cyfra.core.archive.*, mem.* import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} import GMem.fRGBA diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructE2eTest.scala index 61b4db15..c1183c2a 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructE2eTest.scala @@ -2,7 +2,7 @@ package io.computenode.cyfra.e2e import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.runtime.* +import io.computenode.cyfra.core.archive.* import mem.* import io.computenode.cyfra.dsl.{*, given} diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala index 8b70999e..d10cca51 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala @@ -2,7 +2,7 @@ package io.computenode.cyfra.e2e import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.runtime.* +import io.computenode.cyfra.core.archive.* import mem.* import io.computenode.cyfra.dsl.{*, given} diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenE2eTest.scala index 3a53669f..0a374c26 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenE2eTest.scala @@ -1,7 +1,7 @@ package io.computenode.cyfra.e2e import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.runtime.* +import io.computenode.cyfra.core.archive.* import mem.* import io.computenode.cyfra.dsl.{*, given} diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala index 7431960d..df9b0191 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala @@ -6,8 +6,8 @@ import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.control.Pure.pure import io.computenode.cyfra.dsl.struct.GStruct.Empty import io.computenode.cyfra.e2e.ImageTests -import io.computenode.cyfra.runtime.mem.Vec4FloatMem -import io.computenode.cyfra.runtime.{GContext, GFunction} +import io.computenode.cyfra.core.archive.mem.Vec4FloatMem +import io.computenode.cyfra.core.archive.{GContext, GFunction} import io.computenode.cyfra.spirvtools.* import io.computenode.cyfra.spirvtools.SpirvTool.{Param, ToFile} import io.computenode.cyfra.utility.ImageUtility diff --git a/cyfra-examples/src/main/resources/gio.scala b/cyfra-examples/src/main/resources/gio.scala new file mode 100644 index 00000000..1ef1889a --- /dev/null +++ b/cyfra-examples/src/main/resources/gio.scala @@ -0,0 +1,12 @@ +import io.computenode.cyfra.dsl.Value.Int32 + +val inBuffer = GBuffer[Int32]() +val outBuffer = GBuffer[Int32]() + +val program = GProgram.on(inBuffer, outBuffer): + case (in, out) => for + index <- GIO.workerIndex + a <- in.read(index) + _ <- out.write(index, a + 1) + _ <- out.write(index * 2, a * 2) + yield () \ No newline at end of file diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala new file mode 100644 index 00000000..d94c895b --- /dev/null +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -0,0 +1,109 @@ +package io.computenode.cyfra.samples + +import io.computenode.cyfra.core.archive.GContext +import io.computenode.cyfra.core.{GBufferRegion, GExecution, GProgram} +import io.computenode.cyfra.core.layout.* +import io.computenode.cyfra.dsl.Value.{GBoolean, Int32} +import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} +import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.{*, given} +import org.lwjgl.BufferUtils +import io.computenode.cyfra.runtime.VkCyfraRuntime +object TestingStuff: + + given GContext = GContext() + + // === Emit program === + + case class EmitProgramParams(inSize: Int, emitN: Int) + + case class EmitProgramUniform(emitN: Int32) extends GStruct[EmitProgramUniform] + + case class EmitProgramLayout( + in: GBuffer[Int32], + out: GBuffer[Int32], + args: GUniform[EmitProgramUniform] = GUniform.fromParams, // todo will be different in the future + ) extends Layout + + val emitProgram = GProgram[EmitProgramParams, EmitProgramLayout]( + layout = params => + EmitProgramLayout( + in = GBuffer[Int32](params.inSize), + out = GBuffer[Int32](params.inSize * params.emitN), + args = GUniform(EmitProgramUniform(params.emitN)), + ), + dispatch = (layout, args) => GProgram.StaticDispatch((args.inSize, 1, 1)), + ): layout => + val EmitProgramUniform(emitN) = layout.args.read + val invocId = GIO.invocationId + val element = GIO.read(layout.in, invocId) + val bufferOffset = invocId * emitN + GIO.repeat(emitN): i => + GIO.write(layout.out, bufferOffset + i, element) + + // === Filter program === + + case class FilterProgramParams(inSize: Int, filterValue: Int) + + case class FilterProgramUniform(filterValue: Int32) extends GStruct[FilterProgramUniform] + + case class FilterProgramLayout(in: GBuffer[Int32], out: GBuffer[GBoolean], params: GUniform[FilterProgramUniform] = GUniform.fromParams) + extends Layout + + val filterProgram = GProgram[FilterProgramParams, FilterProgramLayout]( + layout = params => + FilterProgramLayout( + in = GBuffer[Int32](params.inSize), + out = GBuffer[GBoolean](params.inSize), + params = GUniform(FilterProgramUniform(params.filterValue)), + ), + dispatch = (layout, args) => GProgram.StaticDispatch((args.inSize, 1, 1)), + ): layout => + val invocId = GIO.invocationId + val element = GIO.read(layout.in, invocId) + val isMatch = element === layout.params.read.filterValue + GIO.write(layout.out, invocId, isMatch) + + // === GExecution === + + case class EmitFilterParams(inSize: Int, emitN: Int, filterValue: Int) + + case class EmitFilterLayout(inBuffer: GBuffer[Int32], emitBuffer: GBuffer[Int32], filterBuffer: GBuffer[GBoolean]) extends Layout + + case class EmitFilterResult(out: GBuffer[GBoolean]) extends Layout + + val emitFilterExecution = GExecution[EmitFilterParams, EmitFilterLayout]() + .addProgram(emitProgram)( + params => EmitProgramParams(inSize = params.inSize, emitN = params.emitN), + layout => EmitProgramLayout(in = layout.inBuffer, out = layout.emitBuffer), + ) + .addProgram(filterProgram)( + params => FilterProgramParams(inSize = params.inSize, filterValue = params.filterValue), + layout => FilterProgramLayout(in = layout.emitBuffer, out = layout.filterBuffer), + ) + + @main + def test = + given VkCyfraRuntime = VkCyfraRuntime() + + val emitFilterParams = EmitFilterParams(inSize = 1024, emitN = 2, filterValue = 42) + + val region = GBufferRegion + .allocate[EmitFilterLayout] + .map: region => + emitFilterExecution.execute(emitFilterParams, region) + + val data = (0 to 1024).toArray + val buffer = BufferUtils.createByteBuffer(data.length * 4) + buffer.asIntBuffer().put(data).flip() + + val result = BufferUtils.createByteBuffer(data.length * 2) + region.runUnsafe( + init = EmitFilterLayout( + inBuffer = GBuffer[Int32](buffer), + emitBuffer = GBuffer[Int32](data.length * 2), + filterBuffer = GBuffer[GBoolean](data.length * 2), + ), + onDone = layout => layout.filterBuffer.read(result), + ) diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/foton/AnimatedJulia.scala similarity index 97% rename from cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala rename to cyfra-examples/src/main/scala/io/computenode/cyfra/samples/foton/AnimatedJulia.scala index 200e16a6..99bd6759 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/foton/AnimatedJulia.scala @@ -1,4 +1,4 @@ -package io.computenode.samples.cyfra.foton +package io.computenode.cyfra.samples.foton import io.computenode.cyfra import io.computenode.cyfra.* diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/foton/AnimatedRaytrace.scala similarity index 98% rename from cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala rename to cyfra-examples/src/main/scala/io/computenode/cyfra/samples/foton/AnimatedRaytrace.scala index bd2c65de..f478647a 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/foton/AnimatedRaytrace.scala @@ -1,4 +1,4 @@ -package io.computenode.samples.cyfra.foton +package io.computenode.cyfra.samples.foton import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.library.Color.hex diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/oldsamples/Raytracing.scala similarity index 99% rename from cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala rename to cyfra-examples/src/main/scala/io/computenode/cyfra/samples/oldsamples/Raytracing.scala index b9c2279d..ab35810e 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/oldsamples/Raytracing.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/oldsamples/Raytracing.scala @@ -1,10 +1,10 @@ -package io.computenode.samples.cyfra.oldsamples +package io.computenode.cyfra.samples.oldsamples import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.runtime.mem.Vec4FloatMem +import io.computenode.cyfra.core.archive.* +import io.computenode.cyfra.core.archive.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility import java.nio.file.Paths diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/1sample.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/1sample.scala similarity index 69% rename from cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/1sample.scala rename to cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/1sample.scala index 518687d3..16121da4 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/1sample.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/1sample.scala @@ -1,8 +1,8 @@ -package io.computenode.samples.cyfra.slides +package io.computenode.cyfra.samples.slides import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.runtime.mem.FloatMem +import io.computenode.cyfra.core.archive.* +import io.computenode.cyfra.core.archive.mem.FloatMem given GContext = new GContext() diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/2simpleray.scala similarity index 91% rename from cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala rename to cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/2simpleray.scala index 6575bbaa..145fe5e6 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/2simpleray.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/2simpleray.scala @@ -1,10 +1,10 @@ -package io.computenode.samples.cyfra.slides +package io.computenode.cyfra.samples.slides import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.struct.GStruct.Empty -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.runtime.mem.Vec4FloatMem +import io.computenode.cyfra.core.archive.* +import io.computenode.cyfra.core.archive.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility import java.nio.file.Paths diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/3rays.scala similarity index 97% rename from cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala rename to cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/3rays.scala index 7784be27..49ff0d46 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/3rays.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/3rays.scala @@ -1,12 +1,12 @@ -package io.computenode.samples.cyfra.slides +package io.computenode.cyfra.samples.slides import io.computenode.cyfra.* import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.struct.GStruct.Empty -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.runtime.mem.Vec4FloatMem +import io.computenode.cyfra.core.archive.* +import io.computenode.cyfra.core.archive.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility import java.nio.file.Paths diff --git a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/4random.scala similarity index 98% rename from cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala rename to cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/4random.scala index 4ecd8e8b..bac16f3b 100644 --- a/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/slides/4random.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/4random.scala @@ -1,11 +1,11 @@ -package io.computenode.samples.cyfra.slides +package io.computenode.cyfra.samples.slides import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.struct.GStruct.Empty -import io.computenode.cyfra.runtime.* -import io.computenode.cyfra.runtime.mem.Vec4FloatMem +import io.computenode.cyfra.core.archive.* +import io.computenode.cyfra.core.archive.mem.Vec4FloatMem import io.computenode.cyfra.utility.ImageUtility import java.nio.file.Paths diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala index d8d6dff5..1e18cd28 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala @@ -6,9 +6,9 @@ import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.animation.AnimatedFunctionRenderer.{AnimationIteration, RenderFn} import io.computenode.cyfra.foton.animation.AnimationFunctions.AnimationInstant -import io.computenode.cyfra.runtime.mem.GMem.fRGBA -import io.computenode.cyfra.runtime.mem.Vec4FloatMem -import io.computenode.cyfra.runtime.{GContext, GFunction, UniformContext} +import io.computenode.cyfra.core.archive.mem.GMem.fRGBA +import io.computenode.cyfra.core.archive.mem.Vec4FloatMem +import io.computenode.cyfra.core.archive.{GContext, GFunction, UniformContext} import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContext.Implicits diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala index df4ea7ca..9a262e95 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala @@ -3,8 +3,8 @@ package io.computenode.cyfra.foton.animation import io.computenode.cyfra import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.runtime.GFunction -import io.computenode.cyfra.runtime.mem.GMem.fRGBA +import io.computenode.cyfra.core.archive.GFunction +import io.computenode.cyfra.core.archive.mem.GMem.fRGBA import io.computenode.cyfra.utility.ImageUtility import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra.utility.Utility.timed diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala index 6a314eb5..8f4d2b70 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala @@ -6,9 +6,9 @@ import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration -import io.computenode.cyfra.runtime.mem.GMem.fRGBA -import io.computenode.cyfra.runtime.mem.Vec4FloatMem -import io.computenode.cyfra.runtime.{GFunction, UniformContext} +import io.computenode.cyfra.core.archive.mem.GMem.fRGBA +import io.computenode.cyfra.core.archive.mem.Vec4FloatMem +import io.computenode.cyfra.core.archive.{GFunction, UniformContext} import io.computenode.cyfra.utility.ImageUtility import io.computenode.cyfra.utility.Utility.timed diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala index 1c591a71..b59765b1 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala @@ -10,7 +10,7 @@ import io.computenode.cyfra.dsl.library.Random import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo -import io.computenode.cyfra.runtime.GContext +import io.computenode.cyfra.core.archive.GContext import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContext.Implicits diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala index 2674c237..c339bec9 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala @@ -7,9 +7,9 @@ import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.animation.AnimationRenderer import io.computenode.cyfra.foton.rt.RtRenderer import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration -import io.computenode.cyfra.runtime.mem.GMem.fRGBA -import io.computenode.cyfra.runtime.mem.Vec4FloatMem -import io.computenode.cyfra.runtime.{GFunction, UniformContext} +import io.computenode.cyfra.core.archive.mem.GMem.fRGBA +import io.computenode.cyfra.core.archive.mem.Vec4FloatMem +import io.computenode.cyfra.core.archive.{GFunction, UniformContext} class AnimationRtRenderer(params: AnimationRtRenderer.Parameters) extends RtRenderer(params) diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala index efe2c76a..27fce060 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/shapes/ShapeCollection.scala @@ -36,7 +36,7 @@ class ShapeCollection(val boxes: List[Box], val spheres: List[Sphere], val quads case _ => assert(false, "Unknown shape type: Broken sealed hierarchy") def testRay(rayPos: Vec3[Float32], rayDir: Vec3[Float32], noHit: RayHitInfo): RayHitInfo = - def testShapeType[T <: GStruct[T] & Shape: FromExpr: Tag: TestRay](shapes: List[T], currentHit: RayHitInfo): RayHitInfo = + def testShapeType[T <: GStruct[T] & Shape: {FromExpr, Tag, TestRay}](shapes: List[T], currentHit: RayHitInfo): RayHitInfo = val testRay = summon[TestRay[T]] if shapes.isEmpty then currentHit else GSeq.of(shapes).fold(currentHit, (currentHit, shape) => testRay.testRay(shape, rayPos, rayDir, currentHit)) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala new file mode 100644 index 00000000..df0b470e --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -0,0 +1,11 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.core.{GExecution, GProgram} +import io.computenode.cyfra.core.layout.Layout + +object ExecutionHandler: + + def handle[Params, L <: Layout, RL <: Layout](execution: GExecution[Params, L, RL], params: Params): List[BoundProgram[?, ?, ?]] = + ??? + + case class BoundProgram[LParams, Params, L <: Layout](layout: L, paramsMapping: LParams => Params, program: GProgram[Params, L]) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/UniformContext.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/UniformContext.scala deleted file mode 100644 index 04df0996..00000000 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/UniformContext.scala +++ /dev/null @@ -1,12 +0,0 @@ -package io.computenode.cyfra.runtime - -import io.computenode.cyfra.dsl.struct.* -import io.computenode.cyfra.dsl.struct.GStruct.Empty -import izumi.reflect.Tag - -class UniformContext[G <: GStruct[G]: Tag: GStructSchema](val uniform: G) - -object UniformContext: - def withUniform[G <: GStruct[G]: Tag: GStructSchema, T](uniform: G)(fn: UniformContext[G] ?=> T): T = - fn(using UniformContext(uniform)) - given empty: UniformContext[Empty] = new UniformContext(Empty()) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala new file mode 100644 index 00000000..d1474976 --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -0,0 +1,29 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.core.layout.{Layout, LayoutStruct} +import io.computenode.cyfra.core.{Allocation, GExecution} +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} +import io.computenode.cyfra.dsl.struct.GStruct +import izumi.reflect.Tag + +import java.nio.ByteBuffer + +class VkAllocation extends Allocation: + extension (buffer: GBinding[?]) + def read(bb: ByteBuffer, offset: Int = 0, length: Int = -1): Unit = ??? + + def write(bb: ByteBuffer, offset: Int = 0, length: Int = -1): Unit = ??? + + extension [Params, L <: Layout, RL <: Layout: LayoutStruct](execution: GExecution[Params, L, RL]) def execute(params: Params, layout: L): RL = ??? + + extension (buffers: GBuffer.type) + def apply[T <: Value: {Tag, FromExpr}](size: Int): GBuffer[T] = ??? + + def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] = ??? + + extension (buffers: GUniform.type) + def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GUniform[T] = ??? + + def apply[T <: Value: {Tag, FromExpr}](): GUniform[T] = ??? diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala new file mode 100644 index 00000000..87dbd5ab --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala @@ -0,0 +1,8 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.core.Allocation +import io.computenode.cyfra.core.{Allocation, CyfraRuntime} + +class VkCyfraRuntime extends CyfraRuntime: + override def allocation(): Allocation = + new VkAllocation() From 4a93d1637cc702e12e2dee287ae11a6febde25fd Mon Sep 17 00:00:00 2001 From: MarconZet <25779550+MarconZet@users.noreply.github.com> Date: Mon, 7 Jul 2025 21:40:27 +0200 Subject: [PATCH 09/59] Vulkan cleanup (#57) --- build.sbt | 6 +- .../cyfra/core/archive/GContext.scala | 93 +++++++++---------- .../cyfra/core/archive/GFunction.scala | 4 +- .../src/test/resources/copy_test2.comp | 15 --- .../src/test/resources/simple_key.comp | 15 --- cyfra-e2e-test/src/test/resources/sort.comp | 39 -------- .../src/test/resources/two_copy.comp | 22 ----- .../cyfra/vulkan/VulkanContext.scala | 16 ++-- .../cyfra/vulkan/command/CommandPool.scala | 50 ++++++---- .../cyfra/vulkan/command/Fence.scala | 4 +- .../vulkan/command/OneTimeCommandPool.scala | 10 -- .../cyfra/vulkan/command/Semaphore.scala | 2 +- .../vulkan/command/StandardCommandPool.scala | 9 -- .../vulkan/compute/ComputePipeline.scala | 45 +++++++-- .../cyfra/vulkan/compute/LayoutInfo.scala | 1 + .../cyfra/vulkan/compute/Shader.scala | 54 ----------- .../cyfra/vulkan/core/DebugCallback.scala | 10 +- .../cyfra/vulkan/core/Instance.scala | 4 +- .../vulkan/{command => core}/Queue.scala | 6 +- .../vulkan/executor/AbstractExecutor.scala | 81 ---------------- .../cyfra/vulkan/executor/MapExecutor.scala | 54 ----------- .../vulkan/executor/SequenceExecutor.scala | 38 +++----- .../cyfra/vulkan/memory/Buffer.scala | 65 +++++++------ .../cyfra/vulkan/memory/DescriptorPool.scala | 4 +- .../cyfra/vulkan/memory/DescriptorSet.scala | 20 ++-- .../src/test/resources/compileAll.ps1 | 0 .../src/test/resources/compileAll.sh | 0 .../src/test/resources/copy_test.comp | 0 .../cyfra}/vulkan/SequenceExecutorTest.scala | 19 ++-- 29 files changed, 210 insertions(+), 476 deletions(-) delete mode 100644 cyfra-e2e-test/src/test/resources/copy_test2.comp delete mode 100644 cyfra-e2e-test/src/test/resources/simple_key.comp delete mode 100644 cyfra-e2e-test/src/test/resources/sort.comp delete mode 100644 cyfra-e2e-test/src/test/resources/two_copy.comp delete mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/OneTimeCommandPool.scala delete mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/StandardCommandPool.scala delete mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/Shader.scala rename cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/{command => core}/Queue.scala (80%) delete mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala delete mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala rename {cyfra-e2e-test => cyfra-vulkan}/src/test/resources/compileAll.ps1 (100%) rename {cyfra-e2e-test => cyfra-vulkan}/src/test/resources/compileAll.sh (100%) rename {cyfra-e2e-test => cyfra-vulkan}/src/test/resources/copy_test.comp (100%) rename {cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e => cyfra-vulkan/src/test/scala/io/computenode/cyfra}/vulkan/SequenceExecutorTest.scala (67%) diff --git a/build.sbt b/build.sbt index a36c04dc..44acec5f 100644 --- a/build.sbt +++ b/build.sbt @@ -70,7 +70,7 @@ lazy val vulkan = (project in file("cyfra-vulkan")) lazy val dsl = (project in file("cyfra-dsl")) .settings(commonSettings) - .dependsOn(vulkan, utility) + .dependsOn(utility) lazy val compiler = (project in file("cyfra-compiler")) .settings(commonSettings) @@ -78,11 +78,11 @@ lazy val compiler = (project in file("cyfra-compiler")) lazy val core = (project in file("cyfra-core")) .settings(commonSettings) - .dependsOn(compiler, dsl, vulkan, utility, spirvTools) + .dependsOn(compiler, dsl, utility, spirvTools) lazy val runtime = (project in file("cyfra-runtime")) .settings(commonSettings) - .dependsOn(core) + .dependsOn(core, vulkan) lazy val foton = (project in file("cyfra-foton")) .settings(commonSettings) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala index c9f32763..9f209ea4 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala @@ -11,10 +11,7 @@ import io.computenode.cyfra.spirv.SpirvTypes.typeStride import io.computenode.cyfra.spirv.compilers.DSLCompiler import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.{UniformStructRef, WorkerIndex} import io.computenode.cyfra.spirvtools.SpirvToolsRunner -import io.computenode.cyfra.vulkan.VulkanContext -import io.computenode.cyfra.vulkan.compute.* -import io.computenode.cyfra.vulkan.executor.SequenceExecutor.* -import io.computenode.cyfra.vulkan.executor.{BufferAction, SequenceExecutor} + import izumi.reflect.Tag import org.lwjgl.system.Configuration @@ -24,55 +21,55 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} class GContext(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()): Configuration.STACK_SIZE.set(1024) // fix lwjgl stack size - val vkContext = new VulkanContext() + val vkContext = ??? implicit val ec: ExecutionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(16)) def compile[G <: GStruct[G]: {Tag, GStructSchema}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( function: GFunction[G, H, R], - ): ComputePipeline = - val uniformStructSchema = summon[GStructSchema[G]] - val uniformStruct = uniformStructSchema.fromTree(UniformStructRef) - val tree = function.fn - .apply(uniformStruct, WorkerIndex, GArray[H](0)) - - val optimizedShaderCode = - spirvToolsRunner.processShaderCodeWithSpirvTools(DSLCompiler.compile(tree, function.arrayInputs, function.arrayOutputs, uniformStructSchema)) - - val inOut = 0 to 1 map (Binding(_, InputBufferSize(typeStride(summon[Tag[H]])))) - val uniform = Option.when(uniformStructSchema.fields.nonEmpty)(Binding(2, UniformSize(totalStride(uniformStructSchema)))) - val layoutInfo = LayoutInfo(Seq(LayoutSet(0, inOut ++ uniform))) - - val shader = Shader(optimizedShaderCode, org.joml.Vector3i(256, 1, 1), layoutInfo, "main", vkContext.device) - ComputePipeline(shader, vkContext) + ): Nothing = ??? +// val uniformStructSchema = summon[GStructSchema[G]] +// val uniformStruct = uniformStructSchema.fromTree(UniformStructRef) +// val tree = function.fn +// .apply(uniformStruct, WorkerIndex, GArray[H](0)) +// +// val optimizedShaderCode = +// spirvToolsRunner.processShaderCodeWithSpirvTools(DSLCompiler.compile(tree, function.arrayInputs, function.arrayOutputs, uniformStructSchema)) +// +// val inOut = 0 to 1 map (Binding(_, InputBufferSize(typeStride(summon[Tag[H]])))) +// val uniform = Option.when(uniformStructSchema.fields.nonEmpty)(Binding(2, UniformSize(totalStride(uniformStructSchema)))) +// val layoutInfo = LayoutInfo(Seq(LayoutSet(0, inOut ++ uniform))) +// +// val shader = Shader(optimizedShaderCode, org.joml.Vector3i(256, 1, 1), layoutInfo, "main", vkContext.device) +// ComputePipeline(shader, vkContext) def execute[G <: GStruct[G]: {Tag, GStructSchema}, H <: Value, R <: Value](mem: GMem[H], fn: GFunction[G, H, R])(using uniformContext: UniformContext[G], - ): GMem[R] = - val isUniformEmpty = uniformContext.uniform.schema.fields.isEmpty - val actions = Map(LayoutLocation(0, 0) -> BufferAction.LoadTo, LayoutLocation(0, 1) -> BufferAction.LoadFrom) ++ - ( - if isUniformEmpty then Map.empty - else Map(LayoutLocation(0, 2) -> BufferAction.LoadTo) - ) - val sequence = ComputationSequence(Seq(Compute(fn.pipeline, actions)), Seq.empty) - val executor = new SequenceExecutor(sequence, vkContext) - - val data = mem.toReadOnlyBuffer - val inData = - if isUniformEmpty then Seq(data) - else Seq(data, GMem.serializeUniform(uniformContext.uniform)) - val out = executor.execute(inData, mem.size) - executor.destroy() - - val outTags = fn.arrayOutputs - assert(outTags.size == 1) - - outTags.head match - case t if t == Tag[Float32] => - new FloatMem(mem.size, out.head).asInstanceOf[GMem[R]] - case t if t == Tag[Int32] => - new IntMem(mem.size, out.head).asInstanceOf[GMem[R]] - case t if t == Tag[Vec4[Float32]] => - new Vec4FloatMem(mem.size, out.head).asInstanceOf[GMem[R]] - case _ => assert(false, "Supported output types are Float32 and Vec4[Float32]") + ): GMem[R] = ??? +// val isUniformEmpty = uniformContext.uniform.schema.fields.isEmpty +// val actions = Map(LayoutLocation(0, 0) -> BufferAction.LoadTo, LayoutLocation(0, 1) -> BufferAction.LoadFrom) ++ +// ( +// if isUniformEmpty then Map.empty +// else Map(LayoutLocation(0, 2) -> BufferAction.LoadTo) +// ) +// val sequence = ComputationSequence(Seq(Compute(fn.pipeline, actions)), Seq.empty) +// val executor = new SequenceExecutor(sequence, vkContext) +// +// val data = mem.toReadOnlyBuffer +// val inData = +// if isUniformEmpty then Seq(data) +// else Seq(data, GMem.serializeUniform(uniformContext.uniform)) +// val out = executor.execute(inData, mem.size) +// executor.destroy() +// +// val outTags = fn.arrayOutputs +// assert(outTags.size == 1) +// +// outTags.head match +// case t if t == Tag[Float32] => +// new FloatMem(mem.size, out.head).asInstanceOf[GMem[R]] +// case t if t == Tag[Int32] => +// new IntMem(mem.size, out.head).asInstanceOf[GMem[R]] +// case t if t == Tag[Vec4[Float32]] => +// new Vec4FloatMem(mem.size, out.head).asInstanceOf[GMem[R]] +// case _ => assert(false, "Supported output types are Float32 and Vec4[Float32]") diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala index c633f909..c5613bb7 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala @@ -5,7 +5,7 @@ import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.collections.{GArray, GArray2D} import io.computenode.cyfra.dsl.struct.* import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.vulkan.compute.ComputePipeline + import izumi.reflect.Tag case class GFunction[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: (G, Int32, GArray[H]) => R)( @@ -13,7 +13,7 @@ case class GFunction[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, Fr ): def arrayInputs: List[Tag[?]] = List(summon[Tag[H]]) def arrayOutputs: List[Tag[?]] = List(summon[Tag[R]]) - val pipeline: ComputePipeline = context.compile(this) + val pipeline: Nothing = ??? object GFunction: def apply[H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: H => R)(using context: GContext): GFunction[GStruct.Empty, H, R] = diff --git a/cyfra-e2e-test/src/test/resources/copy_test2.comp b/cyfra-e2e-test/src/test/resources/copy_test2.comp deleted file mode 100644 index 4277429c..00000000 --- a/cyfra-e2e-test/src/test/resources/copy_test2.comp +++ /dev/null @@ -1,15 +0,0 @@ -#version 450 - -layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in; - -layout (binding = 0, set = 0) buffer InputBuffer { - int inArray[]; -}; -layout (binding = 0, set = 1) buffer OutputBuffer { - int outArray[]; -}; - -void main(void){ - uint index = gl_GlobalInvocationID.x; - outArray[index] = inArray[index] + 2137; -} diff --git a/cyfra-e2e-test/src/test/resources/simple_key.comp b/cyfra-e2e-test/src/test/resources/simple_key.comp deleted file mode 100644 index 13760003..00000000 --- a/cyfra-e2e-test/src/test/resources/simple_key.comp +++ /dev/null @@ -1,15 +0,0 @@ -#version 450 - -layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in; - -layout (binding = 0, set = 0) buffer InputBuffer { - float inArray[]; -}; -layout (binding = 1, set = 0) buffer OutputBuffer { - float outArray[]; -}; - -void main(void){ - uint index = gl_GlobalInvocationID.x; - outArray[index] = inArray[index]; -} \ No newline at end of file diff --git a/cyfra-e2e-test/src/test/resources/sort.comp b/cyfra-e2e-test/src/test/resources/sort.comp deleted file mode 100644 index 37ba1c40..00000000 --- a/cyfra-e2e-test/src/test/resources/sort.comp +++ /dev/null @@ -1,39 +0,0 @@ -#version 450 - -layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in; - -layout (binding = 0, set = 0) buffer KeysBuffer { - int keys[]; -}; -layout (binding = 1, set = 0) buffer OrderBuffer { - uint order[]; -}; - -int get_value(uint index){ - return keys[order[index]]; -} - -void swap(uint a, uint b){ - uint t = order[a]; - order[a] = order[b]; - order[b] = t; -} - -void main(void){ - uint N = gl_NumWorkGroups.x * gl_WorkGroupSize.x; - uint gi = gl_GlobalInvocationID.x; - order[gi] = gi; - - uint j, k, i = gi; - for (k=2;k<=N;k=2*k) { - for (j=k>>1;j>0;j=j>>1) { - memoryBarrierBuffer(); - barrier(); - uint ixj=i^j; - if ((ixj)>i) { - if ((i&k)==0 && get_value(i)>get_value(ixj)) swap(i, ixj); - if ((i&k)!=0 && get_value(i) val createInfo = VkCommandPoolCreateInfo .calloc(stack) .sType$Default() - .pNext(VK_NULL_HANDLE) + .pNext(0) .queueFamilyIndex(queue.familyIndex) - .flags(getFlags) + .flags(flags) val pCommandPoll = stack.callocLong(1) check(vkCreateCommandPool(device.get, createInfo, null, pCommandPoll), "Failed to create command pool") @@ -24,18 +24,6 @@ private[cyfra] abstract class CommandPool(device: Device, queue: Queue) extends private val commandPool = handle - def beginSingleTimeCommands(): VkCommandBuffer = - pushStack: stack => - val commandBuffer = this.createCommandBuffer() - - val beginInfo = VkCommandBufferBeginInfo - .calloc(stack) - .sType$Default() - .flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) - - check(vkBeginCommandBuffer(commandBuffer, beginInfo), "Failed to begin single time command buffer") - commandBuffer - def createCommandBuffer(): VkCommandBuffer = createCommandBuffers(1).head @@ -51,7 +39,25 @@ private[cyfra] abstract class CommandPool(device: Device, queue: Queue) extends check(vkAllocateCommandBuffers(device.get, allocateInfo, pointerBuffer), "Failed to allocate command buffers") 0 until n map (i => pointerBuffer.get(i)) map (new VkCommandBuffer(_, device.get)) - def endSingleTimeCommands(commandBuffer: VkCommandBuffer): Fence = + def executeCommand(block: VkCommandBuffer => Unit): Fence = + pushStack: stack => + val commandBuffer = beginSingleTimeCommands() + block(commandBuffer) + endSingleTimeCommands(commandBuffer) + + private def beginSingleTimeCommands(): VkCommandBuffer = + pushStack: stack => + val commandBuffer = this.createCommandBuffer() + + val beginInfo = VkCommandBufferBeginInfo + .calloc(stack) + .sType$Default() + .flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) + + check(vkBeginCommandBuffer(commandBuffer, beginInfo), "Failed to begin single time command buffer") + commandBuffer + + private def endSingleTimeCommands(commandBuffer: VkCommandBuffer): Fence = pushStack: stack => vkEndCommandBuffer(commandBuffer) val pointerBuffer = stack.callocPointer(1).put(0, commandBuffer) @@ -59,8 +65,8 @@ private[cyfra] abstract class CommandPool(device: Device, queue: Queue) extends .calloc(stack) .sType$Default() .pCommandBuffers(pointerBuffer) - val fence = new Fence(device, 0, () => freeCommandBuffer(commandBuffer)) - queue.submit(submitInfo, fence) + val fence = new Fence(0, () => freeCommandBuffer(commandBuffer)) + check(vkQueueSubmit(queue.get, submitInfo, fence.get), "Failed to submit single time command buffer") fence def freeCommandBuffer(commandBuffer: VkCommandBuffer*): Unit = @@ -73,4 +79,8 @@ private[cyfra] abstract class CommandPool(device: Device, queue: Queue) extends protected def close(): Unit = vkDestroyCommandPool(device.get, commandPool, null) - protected def getFlags: Int +object CommandPool: + private[cyfra] class OneTime(queue: Queue)(using device: Device) + extends CommandPool(VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queue)(using device: Device) // TODO check if flags should be used differently + + private[cyfra] class Standard(queue: Queue)(using device: Device) extends CommandPool(0, queue)(using device: Device) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala index 31f16d8c..50c350ca 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala @@ -9,12 +9,12 @@ import org.lwjgl.vulkan.VkFenceCreateInfo /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] class Fence(device: Device, flags: Int = 0, onDestroy: () => Unit = () => ()) extends VulkanObjectHandle: +private[cyfra] class Fence(flags: Int = 0, onDestroy: () => Unit = () => ())(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack(stack => val fenceInfo = VkFenceCreateInfo .calloc(stack) .sType$Default() - .pNext(VK_NULL_HANDLE) + .pNext(0) .flags(flags) val pFence = stack.callocLong(1) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/OneTimeCommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/OneTimeCommandPool.scala deleted file mode 100644 index 67621756..00000000 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/OneTimeCommandPool.scala +++ /dev/null @@ -1,10 +0,0 @@ -package io.computenode.cyfra.vulkan.command - -import io.computenode.cyfra.vulkan.core.Device -import org.lwjgl.vulkan.VK10.VK_COMMAND_POOL_CREATE_TRANSIENT_BIT - -/** @author - * MarconZet Created 13.04.2020 Copied from Wrap - */ -private[cyfra] class OneTimeCommandPool(device: Device, queue: Queue) extends CommandPool(device, queue): - protected def getFlags: Int = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala index e65b145a..04034b1c 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala @@ -9,7 +9,7 @@ import org.lwjgl.vulkan.VkSemaphoreCreateInfo /** @author * MarconZet Created 30.10.2019 */ -private[cyfra] class Semaphore(device: Device) extends VulkanObjectHandle: +private[cyfra] class Semaphore(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => val semaphoreCreateInfo = VkSemaphoreCreateInfo .calloc(stack) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/StandardCommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/StandardCommandPool.scala deleted file mode 100644 index a7127f4a..00000000 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/StandardCommandPool.scala +++ /dev/null @@ -1,9 +0,0 @@ -package io.computenode.cyfra.vulkan.command - -import io.computenode.cyfra.vulkan.core.Device - -/** @author - * MarconZet Created 13.04.2020 Copied from Wrap - */ -private[cyfra] class StandardCommandPool(device: Device, queue: Queue) extends CommandPool(device, queue): - protected def getFlags: Int = 0 diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala index d452b13f..c63d2210 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala @@ -7,13 +7,32 @@ import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.vulkan.* import org.lwjgl.vulkan.VK10.* +import java.io.{File, FileInputStream} +import java.nio.ByteBuffer +import java.nio.channels.FileChannel +import java.util.Objects +import scala.util.{Try, Using} + /** @author * MarconZet Created 14.04.2020 */ -private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanContext) extends VulkanObjectHandle: - private val device: Device = context.device - val descriptorSetLayouts: Seq[(Long, LayoutSet)] = - computeShader.layoutInfo.sets.map(x => (createDescriptorSetLayout(x), x)) +private[cyfra] class ComputePipeline(shaderCode: ByteBuffer, functionName: String, val layoutInfo: LayoutInfo)(using device: Device) + extends VulkanObjectHandle: + + private val shader: Long = pushStack: stack => // TODO khr_maintenance5 + val shaderModuleCreateInfo = VkShaderModuleCreateInfo + .calloc(stack) + .sType$Default() + .pNext(0) + .flags(0) + .pCode(shaderCode) + + val pShaderModule = stack.callocLong(1) + check(vkCreateShaderModule(device.get, shaderModuleCreateInfo, null, pShaderModule), "Failed to create shader module") + pShaderModule.get() + + val descriptorSetLayouts: Seq[(Long, LayoutSet)] = layoutInfo.sets.map(x => (createDescriptorSetLayout(x), x)) + val pipelineLayout: Long = pushStack: stack => val pipelineLayoutCreateInfo = VkPipelineLayoutCreateInfo .calloc(stack) @@ -34,8 +53,8 @@ private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanC .pNext(0) .flags(0) .stage(VK_SHADER_STAGE_COMPUTE_BIT) - .module(computeShader.get) - .pName(stack.ASCII(computeShader.functionName)) + .module(shader) + .pName(stack.ASCII(functionName)) val computePipelineCreateInfo = VkComputePipelineCreateInfo.calloc(1, stack) computePipelineCreateInfo @@ -49,13 +68,14 @@ private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanC .basePipelineIndex(0) val pPipeline = stack.callocLong(1) - check(vkCreateComputePipelines(device.get, 0, computePipelineCreateInfo, null, pPipeline), "Failed to create compute pipeline") + check(vkCreateComputePipelines(device.get, 0, computePipelineCreateInfo, null, pPipeline), "Failed to create compute pipeline") // TODO vkCreatePipelineCache pPipeline.get(0) protected def close(): Unit = vkDestroyPipeline(device.get, handle, null) vkDestroyPipelineLayout(device.get, pipelineLayout, null) descriptorSetLayouts.map(_._1).foreach(vkDestroyDescriptorSetLayout(device.get, _, null)) + vkDestroyShaderModule(device.get, handle, null) private def createDescriptorSetLayout(set: LayoutSet): Long = pushStack: stack => val descriptorSetLayoutBindings = VkDescriptorSetLayoutBinding.calloc(set.bindings.length, stack) @@ -82,3 +102,14 @@ private[cyfra] class ComputePipeline(val computeShader: Shader, context: VulkanC val pDescriptorSetLayout = stack.callocLong(1) check(vkCreateDescriptorSetLayout(device.get, descriptorSetLayoutCreateInfo, null, pDescriptorSetLayout), "Failed to create descriptor set layout") pDescriptorSetLayout.get(0) + +object ComputePipeline: + def loadShader(path: String): Try[ByteBuffer] = + loadShader(path, getClass.getClassLoader) + + private def loadShader(path: String, classLoader: ClassLoader): Try[ByteBuffer] = + Using.Manager: use => + val file = new File(Objects.requireNonNull(classLoader.getResource(path)).getFile) + val fis = use(new FileInputStream(file)) + val fc = use(fis.getChannel) + fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/LayoutInfo.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/LayoutInfo.scala index 80cbf919..1edbcea8 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/LayoutInfo.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/LayoutInfo.scala @@ -6,6 +6,7 @@ package io.computenode.cyfra.vulkan.compute private[cyfra] case class LayoutInfo(sets: Seq[LayoutSet]) private[cyfra] case class LayoutSet(id: Int, bindings: Seq[Binding]) private[cyfra] case class Binding(id: Int, size: LayoutElementSize) + private[cyfra] sealed trait LayoutElementSize private[cyfra] case class InputBufferSize(elemSize: Int) extends LayoutElementSize private[cyfra] case class UniformSize(size: Int) extends LayoutElementSize diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/Shader.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/Shader.scala deleted file mode 100644 index 6032e37f..00000000 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/Shader.scala +++ /dev/null @@ -1,54 +0,0 @@ -package io.computenode.cyfra.vulkan.compute - -import io.computenode.cyfra.vulkan.core.Device -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} -import io.computenode.cyfra.vulkan.util.VulkanObjectHandle -import org.joml.Vector3ic -import org.lwjgl.vulkan.VK10.* -import org.lwjgl.vulkan.VkShaderModuleCreateInfo - -import java.io.{File, FileInputStream, IOException} -import java.nio.ByteBuffer -import java.nio.channels.FileChannel -import java.util.Objects - -/** @author - * MarconZet Created 25.04.2020 - */ -private[cyfra] class Shader( - shaderCode: ByteBuffer, - val workgroupDimensions: Vector3ic, - val layoutInfo: LayoutInfo, - val functionName: String, - device: Device, -) extends VulkanObjectHandle: - - protected val handle: Long = pushStack: stack => - val shaderModuleCreateInfo = VkShaderModuleCreateInfo - .calloc(stack) - .sType$Default() - .pNext(0) - .flags(0) - .pCode(shaderCode) - - val pShaderModule = stack.callocLong(1) - check(vkCreateShaderModule(device.get, shaderModuleCreateInfo, null, pShaderModule), "Failed to create shader module") - pShaderModule.get() - - protected def close(): Unit = - vkDestroyShaderModule(device.get, handle, null) - -object Shader: - - def loadShader(path: String): ByteBuffer = - loadShader(path, getClass.getClassLoader) - - private def loadShader(path: String, classLoader: ClassLoader): ByteBuffer = - try - val file = new File(Objects.requireNonNull(classLoader.getResource(path)).getFile) - val fis = new FileInputStream(file) - val fc = fis.getChannel - fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()) - catch - case e: IOException => - throw new RuntimeException(e) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala index 4c2c37ca..f3e83712 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala @@ -1,7 +1,7 @@ package io.computenode.cyfra.vulkan.core import io.computenode.cyfra.utility.Logger.logger -import io.computenode.cyfra.vulkan.core.DebugCallback.DEBUG_REPORT +import io.computenode.cyfra.vulkan.core.DebugCallback.DebugReport import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil.NULL @@ -15,7 +15,7 @@ import java.lang.Integer.highestOneBit * MarconZet Created 13.04.2020 */ object DebugCallback: - val DEBUG_REPORT = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT + val DebugReport: Int = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandle: override protected val handle: Long = @@ -42,7 +42,7 @@ private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandl logger.info(decodedMessage) case x => logger.error(s"Unexpected value: x, message: $decodedMessage") 0 - setupDebugging(DEBUG_REPORT, debugCallback) + setupDebugging(DebugReport, debugCallback) override protected def close(): Unit = vkDestroyDebugReportCallbackEXT(instance.get, handle, null) @@ -51,9 +51,9 @@ private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandl val dbgCreateInfo = VkDebugReportCallbackCreateInfoEXT .create() .sType$Default() - .pNext(NULL) + .pNext(0) .pfnCallback(callback) - .pUserData(NULL) + .pUserData(0) .flags(flags) val pCallback = BufferUtils.createLongBuffer(1) val err = vkCreateDebugReportCallbackEXT(instance.get, dbgCreateInfo, null, pCallback) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala index 4f7479e3..dfb585d1 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala @@ -45,7 +45,7 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj val appInfo = VkApplicationInfo .calloc(stack) .sType$Default() - .pNext(NULL) + .pNext(0) .pApplicationName(stack.UTF8("cyfra MVP")) .pEngineName(stack.UTF8("cyfra Computing Engine")) .applicationVersion(VK_MAKE_VERSION(0, 1, 0)) @@ -63,7 +63,7 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj .calloc(stack) .sType$Default() .flags(VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR) - .pNext(NULL) + .pNext(0) .pApplicationInfo(appInfo) .ppEnabledExtensionNames(ppEnabledExtensionNames) .ppEnabledLayerNames(ppEnabledLayerNames) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Queue.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Queue.scala similarity index 80% rename from cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Queue.scala rename to cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Queue.scala index 506ee37c..7d894ba8 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Queue.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Queue.scala @@ -1,5 +1,6 @@ -package io.computenode.cyfra.vulkan.command +package io.computenode.cyfra.vulkan.core +import io.computenode.cyfra.vulkan.command.Fence import io.computenode.cyfra.vulkan.core.Device import io.computenode.cyfra.vulkan.util.Util.pushStack import io.computenode.cyfra.vulkan.util.VulkanObject @@ -15,9 +16,6 @@ private[cyfra] class Queue(val familyIndex: Int, queueIndex: Int, device: Device vkGetDeviceQueue(device.get, familyIndex, queueIndex, pQueue) new VkQueue(pQueue.get(0), device.get) - def submit(submitInfo: VkSubmitInfo, fence: Fence): Int = this.synchronized: - vkQueueSubmit(queue, submitInfo, fence.get) - def get: VkQueue = queue protected def close(): Unit = () diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala deleted file mode 100644 index 823f129e..00000000 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/AbstractExecutor.scala +++ /dev/null @@ -1,81 +0,0 @@ -package io.computenode.cyfra.vulkan.executor - -import io.computenode.cyfra.vulkan.VulkanContext -import io.computenode.cyfra.vulkan.command.{CommandPool, Fence, Queue} -import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} -import io.computenode.cyfra.vulkan.core.Device -import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer, DescriptorPool, DescriptorSet} -import org.lwjgl.BufferUtils -import org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_UNKNOWN -import org.lwjgl.vulkan.* -import org.lwjgl.vulkan.VK10.* - -import java.nio.ByteBuffer - -private[cyfra] abstract class AbstractExecutor(dataLength: Int, val bufferActions: Seq[BufferAction], context: VulkanContext): - protected val device: Device = context.device - protected val queue: Queue = context.computeQueue - protected val allocator: Allocator = context.allocator - protected val descriptorPool: DescriptorPool = context.descriptorPool - protected val commandPool: CommandPool = context.commandPool - - protected val (descriptorSets, buffers) = setupBuffers() - private val commandBuffer: VkCommandBuffer = pushStack: stack => - val commandBuffer = commandPool.createCommandBuffer() - val commandBufferBeginInfo = VkCommandBufferBeginInfo - .calloc(stack) - .sType$Default() - .flags(0) - - check(vkBeginCommandBuffer(commandBuffer, commandBufferBeginInfo), "Failed to begin recording command buffer") - - recordCommandBuffer(commandBuffer) - - check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") - commandBuffer - - def execute(input: Seq[ByteBuffer]): Seq[ByteBuffer] = - val stagingBuffer = - new Buffer( - getBiggestTransportData * dataLength, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - VMA_MEMORY_USAGE_UNKNOWN, - allocator, - ) - for i <- bufferActions.indices if bufferActions(i) == BufferAction.LoadTo do - val buffer = input(i) - Buffer.copyBuffer(buffer, stagingBuffer, buffer.remaining()) - Buffer.copyBuffer(stagingBuffer, buffers(i), buffer.remaining(), commandPool).block().destroy() - - pushStack: stack => - val fence = new Fence(device) - val pCommandBuffer = stack.callocPointer(1).put(0, commandBuffer) - val submitInfo = VkSubmitInfo - .calloc(stack) - .sType$Default() - .pCommandBuffers(pCommandBuffer) - - check(VK10.vkQueueSubmit(queue.get, submitInfo, fence.get), "Failed to submit command buffer to queue") - fence.block().destroy() - - val output = for i <- bufferActions.indices if bufferActions(i) == BufferAction.LoadFrom yield - val fence = Buffer.copyBuffer(buffers(i), stagingBuffer, buffers(i).size, commandPool) - val outBuffer = BufferUtils.createByteBuffer(buffers(i).size) - fence.block().destroy() - Buffer.copyBuffer(stagingBuffer, outBuffer, outBuffer.remaining()) - outBuffer - - stagingBuffer.destroy() - output - - def destroy(): Unit = - commandPool.freeCommandBuffer(commandBuffer) - descriptorSets.foreach(_.destroy()) - buffers.foreach(_.destroy()) - - protected def setupBuffers(): (Seq[DescriptorSet], Seq[Buffer]) - - protected def recordCommandBuffer(commandBuffer: VkCommandBuffer): Unit - - protected def getBiggestTransportData: Int diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala deleted file mode 100644 index e287a04b..00000000 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/MapExecutor.scala +++ /dev/null @@ -1,54 +0,0 @@ -package io.computenode.cyfra.vulkan.executor - -import io.computenode.cyfra.vulkan.VulkanContext -import io.computenode.cyfra.vulkan.compute.* -import io.computenode.cyfra.vulkan.memory.{Buffer, DescriptorSet} -import io.computenode.cyfra.vulkan.util.Util.pushStack -import org.lwjgl.util.vma.Vma.* -import org.lwjgl.vulkan.* -import org.lwjgl.vulkan.VK10.* - -import scala.collection.mutable - -/** @author - * MarconZet Created 15.04.2020 - */ -private[cyfra] class MapExecutor(dataLength: Int, bufferActions: Seq[BufferAction], computePipeline: ComputePipeline, context: VulkanContext) - extends AbstractExecutor(dataLength, bufferActions, context): - private lazy val shader: Shader = computePipeline.computeShader - - protected def getBiggestTransportData: Int = shader.layoutInfo.sets - .flatMap(_.bindings) - .collect { case Binding(_, InputBufferSize(n)) => - n - } - .max - - protected def setupBuffers(): (Seq[DescriptorSet], Seq[Buffer]) = pushStack: stack => - val bindings = shader.layoutInfo.sets.flatMap(_.bindings) - val buffers = bindings.zipWithIndex.map { case (binding, i) => - val bufferSize = binding.size match - case InputBufferSize(n) => n * dataLength - case UniformSize(n) => n - new Buffer(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | bufferActions(i).action, 0, VMA_MEMORY_USAGE_GPU_ONLY, allocator) - } - - val bufferDeque = mutable.ArrayDeque.from(buffers) - val descriptorSetLayouts = computePipeline.descriptorSetLayouts - val descriptorSets = for i <- descriptorSetLayouts.indices yield - val descriptorSet = new DescriptorSet(device, descriptorSetLayouts(i)._1, descriptorSetLayouts(i)._2.bindings, descriptorPool) - val size = descriptorSetLayouts(i)._2.bindings.size - descriptorSet.update(bufferDeque.take(size).toSeq) - bufferDeque.drop(size) - descriptorSet - (descriptorSets, buffers) - - protected def recordCommandBuffer(commandBuffer: VkCommandBuffer): Unit = - pushStack: stack => - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get) - - val pDescriptorSets = stack.longs(descriptorSets.map(_.get)*) - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.pipelineLayout, 0, pDescriptorSets, null) - - val workgroup = shader.workgroupDimensions - vkCmdDispatch(commandBuffer, dataLength / workgroup.x(), 1 / workgroup.y(), 1 / workgroup.z()) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala index 1edacb32..63c61bc2 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala @@ -21,9 +21,9 @@ import java.nio.ByteBuffer * MarconZet Created 15.04.2020 */ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, context: VulkanContext): - private val device: Device = context.device + import context.given + private val queue: Queue = context.computeQueue - private val allocator: Allocator = context.allocator private val descriptorPool: DescriptorPool = context.descriptorPool private val commandPool: CommandPool = context.commandPool @@ -31,7 +31,7 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont val pipelines = computeSequence.sequence.collect: case Compute(pipeline, _) => pipeline - val rawSets = pipelines.map(_.computeShader.layoutInfo.sets) + val rawSets = pipelines.map(_.layoutInfo.sets) val numbered = rawSets.flatten.zipWithIndex val numberedSets = rawSets .foldLeft((numbered, Seq.empty[Seq[(LayoutSet, Int)]])) { case ((remaining, acc), sequence) => @@ -63,7 +63,7 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont } .distinctBy(_._1) .map { case (set, (id, layout)) => - (set, new DescriptorSet(device, id, layout.bindings, descriptorPool)) + (set, new DescriptorSet(id, layout.bindings, descriptorPool)) } .toMap @@ -71,7 +71,7 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont private val descriptorSets = pipelineToDescriptorSets.toSeq.flatMap(_._2).distinctBy(_.get) - private def recordCommandBuffer(dataLength: Int): VkCommandBuffer = pushStack: stack => + private def recordCommandBuffer() = pushStack: stack => val pipelinesHasDependencies = computeSequence.dependencies.map(_.to).toSet val commandBuffer = commandPool.createCommandBuffer() @@ -104,14 +104,13 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont val pDescriptorSets = stack.longs(pipelineToDescriptorSets(pipeline).map(_.get)*) vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.pipelineLayout, 0, pDescriptorSets, null) - val workgroup = pipeline.computeShader.workgroupDimensions - vkCmdDispatch(commandBuffer, dataLength / workgroup.x, 1 / workgroup.y, 1 / workgroup.z) // TODO this can be changed to indirect dispatch, this would unlock options like filters + vkCmdDispatch(commandBuffer, 8, 1, 1) } check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") commandBuffer - private def createBuffers(dataLength: Int): Map[DescriptorSet, Seq[Buffer]] = + private def createBuffers(): Map[DescriptorSet, Seq[Buffer]] = val setToActions = computeSequence.sequence .collect { case Compute(pipeline, bufferActions) => @@ -132,9 +131,9 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont val buffers = set.bindings.zip(actions).map { case (binding, action) => binding.size match case InputBufferSize(elemSize) => - new Buffer(elemSize * dataLength, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | action.action, 0, VMA_MEMORY_USAGE_GPU_ONLY, allocator) + new Buffer.DeviceBuffer(elemSize * 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | action.action) case UniformSize(size) => - new Buffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | action.action, 0, VMA_MEMORY_USAGE_GPU_ONLY, allocator) + new Buffer.DeviceBuffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | action.action) } set.update(buffers) (set, buffers), @@ -143,9 +142,9 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont setToBuffers - def execute(inputs: Seq[ByteBuffer], dataLength: Int): Seq[ByteBuffer] = pushStack: stack => + def execute(inputs: Seq[ByteBuffer]): Seq[ByteBuffer] = pushStack: stack => timed("Vulkan full execute"): - val setToBuffers = createBuffers(dataLength) + val setToBuffers = createBuffers() def buffersWithAction(bufferAction: BufferAction): Seq[Buffer] = computeSequence.sequence.collect { case x: Compute => @@ -158,21 +157,15 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont }.flatten val stagingBuffer = - new Buffer( - inputs.map(_.remaining()).max, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - VMA_MEMORY_USAGE_UNKNOWN, - allocator, - ) + new Buffer.HostBuffer(inputs.map(_.remaining()).max, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) buffersWithAction(BufferAction.LoadTo).zipWithIndex.foreach { case (buffer, i) => Buffer.copyBuffer(inputs(i), stagingBuffer, buffer.size) Buffer.copyBuffer(stagingBuffer, buffer, buffer.size, commandPool).block().destroy() } - val fence = new Fence(device) - val commandBuffer = recordCommandBuffer(dataLength) + val fence = new Fence() + val commandBuffer = recordCommandBuffer() val pCommandBuffer = stack.callocPointer(1).put(0, commandBuffer) val submitInfo = VkSubmitInfo .calloc(stack) @@ -192,7 +185,6 @@ private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, cont stagingBuffer.destroy() commandPool.freeCommandBuffer(commandBuffer) - setToBuffers.keys.foreach(_.update(Seq.empty)) setToBuffers.flatMap(_._2).foreach(_.destroy()) output @@ -206,7 +198,7 @@ object SequenceExecutor: private[cyfra] sealed trait ComputationStep case class Compute(pipeline: ComputePipeline, bufferActions: Map[LayoutLocation, BufferAction]) extends ComputationStep: def pumpLayoutLocations: Seq[Seq[BufferAction]] = - pipeline.computeShader.layoutInfo.sets + pipeline.layoutInfo.sets .map(x => x.bindings.map(y => (x.id, y.id)).map(x => bufferActions.getOrElse(LayoutLocation.apply.tupled(x), BufferAction.DoNothing))) case class LayoutLocation(set: Int, binding: Int) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala index 53b364a7..60ecb48a 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala @@ -14,13 +14,13 @@ import java.nio.ByteBuffer /** @author * MarconZet Created 11.05.2019 */ -private[cyfra] class Buffer(val size: Int, val usage: Int, flags: Int, memUsage: Int, val allocator: Allocator) extends VulkanObjectHandle: +private[cyfra] sealed class Buffer private (val size: Int, usage: Int, flags: Int)(using allocator: Allocator) extends VulkanObjectHandle: val (handle, allocation) = pushStack: stack => val bufferInfo = VkBufferCreateInfo .calloc(stack) .sType$Default() - .pNext(NULL) + .pNext(0) .size(size) .usage(usage) .flags(0) @@ -28,7 +28,7 @@ private[cyfra] class Buffer(val size: Int, val usage: Int, flags: Int, memUsage: val allocInfo = VmaAllocationCreateInfo .calloc(stack) - .usage(memUsage) + .usage(VMA_MEMORY_USAGE_UNKNOWN) .requiredFlags(flags) val pBuffer = stack.callocLong(1) @@ -36,43 +36,42 @@ private[cyfra] class Buffer(val size: Int, val usage: Int, flags: Int, memUsage: check(vmaCreateBuffer(allocator.get, bufferInfo, allocInfo, pBuffer, pAllocation, null), "Failed to create buffer") (pBuffer.get(), pAllocation.get()) - def get(dst: Array[Byte]): Unit = - val len = Math.min(dst.length, size) - val byteBuffer = memCalloc(len) - Buffer.copyBuffer(this, byteBuffer, len) - byteBuffer.get(dst) - memFree(byteBuffer) - protected def close(): Unit = vmaDestroyBuffer(allocator.get, handle, allocation) object Buffer: - def copyBuffer(src: ByteBuffer, dst: Buffer, bytes: Long): Unit = - pushStack: stack => - val pData = stack.callocPointer(1) - check(vmaMapMemory(dst.allocator.get, dst.allocation, pData), "Failed to map destination buffer memory") - val data = pData.get() - memCopy(memAddress(src), data, bytes) - vmaFlushAllocation(dst.allocator.get, dst.allocation, 0, bytes) - vmaUnmapMemory(dst.allocator.get, dst.allocation) + private[cyfra] class DeviceBuffer(size: Int, usage: Int)(using allocator: Allocator) + extends Buffer(size, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)(using allocator) - def copyBuffer(src: Buffer, dst: ByteBuffer, bytes: Long): Unit = - pushStack: stack => + private[cyfra] class HostBuffer(size: Int, usage: Int)(using allocator: Allocator) + extends Buffer(size, usage, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)(using allocator): + def mapped(f: ByteBuffer => Unit): Unit = mappedImpl(f, flush = true) + def mappedNoFlush(f: ByteBuffer => Unit): Unit = mappedImpl(f, flush = false) + + private def mappedImpl(f: ByteBuffer => Unit, flush: Boolean): Unit = pushStack: stack => val pData = stack.callocPointer(1) - check(vmaMapMemory(src.allocator.get, src.allocation, pData), "Failed to map destination buffer memory") + check(vmaMapMemory(this.allocator.get, this.allocation, pData), "Failed to map buffer to memory") val data = pData.get() - memCopy(data, memAddress(dst), bytes) - vmaUnmapMemory(src.allocator.get, src.allocation) + val bb = memByteBuffer(data, size) + try f(bb) + finally + if flush then vmaFlushAllocation(this.allocator.get, this.allocation, 0, size) + vmaUnmapMemory(this.allocator.get, this.allocation) - def copyBuffer(src: Buffer, dst: Buffer, bytes: Long, commandPool: CommandPool): Fence = - pushStack: stack => - val commandBuffer = commandPool.beginSingleTimeCommands() + def copyBuffer(src: ByteBuffer, dst: HostBuffer, bytes: Long): Unit = + dst.mapped: destination => + memCopy(memAddress(src), memAddress(destination), bytes) - val copyRegion = VkBufferCopy - .calloc(1, stack) - .srcOffset(0) - .dstOffset(0) - .size(bytes) - vkCmdCopyBuffer(commandBuffer, src.get, dst.get, copyRegion) + def copyBuffer(src: HostBuffer, dst: ByteBuffer, bytes: Long): Unit = + src.mappedNoFlush: source => + memCopy(memAddress(source), memAddress(dst), bytes) - commandPool.endSingleTimeCommands(commandBuffer) + def copyBuffer(src: Buffer, dst: Buffer, bytes: Long, commandPool: CommandPool): Fence = + commandPool.executeCommand: commandBuffer => + pushStack: stack => + val copyRegion = VkBufferCopy + .calloc(1, stack) + .srcOffset(0) + .dstOffset(0) + .size(bytes) + vkCmdCopyBuffer(commandBuffer, src.get, dst.get, copyRegion) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala index f6ceced3..4cb57928 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala @@ -12,12 +12,12 @@ import org.lwjgl.vulkan.{VkDescriptorPoolCreateInfo, VkDescriptorPoolSize} */ object DescriptorPool: val MAX_SETS = 100 -private[cyfra] class DescriptorPool(device: Device) extends VulkanObjectHandle: +private[cyfra] class DescriptorPool(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => val descriptorPoolSize = VkDescriptorPoolSize.calloc(1, stack) descriptorPoolSize .get(0) - .`type`(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) + .`type`(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) // TODO this is sus when using with uniform buffers .descriptorCount(2 * MAX_SETS) val descriptorPoolCreateInfo = VkDescriptorPoolCreateInfo diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala index e9f49d4d..52e001a0 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala @@ -1,6 +1,6 @@ package io.computenode.cyfra.vulkan.memory -import io.computenode.cyfra.vulkan.compute.Binding +import io.computenode.cyfra.vulkan.compute.{Binding, InputBufferSize, LayoutSet, UniformSize} import io.computenode.cyfra.vulkan.core.Device import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObjectHandle @@ -10,7 +10,7 @@ import org.lwjgl.vulkan.{VkDescriptorBufferInfo, VkDescriptorSetAllocateInfo, Vk /** @author * MarconZet Created 15.04.2020 */ -private[cyfra] class DescriptorSet(device: Device, descriptorSetLayout: Long, val bindings: Seq[Binding], descriptorPool: DescriptorPool) +private[cyfra] class DescriptorSet(descriptorSetLayout: Long, val bindings: Seq[Binding], descriptorPool: DescriptorPool)(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => @@ -26,25 +26,27 @@ private[cyfra] class DescriptorSet(device: Device, descriptorSetLayout: Long, va pDescriptorSet.get() def update(buffers: Seq[Buffer]): Unit = pushStack: stack => + assert(buffers.length == bindings.length, s"Number of buffers (${buffers.length}) does not match number of bindings (${bindings.length})") val writeDescriptorSet = VkWriteDescriptorSet.calloc(buffers.length, stack) - buffers.indices foreach { i => + buffers.zip(bindings).foreach { case (buffer, binding) => val descriptorBufferInfo = VkDescriptorBufferInfo .calloc(1, stack) - .buffer(buffers(i).get) + .buffer(buffer.get) .offset(0) .range(VK_WHOLE_SIZE) - val descriptorType = buffers(i).usage match - case storage if (storage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0 => VK_DESCRIPTOR_TYPE_STORAGE_BUFFER - case uniform if (uniform & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 0 => VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER + val descriptorType = binding.size match + case InputBufferSize(elemSize) => VK_DESCRIPTOR_TYPE_STORAGE_BUFFER + case UniformSize(size) => VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER writeDescriptorSet - .get(i) + .get() .sType$Default() .dstSet(handle) - .dstBinding(i) + .dstBinding(binding.id) .descriptorCount(1) .descriptorType(descriptorType) .pBufferInfo(descriptorBufferInfo) } + writeDescriptorSet.rewind() vkUpdateDescriptorSets(device.get, writeDescriptorSet, null) override protected def close(): Unit = diff --git a/cyfra-e2e-test/src/test/resources/compileAll.ps1 b/cyfra-vulkan/src/test/resources/compileAll.ps1 similarity index 100% rename from cyfra-e2e-test/src/test/resources/compileAll.ps1 rename to cyfra-vulkan/src/test/resources/compileAll.ps1 diff --git a/cyfra-e2e-test/src/test/resources/compileAll.sh b/cyfra-vulkan/src/test/resources/compileAll.sh similarity index 100% rename from cyfra-e2e-test/src/test/resources/compileAll.sh rename to cyfra-vulkan/src/test/resources/compileAll.sh diff --git a/cyfra-e2e-test/src/test/resources/copy_test.comp b/cyfra-vulkan/src/test/resources/copy_test.comp similarity index 100% rename from cyfra-e2e-test/src/test/resources/copy_test.comp rename to cyfra-vulkan/src/test/resources/copy_test.comp diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/vulkan/SequenceExecutorTest.scala b/cyfra-vulkan/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala similarity index 67% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/vulkan/SequenceExecutorTest.scala rename to cyfra-vulkan/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala index 87fa10cb..14ab3e46 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/vulkan/SequenceExecutorTest.scala +++ b/cyfra-vulkan/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala @@ -1,22 +1,23 @@ -package io.computenode.cyfra.e2e.vulkan +package io.computenode.cyfra.vulkan -import io.computenode.cyfra.vulkan.compute.{Binding, ComputePipeline, InputBufferSize, LayoutInfo, LayoutSet, Shader} +import io.computenode.cyfra.vulkan.VulkanContext +import io.computenode.cyfra.vulkan.compute.* +import io.computenode.cyfra.vulkan.core.Device import io.computenode.cyfra.vulkan.executor.BufferAction.{LoadFrom, LoadTo} import io.computenode.cyfra.vulkan.executor.SequenceExecutor import io.computenode.cyfra.vulkan.executor.SequenceExecutor.{ComputationSequence, Compute, Dependency, LayoutLocation} -import io.computenode.cyfra.vulkan.VulkanContext import munit.FunSuite import org.lwjgl.BufferUtils class SequenceExecutorTest extends FunSuite: - private val vulkanContext = VulkanContext() + val vulkanContext = VulkanContext() + import vulkanContext.given test("Memory barrier"): - val code = Shader.loadShader("copy_test.spv") + val code = ComputePipeline.loadShader("copy_test.spv").get val layout = LayoutInfo(Seq(LayoutSet(0, Seq(Binding(0, InputBufferSize(4)))), LayoutSet(1, Seq(Binding(0, InputBufferSize(4)))))) - val shader = new Shader(code, new org.joml.Vector3i(128, 1, 1), layout, "main", vulkanContext.device) - val copy1 = new ComputePipeline(shader, vulkanContext) - val copy2 = new ComputePipeline(shader, vulkanContext) + val copy1 = new ComputePipeline(code, "main", layout) + val copy2 = new ComputePipeline(code, "main", layout) val sequence = ComputationSequence( @@ -28,7 +29,7 @@ class SequenceExecutorTest extends FunSuite: val buffer = BufferUtils.createByteBuffer(input.length * 4) input.foreach(buffer.putInt) buffer.flip() - val res = sequenceExecutor.execute(Seq(buffer), input.length) + val res = sequenceExecutor.execute(Seq(buffer)) val output = input.map(_ => res.head.getInt) assertEquals(input.map(_ + 20000).toList, output.toList) From b7082cdf2e0e1a0af72027eed8edfb5e056854c8 Mon Sep 17 00:00:00 2001 From: MarconZet <25779550+MarconZet@users.noreply.github.com> Date: Sat, 26 Jul 2025 00:47:16 +0200 Subject: [PATCH 10/59] Basic Vulkan runtime (#61) --- README.md | 23 +- build.sbt | 7 +- .../computenode/cyfra/core/Allocation.scala | 11 +- .../computenode/cyfra/core/CyfraRuntime.scala | 2 +- .../cyfra/core/GBufferRegion.scala | 42 ++- .../computenode/cyfra/core/GExecution.scala | 45 ++-- .../io/computenode/cyfra/core/GProgram.scala | 60 ++--- .../computenode/cyfra/core/GioProgram.scala | 19 ++ .../computenode/cyfra/core/SpirvProgram.scala | 61 +++++ .../cyfra/core/layout/Layout.scala | 3 - .../cyfra/core/layout/LayoutBinding.scala | 34 +++ .../cyfra/dsl/binding/GBinding.scala | 27 +- .../cyfra/dsl/binding/GBuffer.scala | 13 - .../cyfra/dsl/binding/GUniform.scala | 19 -- cyfra-examples/src/main/resources/addOne.comp | 48 ++++ .../src/main}/resources/compileAll.ps1 | 0 .../src/main}/resources/compileAll.sh | 2 +- cyfra-examples/src/main/resources/emit.comp | 23 ++ cyfra-examples/src/main/resources/filter.comp | 20 ++ .../cyfra/samples/TestingStuff.scala | 139 +++++++++- .../cyfra/runtime/ExecutionHandler.scala | 255 +++++++++++++++++- .../cyfra/runtime/VkAllocation.scala | 96 ++++++- .../computenode/cyfra/runtime/VkBuffer.scala | 23 ++ .../cyfra/runtime/VkCyfraRuntime.scala | 27 +- .../computenode/cyfra/runtime/VkShader.scala | 42 +++ .../computenode/cyfra/runtime/VkUniform.scala | 21 ++ .../vulkan/compute/ComputePipeline.scala | 51 ++-- .../cyfra/vulkan/compute/LayoutInfo.scala | 12 - .../cyfra/vulkan/core/DebugCallback.scala | 2 +- .../cyfra/vulkan/core/Instance.scala | 18 +- .../cyfra/vulkan/executor/BufferAction.scala | 17 -- .../vulkan/executor/SequenceExecutor.scala | 206 -------------- .../cyfra/vulkan/memory/Buffer.scala | 16 +- .../cyfra/vulkan/memory/DescriptorPool.scala | 15 +- .../cyfra/vulkan/memory/DescriptorSet.scala | 17 +- .../src/test/resources/copy_test.comp | 15 -- .../cyfra/vulkan/SequenceExecutorTest.scala | 35 --- flake.lock | 61 +++++ flake.nix | 33 +++ 39 files changed, 1066 insertions(+), 494 deletions(-) create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/GioProgram.scala create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala create mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutBinding.scala delete mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBuffer.scala delete mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GUniform.scala create mode 100644 cyfra-examples/src/main/resources/addOne.comp rename {cyfra-vulkan/src/test => cyfra-examples/src/main}/resources/compileAll.ps1 (100%) rename {cyfra-vulkan/src/test => cyfra-examples/src/main}/resources/compileAll.sh (85%) create mode 100644 cyfra-examples/src/main/resources/emit.comp create mode 100644 cyfra-examples/src/main/resources/filter.comp create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala delete mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/LayoutInfo.scala delete mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/BufferAction.scala delete mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala delete mode 100644 cyfra-vulkan/src/test/resources/copy_test.comp delete mode 100644 cyfra-vulkan/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/README.md b/README.md index c4488e56..e59b4dcb 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,10 @@ Library provides a way to compile Scala 3 DSL to SPIR-V and to run it with Vulkan runtime on GPUs. It is multiplatform. It works on: - - Linux, Windows, and Mac (for Mac requires installation of moltenvk). - - Any dedicated or integrated GPUs that support Vulkan. In practice, it means almost all moderately modern devices from most manufacturers including Nvidia, AMD, Intel, Apple. + +- Linux, Windows, and Mac (for Mac requires installation of moltenvk). +- Any dedicated or integrated GPUs that support Vulkan. In practice, it means almost all moderately modern devices from + most manufacturers including Nvidia, AMD, Intel, Apple. Library is in an early stage - alpha release and proper documentation are coming. @@ -15,12 +17,15 @@ Included Foton library provides a clean and fun way to animate functions and ray ## Examples ### Ray traced animation + ![output](https://github.com/user-attachments/assets/3eac9f7f-72df-4a5d-b768-9117d651c78d) [code](https://github.com/ComputeNode/cyfra/blob/50aecea/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedRaytrace.scala) -(this is API usage, to see ray tracing implementation look at [RtRenderer](https://github.com/ComputeNode/cyfra/blob/50aecea132188776021afe0b407817665676a021/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala)) +(this is API usage, to see ray tracing implementation look +at [RtRenderer](https://github.com/ComputeNode/cyfra/blob/50aecea132188776021afe0b407817665676a021/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala)) ### Animated Julia set + [code](https://github.com/ComputeNode/cyfra/blob/50aecea132188776021afe0b407817665676a021/cyfra-examples/src/main/scala/io/computenode/samples/cyfra/foton/AnimatedJulia.scala) @@ -28,9 +33,11 @@ Included Foton library provides a clean and fun way to animate functions and ray ## Animation features examples ### Custom animated functions + ### Animated ray traced scene + ## Coding features examples @@ -48,9 +55,15 @@ Included Foton library provides a clean and fun way to animate functions and ray ## Development -To enable validation layers for vulkan, you need to install vulkan SKD. After installing, set the following VM options: +To enable validation layers for vulkan, you need to install vulkan SKD. After installing, set the following VM option: + ``` --Dorg.lwjgl.vulkan.libname=libvulkan.1.dylib -Dio.computenode.cyfra.vulkan.validation=true +``` + +If you are on MacOs, then also add: + +``` +-Dorg.lwjgl.vulkan.libname=libvulkan.1.dylib -Djava.library.path=$VULKAN_SDK/lib ``` \ No newline at end of file diff --git a/build.sbt b/build.sbt index 44acec5f..35a46c2c 100644 --- a/build.sbt +++ b/build.sbt @@ -1,8 +1,8 @@ ThisBuild / organization := "com.computenode.cyfra" ThisBuild / scalaVersion := "3.6.4" -ThisBuild / version := "0.1.0-SNAPSHOT" +ThisBuild / version := "0.2.0-SNAPSHOT" -val lwjglVersion = "3.3.6" +val lwjglVersion = "3.4.0-SNAPSHOT" val jomlVersion = "1.10.0" lazy val osName = System.getProperty("os.name").toLowerCase @@ -37,8 +37,9 @@ lazy val vulkanNatives = lazy val commonSettings = Seq( scalacOptions ++= Seq("-feature", "-deprecation", "-unchecked", "-language:implicitConversions"), + resolvers += "maven snapshots" at "https://central.sonatype.com/repository/maven-snapshots/", libraryDependencies ++= Seq( - "dev.zio" % "izumi-reflect_3" % "2.3.10", + "dev.zio" % "izumi-reflect_3" % "3.0.5", "com.lihaoyi" % "pprint_3" % "0.9.0", "com.diogonunes" % "JColor" % "5.5.1", "org.lwjgl" % "lwjgl" % lwjglVersion, diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala index 194b3a2f..783efaff 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala @@ -1,6 +1,6 @@ package io.computenode.cyfra.core -import io.computenode.cyfra.core.layout.{Layout, LayoutStruct} +import io.computenode.cyfra.core.layout.{Layout, LayoutBinding} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} @@ -11,14 +11,15 @@ import java.nio.ByteBuffer trait Allocation: extension (buffer: GBinding[?]) - def read(bb: ByteBuffer, offset: Int = 0, length: Int = -1): Unit + def read(bb: ByteBuffer, offset: Int = 0, size: Int = -1): Unit - def write(bb: ByteBuffer, offset: Int = 0, length: Int = -1): Unit + def write(bb: ByteBuffer, offset: Int = 0, size: Int = -1): Unit - extension [Params, L <: Layout, RL <: Layout: LayoutStruct](execution: GExecution[Params, L, RL]) def execute(params: Params, layout: L): RL + extension [Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding](execution: GExecution[Params, EL, RL]) + def execute(params: Params, layout: EL): RL extension (buffers: GBuffer.type) - def apply[T <: Value: {Tag, FromExpr}](size: Int): GBuffer[T] + def apply[T <: Value: {Tag, FromExpr}](length: Int): GBuffer[T] def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/CyfraRuntime.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/CyfraRuntime.scala index a7c029e4..a38c620c 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/CyfraRuntime.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/CyfraRuntime.scala @@ -4,4 +4,4 @@ import io.computenode.cyfra.core.Allocation trait CyfraRuntime: - def allocation(): Allocation + def withAllocation(f: Allocation => Unit): Unit diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala index 2aec9159..cfd3ad8d 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala @@ -1,8 +1,8 @@ package io.computenode.cyfra.core import io.computenode.cyfra.core.Allocation -import io.computenode.cyfra.core.GProgram.BufferSizeSpec -import io.computenode.cyfra.core.layout.{Layout, LayoutStruct} +import io.computenode.cyfra.core.GProgram.BufferLengthSpec +import io.computenode.cyfra.core.layout.{Layout, LayoutBinding} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.GBuffer @@ -10,38 +10,34 @@ import izumi.reflect.Tag import java.nio.ByteBuffer -sealed trait GBufferRegion[ReqAlloc <: Layout: LayoutStruct, ResAlloc <: Layout: LayoutStruct]: - val initAlloc: ReqAlloc +sealed trait GBufferRegion[ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding] object GBufferRegion: - def allocate[Alloc <: Layout: LayoutStruct]: GBufferRegion[Alloc, Alloc] = - AllocRegion(summon[LayoutStruct[Alloc]].layoutRef) + def allocate[Alloc <: Layout: LayoutBinding]: GBufferRegion[Alloc, Alloc] = AllocRegion() - case class AllocRegion[Alloc <: Layout: LayoutStruct](l: Alloc) extends GBufferRegion[Alloc, Alloc]: - val initAlloc: Alloc = l + case class AllocRegion[Alloc <: Layout: LayoutBinding]() extends GBufferRegion[Alloc, Alloc] - case class MapRegion[ReqAlloc <: Layout: LayoutStruct, BodyAlloc <: Layout: LayoutStruct, ResAlloc <: Layout: LayoutStruct]( + case class MapRegion[ReqAlloc <: Layout: LayoutBinding, BodyAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding]( reqRegion: GBufferRegion[ReqAlloc, BodyAlloc], f: Allocation => BodyAlloc => ResAlloc, - ) extends GBufferRegion[ReqAlloc, ResAlloc]: - val initAlloc: ReqAlloc = reqRegion.initAlloc + ) extends GBufferRegion[ReqAlloc, ResAlloc] - extension [ReqAlloc <: Layout: LayoutStruct, ResAlloc <: Layout: LayoutStruct](region: GBufferRegion[ReqAlloc, ResAlloc]) - def map[NewAlloc <: Layout: LayoutStruct](f: Allocation ?=> ResAlloc => NewAlloc): GBufferRegion[ReqAlloc, NewAlloc] = + extension [ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding](region: GBufferRegion[ReqAlloc, ResAlloc]) + def map[NewAlloc <: Layout: LayoutBinding](f: Allocation ?=> ResAlloc => NewAlloc): GBufferRegion[ReqAlloc, NewAlloc] = MapRegion(region, (alloc: Allocation) => (resAlloc: ResAlloc) => f(using alloc)(resAlloc)) def runUnsafe(init: Allocation ?=> ReqAlloc, onDone: Allocation ?=> ResAlloc => Unit)(using cyfraRuntime: CyfraRuntime): Unit = - val allocation = cyfraRuntime.allocation() - init(using allocation) + cyfraRuntime.withAllocation: allocation => - // noinspection ScalaRedundantCast - val steps: Seq[Allocation => Layout => Layout] = Seq.unfold(region: GBufferRegion[?, ?]): - case _: AllocRegion[?] => None - case MapRegion(req, f) => - Some((f.asInstanceOf[Allocation => Layout => Layout], req)) + // noinspection ScalaRedundantCast + val steps: Seq[Allocation => Layout => Layout] = Seq.unfold(region: GBufferRegion[?, ?]): + case _: AllocRegion[?] => None + case MapRegion(req, f) => + Some((f.asInstanceOf[Allocation => Layout => Layout], req)) - val bodyAlloc = steps.foldLeft[Layout](region.initAlloc): (acc, step) => - step(allocation)(acc) + val initAlloc = init(using allocation) + val bodyAlloc = steps.foldLeft[Layout](initAlloc): (acc, step) => + step(allocation)(acc) - onDone(using allocation)(bodyAlloc.asInstanceOf[ResAlloc]) + onDone(using allocation)(bodyAlloc.asInstanceOf[ResAlloc]) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala index 0caabec6..22418ead 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala @@ -10,15 +10,18 @@ import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.UniformStructRef import izumi.reflect.Tag import GExecution.* -trait GExecution[-Params, ExecLayout <: Layout, +ResLayout <: Layout]: +trait GExecution[-Params, ExecLayout <: Layout: LayoutBinding, ResLayout <: Layout: LayoutBinding]: - def flatMap[NRL <: Layout, NP <: Params](f: ResLayout => GExecution[NP, ExecLayout, NRL]): GExecution[NP, ExecLayout, NRL] = + def layoutBinding: LayoutBinding[ExecLayout] = summon[LayoutBinding[ExecLayout]] + def resLayoutBinding: LayoutBinding[ResLayout] = summon[LayoutBinding[ResLayout]] + + def flatMap[NRL <: Layout: LayoutBinding, NP <: Params](f: ResLayout => GExecution[NP, ExecLayout, NRL]): GExecution[NP, ExecLayout, NRL] = FlatMap(this, (p, r) => f(r)) - def map[NRL <: Layout](f: ResLayout => NRL): GExecution[Params, ExecLayout, NRL] = + def map[NRL <: Layout: LayoutBinding](f: ResLayout => NRL): GExecution[Params, ExecLayout, NRL] = Map(this, f, identity, identity) - def contramap[NL <: Layout](f: NL => ExecLayout): GExecution[Params, NL, ResLayout] = + def contramap[NEL <: Layout: LayoutBinding](f: NEL => ExecLayout): GExecution[Params, NEL, ResLayout] = Map(this, identity, f, identity) def contramapParams[NP](f: NP => Params): GExecution[NP, ExecLayout, ResLayout] = @@ -32,31 +35,33 @@ trait GExecution[-Params, ExecLayout <: Layout, +ResLayout <: Layout]: object GExecution: - def apply[Params, L <: Layout]() = - Pure[Params, L, L]() + def apply[Params, L <: Layout: LayoutBinding]() = + Pure[Params, L]() - def forParams[Params, L <: Layout, RL <: Layout](f: Params => GExecution[Params, L, RL]): GExecution[Params, L, RL] = - FlatMap[Params, L, RL, RL](Pure[Params, L, RL](), (params: Params, _: RL) => f(params)) + def forParams[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding]( + f: Params => GExecution[Params, EL, RL], + ): GExecution[Params, EL, RL] = + FlatMap[Params, EL, EL, RL](Pure[Params, EL](), (params: Params, _: EL) => f(params)) - case class Pure[Params, L <: Layout, RL <: Layout]() extends GExecution[Params, L, RL] + case class Pure[Params, L <: Layout: LayoutBinding]() extends GExecution[Params, L, L] - case class FlatMap[Params, L <: Layout, RL <: Layout, NRL <: Layout]( - execution: GExecution[Params, L, RL], - f: (Params, RL) => GExecution[Params, L, NRL], - ) extends GExecution[Params, L, NRL] + case class FlatMap[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding, NRL <: Layout: LayoutBinding]( + execution: GExecution[Params, EL, RL], + f: (Params, RL) => GExecution[Params, EL, NRL], + ) extends GExecution[Params, EL, NRL] - case class Map[P, NP, L <: Layout, NL <: Layout, RL <: Layout, NRL <: Layout]( - execution: GExecution[P, L, RL], + case class Map[P, NP, EL <: Layout: LayoutBinding, NEL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding, NRL <: Layout: LayoutBinding]( + execution: GExecution[P, EL, RL], mapResult: RL => NRL, - contramapLayout: NL => L, + contramapLayout: NEL => EL, contramapParams: NP => P, - ) extends GExecution[NP, NL, NRL]: + ) extends GExecution[NP, NEL, NRL]: - override def map[NNRL <: Layout](f: NRL => NNRL): GExecution[NP, NL, NNRL] = + override def map[NNRL <: Layout: LayoutBinding](f: NRL => NNRL): GExecution[NP, NEL, NNRL] = Map(execution, mapResult andThen f, contramapLayout, contramapParams) - override def contramapParams[NNP](f: NNP => NP): GExecution[NNP, NL, NRL] = + override def contramapParams[NNP](f: NNP => NP): GExecution[NNP, NEL, NRL] = Map(execution, mapResult, contramapLayout, f andThen contramapParams) - override def contramap[NNL <: Layout](f: NNL => NL): GExecution[NP, NNL, NRL] = + override def contramap[NNL <: Layout: LayoutBinding](f: NNL => NEL): GExecution[NP, NNL, NRL] = Map(execution, mapResult, f andThen contramapLayout, contramapParams) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala index 77586f5e..da5407df 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala @@ -1,70 +1,48 @@ package io.computenode.cyfra.core -import io.computenode.cyfra.core.layout.LayoutStruct +import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} import io.computenode.cyfra.dsl.gio.GIO -import io.computenode.cyfra.core.layout.Layout import java.nio.ByteBuffer import GProgram.* import io.computenode.cyfra.dsl.{Expression, Value} -import io.computenode.cyfra.dsl.Value.{FromExpr, Int32} +import io.computenode.cyfra.dsl.Value.{FromExpr, GBoolean, Int32} import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.struct.GStruct.Empty import izumi.reflect.Tag -sealed trait GProgram[Params, L <: Layout: LayoutStruct] extends GExecution[Params, L, L]: +trait GProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}] extends GExecution[Params, L, L]: val layout: InitProgramLayout => Params => L val dispatch: (L, Params) => ProgramDispatch val workgroupSize: WorkDimensions + private[cyfra] def cacheKey: String // TODO better type + def layoutStruct = summon[LayoutStruct[L]] object GProgram: - - class GioProgram[Params, L <: Layout: LayoutStruct]( - val body: L => GIO[?], - val layout: InitProgramLayout => Params => L, - val dispatch: (L, Params) => ProgramDispatch, - val workgroupSize: WorkDimensions, - ) extends GProgram[Params, L]: - private[cyfra] def layoutStruct: LayoutStruct[L] = summon[LayoutStruct[L]] - - class SpirvProgram[Params, L <: Layout: LayoutStruct]( - val code: ByteBuffer, - val layout: InitProgramLayout => Params => L, - val dispatch: (L, Params) => ProgramDispatch, - val workgroupSize: WorkDimensions, - ) extends GProgram[Params, L]: - private[cyfra] def layoutStruct: LayoutStruct[L] = summon[LayoutStruct[L]] - type WorkDimensions = (Int, Int, Int) sealed trait ProgramDispatch - case class DynamicDispatch[L <: Layout](buffer: GBinding[?], offset: Int) extends ProgramDispatch - case class StaticDispatch(size: WorkDimensions) extends ProgramDispatch - private[cyfra] case class BufferSizeSpec[T <: Value: {Tag, FromExpr}](size: Int) extends GBuffer[T] - - private[cyfra] case class ParamUniform[T <: GStruct[T]: {Tag, FromExpr}](value: T) extends GUniform[T] + def apply[Params, L <: Layout: {LayoutBinding, LayoutStruct}]( + layout: InitProgramLayout ?=> Params => L, + dispatch: (L, Params) => ProgramDispatch, + workgroupSize: WorkDimensions = (128, 1, 1), + )(body: L => GIO[?]): GProgram[Params, L] = + new GioProgram[Params, L](body, s => layout(using s), dispatch, workgroupSize) - private[cyfra] case class DynamicUniform[T <: GStruct[T]: {Tag, FromExpr}]() extends GUniform[T] + private[cyfra] class BufferLengthSpec[T <: Value: {Tag, FromExpr}](val length: Int) extends GBuffer[T]: + private[cyfra] def materialise()(using Allocation): GBuffer[T] = GBuffer.apply[T](length) + private[cyfra] class DynamicUniform[T <: GStruct[T]: {Tag, FromExpr}]() extends GUniform[T] trait InitProgramLayout: - extension (buffers: GBuffer.type) - def apply[T <: Value: {Tag, FromExpr}](size: Int): GBuffer[T] = - BufferSizeSpec[T](size) - - extension (uniforms: GUniform.type) - def apply[T <: GStruct[T]: {Tag, FromExpr}](value: T): GUniform[T] = - ParamUniform[T](value) + extension (_buffers: GBuffer.type) + def apply[T <: Value: {Tag, FromExpr}](length: Int): GBuffer[T] = + BufferLengthSpec[T](length) + extension (_uniforms: GUniform.type) def apply[T <: GStruct[T]: {Tag, FromExpr}](): GUniform[T] = DynamicUniform[T]() - - def apply[Params, L <: Layout: LayoutStruct]( - layout: InitProgramLayout ?=> Params => L, - dispatch: (L, Params) => ProgramDispatch, - workgroupSize: WorkDimensions = (128, 1, 1), - )(body: L => GIO[?]): GProgram[Params, L] = - new GioProgram[Params, L](body, s => layout(using s), dispatch, workgroupSize) + def apply[T <: GStruct[T]: {Tag, FromExpr}](value: T): GUniform[T] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GioProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GioProgram.scala new file mode 100644 index 00000000..d97f97b2 --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GioProgram.scala @@ -0,0 +1,19 @@ +package io.computenode.cyfra.core + +import io.computenode.cyfra.core.GProgram.* +import io.computenode.cyfra.core.layout.* +import io.computenode.cyfra.dsl.Value.GBoolean +import io.computenode.cyfra.dsl.gio.GIO +import izumi.reflect.Tag + +case class GioProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}]( + body: L => GIO[?], + layout: InitProgramLayout => Params => L, + dispatch: (L, Params) => ProgramDispatch, + workgroupSize: WorkDimensions, +) extends GProgram[Params, L]: + private[cyfra] def cacheKey: String = summon[LayoutStruct[L]].elementTypes match + case x if x.size == 12 => "addOne" + case x if x.contains(summon[Tag[GBoolean]]) && x.size == 3 => "filter" + case x if x.size == 3 => "emit" + case _ => ??? diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala new file mode 100644 index 00000000..c7b9f29a --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala @@ -0,0 +1,61 @@ +package io.computenode.cyfra.core + +import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} +import io.computenode.cyfra.core.GProgram.{InitProgramLayout, ProgramDispatch, WorkDimensions} +import io.computenode.cyfra.core.SpirvProgram.Operation.ReadWrite +import io.computenode.cyfra.core.SpirvProgram.{Binding, ShaderLayout} +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.{FromExpr, GBoolean} +import io.computenode.cyfra.dsl.binding.GBinding +import io.computenode.cyfra.dsl.gio.GIO +import izumi.reflect.Tag + +import java.io.File +import java.io.FileInputStream +import java.nio.ByteBuffer +import java.nio.channels.FileChannel +import java.util.Objects +import scala.util.Try +import scala.util.Using +import scala.util.chaining.* + +case class SpirvProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}] private ( + layout: InitProgramLayout => Params => L, + dispatch: (L, Params) => ProgramDispatch, + workgroupSize: WorkDimensions, + code: ByteBuffer, + entryPoint: String, + shaderBindings: L => ShaderLayout, + cacheKey: String, +) extends GProgram[Params, L] + +object SpirvProgram: + type ShaderLayout = Seq[Seq[Binding]] + case class Binding(binding: GBinding[?], operation: Operation) + enum Operation: + case Read + case Write + case ReadWrite + + def apply[Params, L <: Layout: {LayoutBinding, LayoutStruct}]( + path: String, + layout: InitProgramLayout ?=> Params => L, + dispatch: (L, Params) => ProgramDispatch, + ): SpirvProgram[Params, L] = + val code = loadShader(path).get + val workgroupSize = (128, 1, 1) // TODO Extract form shader + val main = "main" + val f: L => ShaderLayout = { case layout: Product => + layout.productIterator.zipWithIndex.map { case (binding: GBinding[?], i) => Binding(binding, ReadWrite) }.toSeq.pipe(Seq(_)) + } + val cacheKey = + val x = new File(path).getName + x.substring(0, x.lastIndexOf('.')) + new SpirvProgram[Params, L]((il: InitProgramLayout) => layout(using il), dispatch, workgroupSize, code, main, f, cacheKey) + + def loadShader(path: String, classLoader: ClassLoader = getClass.getClassLoader): Try[ByteBuffer] = + Using.Manager: use => + val file = new File(Objects.requireNonNull(classLoader.getResource(path)).getFile) + val fis = use(new FileInputStream(file)) + val fc = use(fis.getChannel) + fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/Layout.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/Layout.scala index d03d858f..37f369e8 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/Layout.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/Layout.scala @@ -1,6 +1,3 @@ package io.computenode.cyfra.core.layout -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.binding.GBuffer - trait Layout diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutBinding.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutBinding.scala new file mode 100644 index 00000000..5a7eaa52 --- /dev/null +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutBinding.scala @@ -0,0 +1,34 @@ +package io.computenode.cyfra.core.layout + +import io.computenode.cyfra.dsl.binding.GBinding + +import scala.Tuple.* +import scala.compiletime.{constValue, erasedValue, error} +import scala.deriving.Mirror + +trait LayoutBinding[L <: Layout]: + def fromBindings(bindings: Seq[GBinding[?]]): L + def toBindings(layout: L): Seq[GBinding[?]] + +object LayoutBinding: + inline given derived[L <: Layout](using m: Mirror.ProductOf[L]): LayoutBinding[L] = + allElementsAreBindings[m.MirroredElemTypes, m.MirroredElemLabels]() + val size = constValue[Size[m.MirroredElemTypes]] + val constructor = m.fromProduct + new DerivedLayoutBinding[L](size, constructor) + + // noinspection NoTailRecursionAnnotation + private inline def allElementsAreBindings[Types <: Tuple, Names <: Tuple](): Unit = + inline erasedValue[Types] match + case _: EmptyTuple => () + case _: (GBinding[?] *: t) => allElementsAreBindings[t, Tail[Names]]() + case _ => + val name = constValue[Head[Names]] + error(s"$name is not a GBinding, all elements of a Layout must be GBindings") + + class DerivedLayoutBinding[L <: Layout](size: Int, constructor: Product => L) extends LayoutBinding[L]: + override def fromBindings(bindings: Seq[GBinding[?]]): L = + assert(bindings.size == size, s"Expected $size) bindings, got ${bindings.size}") + constructor(Tuple.fromArray(bindings.toArray)) + override def toBindings(layout: L): Seq[GBinding[?]] = + layout.asInstanceOf[Product].productIterator.map(_.asInstanceOf[GBinding[?]]).toSeq diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala index d9006d69..60c53cac 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala @@ -1,7 +1,30 @@ package io.computenode.cyfra.dsl.binding import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.Value.FromExpr.fromExpr as fromExprEval +import io.computenode.cyfra.dsl.Value.{FromExpr, Int32} +import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.dsl.struct.GStruct import izumi.reflect.Tag -trait GBinding[T <: Value: {Tag, FromExpr}] +sealed trait GBinding[T <: Value: {Tag, FromExpr}]: + def tag = summon[Tag[T]] + def fromExpr = summon[FromExpr[T]] + +trait GBuffer[T <: Value: {FromExpr, Tag}] extends GBinding[T]: + def read(index: Int32): T = FromExpr.fromExpr(ReadBuffer(this, index)) + + def write(index: Int32, value: T): GIO[Unit] = GIO.write(this, index, value) + +object GBuffer + +trait GUniform[T <: Value: {Tag, FromExpr}] extends GBinding[T]: + def read: T = fromExprEval(ReadUniform(this)) + + def write(value: T): GIO[Unit] = WriteUniform(this, value) + +object GUniform: + + class ParamUniform[T <: GStruct[T]: {Tag, FromExpr}]() extends GUniform[T] + + def fromParams[T <: GStruct[T]: {Tag, FromExpr}] = ParamUniform[T]() diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBuffer.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBuffer.scala deleted file mode 100644 index b9f849cf..00000000 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBuffer.scala +++ /dev/null @@ -1,13 +0,0 @@ -package io.computenode.cyfra.dsl.binding - -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Value.{FromExpr, Int32} -import io.computenode.cyfra.dsl.gio.GIO -import izumi.reflect.Tag - -trait GBuffer[T <: Value: {FromExpr, Tag}] extends GBinding[T]: - def read(index: Int32): T = FromExpr.fromExpr(ReadBuffer(this, index)) - - def write(index: Int32, value: T): GIO[Unit] = GIO.write(this, index, value) - -object GBuffer diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GUniform.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GUniform.scala deleted file mode 100644 index 9e753e77..00000000 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GUniform.scala +++ /dev/null @@ -1,19 +0,0 @@ -package io.computenode.cyfra.dsl.binding - -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Value.FromExpr -import io.computenode.cyfra.dsl.Value.FromExpr.fromExpr -import io.computenode.cyfra.dsl.gio.GIO -import io.computenode.cyfra.dsl.struct.GStruct -import izumi.reflect.Tag - -trait GUniform[T <: Value: {Tag, FromExpr}] extends GBinding[T]: - def read: T = fromExpr(ReadUniform(this)) - - def write(value: T): GIO[Unit] = WriteUniform(this, value) - -object GUniform: - - case class ParamUniform[T <: GStruct[T]: {Tag, FromExpr}]() extends GUniform[T] - - def fromParams[T <: GStruct[T]: {Tag, FromExpr}] = ParamUniform[T]() diff --git a/cyfra-examples/src/main/resources/addOne.comp b/cyfra-examples/src/main/resources/addOne.comp new file mode 100644 index 00000000..091de31f --- /dev/null +++ b/cyfra-examples/src/main/resources/addOne.comp @@ -0,0 +1,48 @@ +#version 450 + +layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in; + +layout (set = 0, binding = 0) buffer In1 { + int in1[]; +}; +layout (set = 0, binding = 1) buffer In2 { + int in2[]; +}; +layout (set = 0, binding = 2) buffer In3 { + int in3[]; +}; +layout (set = 0, binding = 3) buffer In4 { + int in4[]; +}; +layout (set = 0, binding = 4) buffer In5 { + int in5[]; +}; +layout (set = 0, binding = 5) buffer Out1 { + int out1[]; +}; +layout (set = 0, binding = 6) buffer Out2 { + int out2[]; +}; +layout (set = 0, binding = 7) buffer Out3 { + int out3[]; +}; +layout (set = 0, binding = 8) buffer Out4 { + int out4[]; +}; +layout (set = 0, binding = 9) buffer Out5 { + int out5[]; +}; +layout (set = 0, binding = 10) uniform U1 { + int a; +}; +layout (set = 0, binding = 11) uniform U2 { + int b; +}; +void main(void) { + uint index = gl_GlobalInvocationID.x; + out1[index] = in1[index] + a + b; + out2[index] = in2[index] + a + b; + out3[index] = in3[index] + a + b; + out4[index] = in4[index] + a + b; + out5[index] = in5[index] + a + b; +} diff --git a/cyfra-vulkan/src/test/resources/compileAll.ps1 b/cyfra-examples/src/main/resources/compileAll.ps1 similarity index 100% rename from cyfra-vulkan/src/test/resources/compileAll.ps1 rename to cyfra-examples/src/main/resources/compileAll.ps1 diff --git a/cyfra-vulkan/src/test/resources/compileAll.sh b/cyfra-examples/src/main/resources/compileAll.sh similarity index 85% rename from cyfra-vulkan/src/test/resources/compileAll.sh rename to cyfra-examples/src/main/resources/compileAll.sh index fdd4be8c..e4f70140 100644 --- a/cyfra-vulkan/src/test/resources/compileAll.sh +++ b/cyfra-examples/src/main/resources/compileAll.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash for f in *.comp do diff --git a/cyfra-examples/src/main/resources/emit.comp b/cyfra-examples/src/main/resources/emit.comp new file mode 100644 index 00000000..5789c424 --- /dev/null +++ b/cyfra-examples/src/main/resources/emit.comp @@ -0,0 +1,23 @@ +#version 450 + +layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in; + +layout (set = 0, binding = 0) buffer InputBuffer { + int inBuffer[]; +}; +layout (set = 0, binding = 1) buffer OutputBuffer { + int outBuffer[]; +}; + +layout (set = 0, binding = 2) uniform InputUniform { + int emitN; +}; + +void main(void) { + uint index = gl_GlobalInvocationID.x; + int element = inBuffer[index]; + uint offset = index * uint(emitN); + for (int i = 0; i < emitN; i++) { + outBuffer[offset + uint(i)] = element; + } +} diff --git a/cyfra-examples/src/main/resources/filter.comp b/cyfra-examples/src/main/resources/filter.comp new file mode 100644 index 00000000..37beef64 --- /dev/null +++ b/cyfra-examples/src/main/resources/filter.comp @@ -0,0 +1,20 @@ +#version 450 + +layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in; + +layout (set = 0, binding = 0) buffer InputBuffer { + int inBuffer[]; +}; +layout (set = 0, binding = 1) buffer OutputBuffer { + bool outBuffer[]; +}; + +layout (set = 0, binding = 2) uniform InputUniform { + int filterValue; +}; + +void main(void) { + uint index = gl_GlobalInvocationID.x; + int element = inBuffer[index]; + outBuffer[index] = (element == filterValue); +} diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index d94c895b..e604bde3 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -1,15 +1,16 @@ package io.computenode.cyfra.samples import io.computenode.cyfra.core.archive.GContext -import io.computenode.cyfra.core.{GBufferRegion, GExecution, GProgram} import io.computenode.cyfra.core.layout.* +import io.computenode.cyfra.core.{GBufferRegion, GExecution, GProgram} import io.computenode.cyfra.dsl.Value.{GBoolean, Int32} import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} -import org.lwjgl.BufferUtils import io.computenode.cyfra.runtime.VkCyfraRuntime +import org.lwjgl.BufferUtils +import org.lwjgl.system.MemoryUtil object TestingStuff: given GContext = GContext() @@ -33,7 +34,7 @@ object TestingStuff: out = GBuffer[Int32](params.inSize * params.emitN), args = GUniform(EmitProgramUniform(params.emitN)), ), - dispatch = (layout, args) => GProgram.StaticDispatch((args.inSize, 1, 1)), + dispatch = (_, args) => GProgram.StaticDispatch((args.inSize / 128, 1, 1)), ): layout => val EmitProgramUniform(emitN) = layout.args.read val invocId = GIO.invocationId @@ -58,7 +59,7 @@ object TestingStuff: out = GBuffer[GBoolean](params.inSize), params = GUniform(FilterProgramUniform(params.filterValue)), ), - dispatch = (layout, args) => GProgram.StaticDispatch((args.inSize, 1, 1)), + dispatch = (_, args) => GProgram.StaticDispatch((args.inSize / 128, 1, 1)), ): layout => val invocId = GIO.invocationId val element = GIO.read(layout.in, invocId) @@ -79,13 +80,13 @@ object TestingStuff: layout => EmitProgramLayout(in = layout.inBuffer, out = layout.emitBuffer), ) .addProgram(filterProgram)( - params => FilterProgramParams(inSize = params.inSize, filterValue = params.filterValue), + params => FilterProgramParams(inSize = 2 * params.inSize, filterValue = params.filterValue), layout => FilterProgramLayout(in = layout.emitBuffer, out = layout.filterBuffer), ) @main def test = - given VkCyfraRuntime = VkCyfraRuntime() + given runtime: VkCyfraRuntime = VkCyfraRuntime() val emitFilterParams = EmitFilterParams(inSize = 1024, emitN = 2, filterValue = 42) @@ -94,16 +95,136 @@ object TestingStuff: .map: region => emitFilterExecution.execute(emitFilterParams, region) - val data = (0 to 1024).toArray + val data = (0 until 1024).toArray val buffer = BufferUtils.createByteBuffer(data.length * 4) buffer.asIntBuffer().put(data).flip() - val result = BufferUtils.createByteBuffer(data.length * 2) + val result = BufferUtils.createIntBuffer(data.length * 2) + val rbb = MemoryUtil.memByteBuffer(result) region.runUnsafe( init = EmitFilterLayout( inBuffer = GBuffer[Int32](buffer), emitBuffer = GBuffer[Int32](data.length * 2), filterBuffer = GBuffer[GBoolean](data.length * 2), ), - onDone = layout => layout.filterBuffer.read(result), + onDone = layout => layout.filterBuffer.read(rbb), + ) + runtime.close() + + val actual = (0 until 2 * 1024).map(i => result.get(i * 1) != 0) + val expected = (0 until 1024).flatMap(x => Seq.fill(emitFilterParams.emitN)(x)).map(_ == emitFilterParams.filterValue) + expected + .zip(actual) + .zipWithIndex + .foreach: + case ((e, a), i) => assert(e == a, s"Mismatch at index $i: expected $e, got $a") + +// Test case: Use one program 10 times, copying values from five input buffers to five output buffers and adding values from two uniforms + case class AddProgramParams(bufferSize: Int, addA: Int, addB: Int) + case class AddProgramUniform(a: Int32) extends GStruct[AddProgramUniform] + case class AddProgramLayout( + in1: GBuffer[Int32], + in2: GBuffer[Int32], + in3: GBuffer[Int32], + in4: GBuffer[Int32], + in5: GBuffer[Int32], + out1: GBuffer[Int32], + out2: GBuffer[Int32], + out3: GBuffer[Int32], + out4: GBuffer[Int32], + out5: GBuffer[Int32], + u1: GUniform[AddProgramUniform] = GUniform.fromParams, + u2: GUniform[AddProgramUniform] = GUniform.fromParams, + ) extends Layout + + case class AddProgramExecLayout( + in1: GBuffer[Int32], + in2: GBuffer[Int32], + in3: GBuffer[Int32], + in4: GBuffer[Int32], + in5: GBuffer[Int32], + out1: GBuffer[Int32], + out2: GBuffer[Int32], + out3: GBuffer[Int32], + out4: GBuffer[Int32], + out5: GBuffer[Int32], + ) extends Layout + + val addProgram: GProgram[AddProgramParams, AddProgramLayout] = GProgram[AddProgramParams, AddProgramLayout]( + layout = params => + AddProgramLayout( + in1 = GBuffer[Int32](params.bufferSize), + in2 = GBuffer[Int32](params.bufferSize), + in3 = GBuffer[Int32](params.bufferSize), + in4 = GBuffer[Int32](params.bufferSize), + in5 = GBuffer[Int32](params.bufferSize), + out1 = GBuffer[Int32](params.bufferSize), + out2 = GBuffer[Int32](params.bufferSize), + out3 = GBuffer[Int32](params.bufferSize), + out4 = GBuffer[Int32](params.bufferSize), + out5 = GBuffer[Int32](params.bufferSize), + u1 = GUniform(AddProgramUniform(params.addA)), + u2 = GUniform(AddProgramUniform(params.addB)), + ), + dispatch = (layout, args) => GProgram.StaticDispatch((args.bufferSize / 128, 1, 1)), + )(_ => ???) + def swap(l: AddProgramLayout): AddProgramLayout = + val AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5, u1, u2) = l + AddProgramLayout(out1, out2, out3, out4, out5, in1, in2, in3, in4, in5, u1, u2) + + def fromExecLayout(l: AddProgramExecLayout): AddProgramLayout = + val AddProgramExecLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5) = l + AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5) + + val execution = (0 until 11).foldLeft( + GExecution[AddProgramParams, AddProgramExecLayout]().asInstanceOf[GExecution[AddProgramParams, AddProgramExecLayout, AddProgramExecLayout]], + )((x, i) => + if i % 2 == 0 then x.addProgram(addProgram)(mapParams = identity[AddProgramParams], mapLayout = fromExecLayout) + else x.addProgram(addProgram)(mapParams = identity, mapLayout = x => swap(fromExecLayout(x))), + ) + + @main + def testAddProgram10Times = + given runtime: VkCyfraRuntime = VkCyfraRuntime() + val bufferSize = 1280 + val params = AddProgramParams(bufferSize, addA = 0, addB = 1) + val region = GBufferRegion + .allocate[AddProgramExecLayout] + .map: region => + execution.execute(params, region) + + val inBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) + val wbbList = inBuffers.map(MemoryUtil.memByteBuffer) + val outBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) + val rbbList = outBuffers.map(MemoryUtil.memByteBuffer) + + val inData = (0 until bufferSize).toArray + inBuffers.foreach(_.put(inData).flip()) + region.runUnsafe( + init = AddProgramExecLayout( + in1 = GBuffer[Int32](wbbList(0)), + in2 = GBuffer[Int32](wbbList(1)), + in3 = GBuffer[Int32](wbbList(2)), + in4 = GBuffer[Int32](wbbList(3)), + in5 = GBuffer[Int32](wbbList(4)), + out1 = GBuffer[Int32](bufferSize), + out2 = GBuffer[Int32](bufferSize), + out3 = GBuffer[Int32](bufferSize), + out4 = GBuffer[Int32](bufferSize), + out5 = GBuffer[Int32](bufferSize), + ), + onDone = layout => { + layout.out1.read(rbbList(0)) + layout.out2.read(rbbList(1)) + layout.out3.read(rbbList(2)) + layout.out4.read(rbbList(3)) + layout.out5.read(rbbList(4)) + }, ) + runtime.close() + val expected = inData.map(_ + 11 * (params.addA + params.addB)) + outBuffers.foreach { buf => + (0 until bufferSize).foreach { i => + assert(buf.get(i) == expected(i), s"Mismatch at index $i: expected ${expected(i)}, got ${buf.get(i)}") + } + } diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index df0b470e..91b445a9 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -1,11 +1,258 @@ package io.computenode.cyfra.runtime +import io.computenode.cyfra.core.GProgram.InitProgramLayout +import io.computenode.cyfra.core.SpirvProgram.* +import io.computenode.cyfra.core.binding.{BufferRef, UniformRef} import io.computenode.cyfra.core.{GExecution, GProgram} -import io.computenode.cyfra.core.layout.Layout +import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} +import io.computenode.cyfra.runtime.ExecutionHandler.{ + BindingLogicError, + Dispatch, + DispatchType, + ExecutionBinding, + ExecutionStep, + PipelineBarrier, + ShaderCall, +} +import io.computenode.cyfra.runtime.ExecutionHandler.DispatchType.* +import io.computenode.cyfra.runtime.ExecutionHandler.ExecutionBinding.{BufferBinding, UniformBinding} +import io.computenode.cyfra.utility.Utility.timed +import io.computenode.cyfra.vulkan.command.{CommandPool, Fence} +import io.computenode.cyfra.vulkan.compute.ComputePipeline +import io.computenode.cyfra.vulkan.core.Queue +import io.computenode.cyfra.vulkan.memory.{DescriptorPool, DescriptorSet} +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import izumi.reflect.Tag +import org.lwjgl.vulkan.VK10.* +import org.lwjgl.vulkan.VK13.{VK_ACCESS_2_SHADER_READ_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, vkCmdPipelineBarrier2} +import org.lwjgl.vulkan.{VkCommandBuffer, VkCommandBufferBeginInfo, VkDependencyInfo, VkMemoryBarrier2, VkSubmitInfo} + +import scala.collection.mutable + +class ExecutionHandler(runtime: VkCyfraRuntime): + private val context = runtime.context + import context.given + + private val queue: Queue = context.computeQueue // TODO multiple queues - multithreading support + private val descriptorPool: DescriptorPool = context.descriptorPool // TODO descriptor pool manager - descriptor allocation and reclamation support + private val commandPool: CommandPool = context.commandPool // TODO multiple command pools - different command pools for different workloads + + def handle[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding](execution: GExecution[Params, EL, RL], params: Params, layout: EL)( + using VkAllocation, + ): RL = + val (result, shaderCalls) = interpret(execution, params, layout) + + val descriptorSets = shaderCalls.map { case ShaderCall(pipeline, layout, _) => + pipeline.pipelineLayout.sets.map(descriptorPool.allocate).zip(layout).map { case (set, bindings) => + set.update(bindings.map(x => VkAllocation.getUnderlying(x.binding))) + set + } + } + + val dispatches: Seq[Dispatch] = shaderCalls + .zip(descriptorSets) + .map: + case (ShaderCall(pipeline, layout, dispatch), sets) => + Dispatch(pipeline, layout, sets, dispatch) + + val (executeSteps, _) = dispatches.foldLeft((Seq.empty[ExecutionStep], Set.empty[GBinding[?]])): + case ((steps, dirty), step) => + val bindings = step.layout.flatten.map(_.binding) + if bindings.exists(dirty.contains) then (steps.appendedAll(Seq(PipelineBarrier, step)), bindings.toSet) + else (steps.appended(step), dirty ++ bindings) + + val commandBuffer = recordCommandBuffer(executeSteps) + pushStack: stack => + val pCommandBuffer = stack.callocPointer(1).put(0, commandBuffer) + val submitInfo = VkSubmitInfo + .calloc(stack) + .sType$Default() + .pCommandBuffers(pCommandBuffer) + + val fence = new Fence() + timed("Vulkan render command"): + check(vkQueueSubmit(queue.get, submitInfo, fence.get), "Failed to submit command buffer to queue") + fence.block().destroy() + commandPool.freeCommandBuffer(commandBuffer) + result + + private def interpret[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding]( + execution: GExecution[Params, EL, RL], + params: Params, + layout: EL, + )(using VkAllocation): (RL, Seq[ShaderCall]) = + val bindingsAcc: mutable.Map[GBinding[?], mutable.Buffer[GBinding[?]]] = mutable.Map.empty + + def mockBindings[L <: Layout: LayoutBinding](layout: L): L = + val mapper = summon[LayoutBinding[L]] + val res = mapper + .toBindings(layout) + .map: + case x: ExecutionBinding[?] => x + case x: GBinding[?] => + val e = ExecutionBinding(x)(using x.fromExpr, x.tag) + bindingsAcc.put(e, mutable.Buffer(x)) + e + + mapper.fromBindings(res) + + // noinspection TypeParameterShadow + def interpretImpl[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding]( + execution: GExecution[Params, EL, RL], + params: Params, + layout: EL, + ): (RL, Seq[ShaderCall]) = + execution match + case GExecution.Pure() => (layout, Seq.empty) + case GExecution.Map(innerExec, map, cmap, cmapP) => + val pel = innerExec.layoutBinding + val prl = innerExec.resLayoutBinding + val cParams = cmapP(params) + val cLayout = mockBindings(cmap(layout))(using pel) + val (prevRl, calls) = interpretImpl(innerExec, cParams, cLayout)(using pel, prl) + val nextRl = mockBindings(map(prevRl)) + (nextRl, calls) + case GExecution.FlatMap(execution, f) => + val el = execution.layoutBinding + val (rl, calls) = interpretImpl(execution, params, layout)(using el, execution.resLayoutBinding) + val nextExecution = f(params, rl) + val (rl2, calls2) = interpretImpl(nextExecution, params, layout)(using el, nextExecution.resLayoutBinding) + (rl2, calls ++ calls2) + case program: GProgram[Params, EL] => + given lb: LayoutBinding[EL] = program.layoutBinding + given LayoutStruct[EL] = program.layoutStruct + val shader = + runtime.getOrLoadProgram(program) + val layoutInit = + val initProgram: InitProgramLayout = summon[VkAllocation].getInitProgramLayout + program.layout(initProgram)(params) + lb.toBindings(layout) + .zip(lb.toBindings(layoutInit)) + .foreach: + case (binding, initBinding) => + bindingsAcc(binding).append(initBinding) + val dispatch = program.dispatch(layout, params) match + case GProgram.DynamicDispatch(buffer, offset) => DispatchType.Indirect(buffer, offset) + case GProgram.StaticDispatch(size) => DispatchType.Direct(size._1, size._2, size._3) + // noinspection ScalaRedundantCast + (layout.asInstanceOf[RL], Seq(ShaderCall(shader.underlying, shader.shaderBindings(layout), dispatch))) + case _ => ??? + + val (rl, steps) = interpretImpl(execution, params, mockBindings(layout)) + val bingingToVk = bindingsAcc.map(x => (x._1, interpretBinding(x._1, x._2.toSeq))) + + val nextSteps = steps.map: + case ShaderCall(pipeline, layout, dispatch) => + val nextLayout = layout.map: + _.map: + case Binding(binding, operation) => Binding(bingingToVk(binding), operation) + val nextDispatch = dispatch match + case x: Direct => x + case Indirect(buffer, offset) => Indirect(bingingToVk(buffer), offset) + ShaderCall(pipeline, nextLayout, nextDispatch) + + val mapper = summon[LayoutBinding[RL]] + val res = mapper.fromBindings(mapper.toBindings(rl).map(bingingToVk.apply)) + (res, nextSteps) + + private def interpretBinding(binding: GBinding[?], bindings: Seq[GBinding[?]])(using VkAllocation): GBinding[?] = + binding match + case _: BufferBinding[?] => + val (allocations, sizeSpec) = bindings.partitionMap: + case x: VkBuffer[?] => Left(x) + case x: GProgram.BufferLengthSpec[?] => Right(x) + case x => throw BindingLogicError(x, "Unsupported buffer type") + if allocations.size > 1 then throw BindingLogicError(allocations, "Multiple allocations for buffer") + val alloc = allocations.headOption + + val lengths = sizeSpec.distinctBy(_.length) + if lengths.size > 1 then throw BindingLogicError(lengths, "Multiple conflicting lengths for buffer") + val length = lengths.headOption + + (alloc, length) match + case (Some(buffer), Some(sizeSpec)) => + if buffer.length != sizeSpec.length then + throw BindingLogicError(Seq(buffer, sizeSpec), s"Buffer length mismatch, ${buffer.length} != ${sizeSpec.length}") + buffer + case (Some(buffer), None) => buffer + case (None, Some(length)) => length.materialise() + case (None, None) => throw new IllegalStateException("Cannot create buffer without size or allocation") + + case _: UniformBinding[?] => + val allocations = bindings.filter: + case _: VkUniform[?] => true + case _: GProgram.DynamicUniform[?] => false + case _: GUniform.ParamUniform[?] => false + case x => throw BindingLogicError(x, "Unsupported binding type") + if allocations.size > 1 then throw BindingLogicError(allocations, "Multiple allocations for uniform") + allocations.headOption.getOrElse(throw new IllegalStateException("Uniform never allocated")) + case x => throw new IllegalArgumentException(s"Binding of type ${x.getClass.getName} should not be here") + + private def recordCommandBuffer(steps: Seq[ExecutionStep]): VkCommandBuffer = pushStack: stack => + val commandBuffer = commandPool.createCommandBuffer() + val commandBufferBeginInfo = VkCommandBufferBeginInfo + .calloc(stack) + .sType$Default() + .flags(0) + + check(vkBeginCommandBuffer(commandBuffer, commandBufferBeginInfo), "Failed to begin recording command buffer") + + steps.foreach: + case PipelineBarrier => + val memoryBarrier = VkMemoryBarrier2 // TODO don't synchronise everything + .calloc(1, stack) + .sType$Default() + .srcStageMask(VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT) + .srcAccessMask(VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT) + .dstStageMask(VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT) + .dstAccessMask(VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT) + + val dependencyInfo = VkDependencyInfo + .calloc(stack) + .sType$Default() + .pMemoryBarriers(memoryBarrier) + + vkCmdPipelineBarrier2(commandBuffer, dependencyInfo) + + case Dispatch(pipeline, layout, descriptorSets, dispatch) => + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get) + + val pDescriptorSets = stack.longs(descriptorSets.map(_.get)*) + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.pipelineLayout.id, 0, pDescriptorSets, null) + + dispatch match + case Direct(x, y, z) => vkCmdDispatch(commandBuffer, x, y, z) + case Indirect(buffer, offset) => vkCmdDispatchIndirect(commandBuffer, VkAllocation.getUnderlying(buffer).get, offset) + + check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") + commandBuffer object ExecutionHandler: + case class ShaderCall(pipeline: ComputePipeline, layout: ShaderLayout, dispatch: DispatchType) + + sealed trait ExecutionStep + case class Dispatch(pipeline: ComputePipeline, layout: ShaderLayout, descriptorSets: Seq[DescriptorSet], dispatch: DispatchType) + extends ExecutionStep + case object PipelineBarrier extends ExecutionStep + + sealed trait DispatchType + object DispatchType: + case class Direct(x: Int, y: Int, z: Int) extends DispatchType + case class Indirect(buffer: GBinding[?], offset: Int) extends DispatchType + + sealed trait ExecutionBinding[T <: Value: {FromExpr, Tag}] + object ExecutionBinding: + class UniformBinding[T <: Value: {FromExpr, Tag}] extends ExecutionBinding[T] with GUniform[T] + class BufferBinding[T <: Value: {FromExpr, Tag}] extends ExecutionBinding[T] with GBuffer[T] - def handle[Params, L <: Layout, RL <: Layout](execution: GExecution[Params, L, RL], params: Params): List[BoundProgram[?, ?, ?]] = - ??? + def apply[T <: Value: {FromExpr, Tag}](binding: GBinding[T]): ExecutionBinding[T] & GBinding[T] = binding match + case _: GUniform[T] => new UniformBinding() + case _: GBuffer[T] => new BufferBinding() - case class BoundProgram[LParams, Params, L <: Layout](layout: L, paramsMapping: LParams => Params, program: GProgram[Params, L]) + case class BindingLogicError(bindings: Seq[GBinding[?]], message: String) extends RuntimeException(s"Error in binding logic for $bindings: $message") + object BindingLogicError: + def apply(binding: GBinding[?], message: String): BindingLogicError = + new BindingLogicError(Seq(binding), message) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index d1474976..59142676 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -1,29 +1,105 @@ package io.computenode.cyfra.runtime -import io.computenode.cyfra.core.layout.{Layout, LayoutStruct} -import io.computenode.cyfra.core.{Allocation, GExecution} +import io.computenode.cyfra.core.layout.{Layout, LayoutBinding} +import io.computenode.cyfra.core.{Allocation, GExecution, GProgram} +import io.computenode.cyfra.core.SpirvProgram +import io.computenode.cyfra.dsl.Expression.ConstInt32 import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.runtime.VkAllocation.getUnderlying +import io.computenode.cyfra.spirv.SpirvTypes.typeStride +import io.computenode.cyfra.vulkan.command.CommandPool +import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} +import io.computenode.cyfra.vulkan.util.Util.pushStack +import io.computenode.cyfra.dsl.Value.Int32 import izumi.reflect.Tag +import org.lwjgl.BufferUtils +import org.lwjgl.system.MemoryUtil +import org.lwjgl.vulkan.VK10 +import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT} import java.nio.ByteBuffer +import scala.collection.mutable +import scala.util.chaining.* + +class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler)(using Allocator) extends Allocation: + given VkAllocation = this -class VkAllocation extends Allocation: extension (buffer: GBinding[?]) - def read(bb: ByteBuffer, offset: Int = 0, length: Int = -1): Unit = ??? + def read(bb: ByteBuffer, offset: Int = 0, size: Int = -1): Unit = + val buf = getUnderlying(buffer) + val s = if size < 0 then buf.size - offset else size + + buf match + case buffer: Buffer.HostBuffer => Buffer.copyBuffer(buffer, bb, offset, 0, s) + case buffer: Buffer.DeviceBuffer => + val stagingBuffer = getStagingBuffer(s) + Buffer.copyBuffer(buffer, stagingBuffer, offset, 0, s, commandPool).block().destroy() + Buffer.copyBuffer(stagingBuffer, bb, 0, 0, s) - def write(bb: ByteBuffer, offset: Int = 0, length: Int = -1): Unit = ??? + def write(bb: ByteBuffer, offset: Int = 0, size: Int = -1): Unit = + val buf = getUnderlying(buffer) + val s = if size < 0 then bb.remaining() else size - extension [Params, L <: Layout, RL <: Layout: LayoutStruct](execution: GExecution[Params, L, RL]) def execute(params: Params, layout: L): RL = ??? + buf match + case buffer: Buffer.HostBuffer => Buffer.copyBuffer(bb, buffer, offset, 0, s) + case buffer: Buffer.DeviceBuffer => + val stagingBuffer = getStagingBuffer(s) + Buffer.copyBuffer(bb, stagingBuffer, 0, 0, s) + Buffer.copyBuffer(stagingBuffer, buffer, 0, offset, s, commandPool).block().destroy() extension (buffers: GBuffer.type) - def apply[T <: Value: {Tag, FromExpr}](size: Int): GBuffer[T] = ??? + def apply[T <: Value: {Tag, FromExpr}](length: Int): GBuffer[T] = + VkBuffer[T](length).tap(bindings += _) - def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] = ??? + def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] = + val sizeOfT = typeStride(summon[Tag[T]]) + val length = buff.remaining() / sizeOfT + if buff.remaining() % sizeOfT != 0 then ??? + GBuffer[T](length).tap(_.write(buff)) extension (buffers: GUniform.type) - def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GUniform[T] = ??? + def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GUniform[T] = + GUniform[T]().tap(_.write(buff)) + + def apply[T <: Value: {Tag, FromExpr}](): GUniform[T] = + VkUniform[T]().tap(bindings += _) + + extension [Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding](execution: GExecution[Params, EL, RL]) + def execute(params: Params, layout: EL): RL = executionHandler.handle(execution, params, layout) + + private def direct[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GUniform[T] = + GUniform[T](buff) + + def getInitProgramLayout: GProgram.InitProgramLayout = + new GProgram.InitProgramLayout: + extension (uniforms: GUniform.type) + def apply[T <: GStruct[T]: {Tag, FromExpr}](value: T): GUniform[T] = pushStack: stack => + val bb = value.productElement(0) match + case Int32(tree: ConstInt32) => MemoryUtil.memByteBuffer(stack.ints(tree.value)) + case _ => ??? + direct(bb) + + private val bindings = mutable.Buffer[VkUniform[?] | VkBuffer[?]]() + private[cyfra] def close(): Unit = + bindings.map(getUnderlying).foreach(_.destroy()) + stagingBuffer.foreach(_.destroy()) + + private var stagingBuffer: Option[Buffer.HostBuffer] = None + private def getStagingBuffer(size: Int): Buffer.HostBuffer = + stagingBuffer match + case Some(buffer) if buffer.size >= size => buffer + case _ => + stagingBuffer.foreach(_.destroy()) + val newBuffer = Buffer.HostBuffer(size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT) + stagingBuffer = Some(newBuffer) + newBuffer - def apply[T <: Value: {Tag, FromExpr}](): GUniform[T] = ??? +object VkAllocation: + private[runtime] def getUnderlying(buffer: GBinding[?]): Buffer = + buffer match + case buffer: VkBuffer[?] => buffer.underlying + case uniform: VkUniform[?] => uniform.underlying + case _ => throw new IllegalArgumentException(s"Tried to get underlying of non-VkBinding $buffer") diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala new file mode 100644 index 00000000..cda73868 --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala @@ -0,0 +1,23 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer} +import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} +import izumi.reflect.Tag +import io.computenode.cyfra.spirv.SpirvTypes.typeStride +import org.lwjgl.vulkan.VK10 +import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT} + +class VkBuffer[T <: Value: {Tag, FromExpr}] private (var length: Int, val underlying: Buffer) extends GBuffer[T]: + val sizeOfT: Int = typeStride(summon[Tag[T]]) + +object VkBuffer: + private final val Padding = 64 + private final val UsageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT + + def apply[T <: Value: {Tag, FromExpr}](length: Int)(using Allocator): VkBuffer[T] = + val sizeOfT = typeStride(summon[Tag[T]]) + val size = (length * sizeOfT + Padding - 1) / Padding * Padding + val buffer = new Buffer.DeviceBuffer(size, UsageFlags) + new VkBuffer[T](length, buffer) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala index 87dbd5ab..f28cfd65 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala @@ -1,8 +1,27 @@ package io.computenode.cyfra.runtime -import io.computenode.cyfra.core.Allocation -import io.computenode.cyfra.core.{Allocation, CyfraRuntime} +import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} +import io.computenode.cyfra.core.{Allocation, CyfraRuntime, GExecution, GProgram, SpirvProgram} +import io.computenode.cyfra.vulkan.VulkanContext +import io.computenode.cyfra.vulkan.compute.ComputePipeline + +import scala.collection.mutable class VkCyfraRuntime extends CyfraRuntime: - override def allocation(): Allocation = - new VkAllocation() + val context = new VulkanContext() + import context.given + + private val executionHandler = new ExecutionHandler(this) + + private val shaderCache = mutable.Map.empty[String, VkShader[?]] + private[cyfra] def getOrLoadProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}](program: GProgram[Params, L]): VkShader[L] = + shaderCache.getOrElseUpdate(program.cacheKey, VkShader(program)).asInstanceOf[VkShader[L]] + + override def withAllocation(f: Allocation => Unit): Unit = + val allocation = new VkAllocation(context.commandPool, executionHandler) + f(allocation) + allocation.close() + + def close(): Unit = + shaderCache.values.foreach(_.underlying.destroy()) + context.destroy() diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala new file mode 100644 index 00000000..4544553e --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala @@ -0,0 +1,42 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.core.{GProgram, GioProgram, SpirvProgram} +import io.computenode.cyfra.core.SpirvProgram.* +import io.computenode.cyfra.core.GProgram.InitProgramLayout +import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} +import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} +import io.computenode.cyfra.vulkan.compute.ComputePipeline +import io.computenode.cyfra.vulkan.compute.ComputePipeline.* +import io.computenode.cyfra.vulkan.core.Device +import izumi.reflect.Tag + +import scala.util.{Failure, Success} + +case class VkShader[L](underlying: ComputePipeline, shaderBindings: L => ShaderLayout) + +object VkShader: + def apply[P, L <: Layout: {LayoutBinding, LayoutStruct}](program: GProgram[P, L])(using Device): VkShader[L] = + val SpirvProgram(layout, dispatch, _workgroupSize, code, entryPoint, shaderBindings, _) = program match + case p: GioProgram[?, ?] => compile(p) + case p: SpirvProgram[?, ?] => p + case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") + + val shaderLayout = shaderBindings(summon[LayoutStruct[L]].layoutRef) + val sets = shaderLayout.map: set => + val descriptors = set.map { case Binding(binding, op) => + val kind = binding match + case buffer: GBuffer[?] => BindingType.StorageBuffer + case uniform: GUniform[?] => BindingType.Uniform + DescriptorInfo(kind) + } + DescriptorSetInfo(descriptors) + + val pipeline = ComputePipeline(code, entryPoint, LayoutInfo(sets)) + VkShader(pipeline, shaderBindings) + + def compile[Params, L <: Layout: {LayoutBinding, LayoutStruct}](program: GioProgram[Params, L]): SpirvProgram[Params, L] = + val GioProgram(_, layout, dispatch, _) = program + val name = program.cacheKey + ".spv" + loadShader(name) match + case Failure(_) => ??? + case Success(_) => SpirvProgram(name, (il: InitProgramLayout) ?=> layout(il), dispatch) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala new file mode 100644 index 00000000..f8c75da7 --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala @@ -0,0 +1,21 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.GUniform +import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} +import izumi.reflect.Tag +import org.lwjgl.vulkan.VK10 +import org.lwjgl.vulkan.VK10.* + +class VkUniform[T <: Value: {Tag, FromExpr}] private (val underlying: Buffer) extends GUniform[T]: + val sizeOfT: Int = 4 + +object VkUniform: + private final val UsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT + + def apply[T <: Value: {Tag, FromExpr}]()(using Allocator): VkUniform[T] = + val sizeOfT = 4 // typeStride(summon[Tag[T]]) + val buffer = new Buffer.DeviceBuffer(sizeOfT, UsageFlags) + new VkUniform[T](buffer) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala index c63d2210..2fe2c35d 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/ComputePipeline.scala @@ -4,6 +4,7 @@ import io.computenode.cyfra.vulkan.VulkanContext import io.computenode.cyfra.vulkan.core.Device import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObjectHandle +import io.computenode.cyfra.vulkan.compute.ComputePipeline.* import org.lwjgl.vulkan.* import org.lwjgl.vulkan.VK10.* @@ -16,7 +17,7 @@ import scala.util.{Try, Using} /** @author * MarconZet Created 14.04.2020 */ -private[cyfra] class ComputePipeline(shaderCode: ByteBuffer, functionName: String, val layoutInfo: LayoutInfo)(using device: Device) +private[cyfra] class ComputePipeline(shaderCode: ByteBuffer, functionName: String, layoutInfo: LayoutInfo)(using device: Device) extends VulkanObjectHandle: private val shader: Long = pushStack: stack => // TODO khr_maintenance5 @@ -31,9 +32,9 @@ private[cyfra] class ComputePipeline(shaderCode: ByteBuffer, functionName: Strin check(vkCreateShaderModule(device.get, shaderModuleCreateInfo, null, pShaderModule), "Failed to create shader module") pShaderModule.get() - val descriptorSetLayouts: Seq[(Long, LayoutSet)] = layoutInfo.sets.map(x => (createDescriptorSetLayout(x), x)) + val pipelineLayout: PipelineLayout = pushStack: stack => + val descriptorSetLayouts: Seq[DescriptorSetLayout] = layoutInfo.sets.map(x => DescriptorSetLayout(createDescriptorSetLayout(x), x)) - val pipelineLayout: Long = pushStack: stack => val pipelineLayoutCreateInfo = VkPipelineLayoutCreateInfo .calloc(stack) .sType$Default() @@ -44,7 +45,8 @@ private[cyfra] class ComputePipeline(shaderCode: ByteBuffer, functionName: Strin val pPipelineLayout = stack.callocLong(1) check(vkCreatePipelineLayout(device.get, pipelineLayoutCreateInfo, null, pPipelineLayout), "Failed to create pipeline layout") - pPipelineLayout.get(0) + val layout = pPipelineLayout.get(0) + PipelineLayout(layout, descriptorSetLayouts) protected val handle: Long = pushStack: stack => val pipelineShaderStageCreateInfo = VkPipelineShaderStageCreateInfo @@ -63,7 +65,7 @@ private[cyfra] class ComputePipeline(shaderCode: ByteBuffer, functionName: Strin .pNext(0) .flags(0) .stage(pipelineShaderStageCreateInfo) - .layout(pipelineLayout) + .layout(pipelineLayout.id) .basePipelineHandle(0) .basePipelineIndex(0) @@ -73,19 +75,19 @@ private[cyfra] class ComputePipeline(shaderCode: ByteBuffer, functionName: Strin protected def close(): Unit = vkDestroyPipeline(device.get, handle, null) - vkDestroyPipelineLayout(device.get, pipelineLayout, null) - descriptorSetLayouts.map(_._1).foreach(vkDestroyDescriptorSetLayout(device.get, _, null)) - vkDestroyShaderModule(device.get, handle, null) + vkDestroyPipelineLayout(device.get, pipelineLayout.id, null) + pipelineLayout.sets.map(_.id).foreach(vkDestroyDescriptorSetLayout(device.get, _, null)) + vkDestroyShaderModule(device.get, shader, null) - private def createDescriptorSetLayout(set: LayoutSet): Long = pushStack: stack => - val descriptorSetLayoutBindings = VkDescriptorSetLayoutBinding.calloc(set.bindings.length, stack) - set.bindings.foreach: binding => + private def createDescriptorSetLayout(set: DescriptorSetInfo): Long = pushStack: stack => + val descriptorSetLayoutBindings = VkDescriptorSetLayoutBinding.calloc(set.descriptors.length, stack) + set.descriptors.zipWithIndex.foreach: binding => descriptorSetLayoutBindings .get() - .binding(binding.id) - .descriptorType(binding.size match - case InputBufferSize(_) => VK_DESCRIPTOR_TYPE_STORAGE_BUFFER - case UniformSize(_) => VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) + .binding(binding._2) + .descriptorType(binding._1.kind match + case BindingType.StorageBuffer => VK_DESCRIPTOR_TYPE_STORAGE_BUFFER + case BindingType.Uniform => VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) .descriptorCount(1) .stageFlags(VK_SHADER_STAGE_COMPUTE_BIT) .pImmutableSamplers(null) @@ -104,12 +106,13 @@ private[cyfra] class ComputePipeline(shaderCode: ByteBuffer, functionName: Strin pDescriptorSetLayout.get(0) object ComputePipeline: - def loadShader(path: String): Try[ByteBuffer] = - loadShader(path, getClass.getClassLoader) - - private def loadShader(path: String, classLoader: ClassLoader): Try[ByteBuffer] = - Using.Manager: use => - val file = new File(Objects.requireNonNull(classLoader.getResource(path)).getFile) - val fis = use(new FileInputStream(file)) - val fc = use(fis.getChannel) - fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()) + private[cyfra] case class PipelineLayout(id: Long, sets: Seq[DescriptorSetLayout]) + private[cyfra] case class DescriptorSetLayout(id: Long, set: DescriptorSetInfo) + + private[cyfra] case class LayoutInfo(sets: Seq[DescriptorSetInfo]) + private[cyfra] case class DescriptorSetInfo(descriptors: Seq[DescriptorInfo]) + private[cyfra] case class DescriptorInfo(kind: BindingType) + + private[cyfra] enum BindingType: + case StorageBuffer + case Uniform diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/LayoutInfo.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/LayoutInfo.scala deleted file mode 100644 index 1edbcea8..00000000 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/compute/LayoutInfo.scala +++ /dev/null @@ -1,12 +0,0 @@ -package io.computenode.cyfra.vulkan.compute - -/** @author - * MarconZet Created 25.04.2020 - */ -private[cyfra] case class LayoutInfo(sets: Seq[LayoutSet]) -private[cyfra] case class LayoutSet(id: Int, bindings: Seq[Binding]) -private[cyfra] case class Binding(id: Int, size: LayoutElementSize) - -private[cyfra] sealed trait LayoutElementSize -private[cyfra] case class InputBufferSize(elemSize: Int) extends LayoutElementSize -private[cyfra] case class UniformSize(size: Int) extends LayoutElementSize diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala index f3e83712..3721e9b3 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala @@ -35,7 +35,7 @@ private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandl case VK_DEBUG_REPORT_DEBUG_BIT_EXT => logger.debug(decodedMessage) case VK_DEBUG_REPORT_ERROR_BIT_EXT => - logger.error(decodedMessage, new RuntimeException()) + logger.error(decodedMessage) case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT => logger.warn(decodedMessage) case VK_DEBUG_REPORT_INFORMATION_BIT_EXT => diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala index dfb585d1..7452ec0a 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala @@ -4,10 +4,11 @@ import io.computenode.cyfra.utility.Logger.logger import io.computenode.cyfra.vulkan.VulkanContext.ValidationLayer import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObject -import org.lwjgl.system.MemoryStack +import org.lwjgl.system.{MemoryStack, MemoryUtil} import org.lwjgl.system.MemoryUtil.NULL import org.lwjgl.vulkan.* import org.lwjgl.vulkan.EXTDebugReport.VK_EXT_DEBUG_REPORT_EXTENSION_NAME +import org.lwjgl.vulkan.EXTLayerSettings.VK_LAYER_SETTING_TYPE_BOOL32_EXT import org.lwjgl.vulkan.KHRPortabilityEnumeration.{VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME} import org.lwjgl.vulkan.VK10.* @@ -67,6 +68,19 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj .pApplicationInfo(appInfo) .ppEnabledExtensionNames(ppEnabledExtensionNames) .ppEnabledLayerNames(ppEnabledLayerNames) + + if enableValidationLayers then + val layerSettings = VkLayerSettingEXT.calloc(1, stack) + layerSettings + .get(0) + .pLayerName(stack.ASCII(ValidationLayer)) + .pSettingName(stack.ASCII("validate_sync")) + .`type`(VK_LAYER_SETTING_TYPE_BOOL32_EXT) + .valueCount(1) + .pValues(MemoryUtil.memByteBuffer(stack.ints(1))) + val layerSettingsCI = VkLayerSettingsCreateInfoEXT.calloc(stack).sType$Default().pSettings(layerSettings) + pCreateInfo.pNext(layerSettingsCI) + val pInstance = stack.mallocPointer(1) check(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance") new VkInstance(pInstance.get(0), pCreateInfo) @@ -103,7 +117,7 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj if enableValidationLayers then extensions.addAll(Instance.ValidationLayersExtensions) val filteredExtensions = extensions.filter(ext => - availableExtensions.contains(ext).tap { x => + availableExtensions.contains(ext).tap { x => // TODO detect when this extension is needed if !x then logger.warn(s"Requested Vulkan instance extension '$ext' is not available") }, ) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/BufferAction.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/BufferAction.scala deleted file mode 100644 index 32b5ba49..00000000 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/BufferAction.scala +++ /dev/null @@ -1,17 +0,0 @@ -package io.computenode.cyfra.vulkan.executor - -import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT} - -enum BufferAction(val action: Int): - case DoNothing extends BufferAction(0) - case LoadTo extends BufferAction(VK_BUFFER_USAGE_TRANSFER_DST_BIT) - case LoadFrom extends BufferAction(VK_BUFFER_USAGE_TRANSFER_SRC_BIT) - case LoadFromTo extends BufferAction(VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - - private def findAction(action: Int): BufferAction = action match - case VK_BUFFER_USAGE_TRANSFER_DST_BIT => LoadTo - case VK_BUFFER_USAGE_TRANSFER_SRC_BIT => LoadFrom - case 3 => LoadFromTo - case _ => DoNothing - - def |(other: BufferAction): BufferAction = findAction(this.action | other.action) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala deleted file mode 100644 index 63c61bc2..00000000 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/executor/SequenceExecutor.scala +++ /dev/null @@ -1,206 +0,0 @@ -package io.computenode.cyfra.vulkan.executor - -import io.computenode.cyfra.utility.Utility.timed -import io.computenode.cyfra.vulkan.VulkanContext -import io.computenode.cyfra.vulkan.command.* -import io.computenode.cyfra.vulkan.compute.* -import io.computenode.cyfra.vulkan.core.* -import io.computenode.cyfra.vulkan.executor.SequenceExecutor.* -import io.computenode.cyfra.vulkan.memory.* -import io.computenode.cyfra.vulkan.util.Util.* -import org.lwjgl.BufferUtils -import org.lwjgl.util.vma.Vma.* -import org.lwjgl.vulkan.* -import org.lwjgl.vulkan.KHRSynchronization2.vkCmdPipelineBarrier2KHR -import org.lwjgl.vulkan.VK10.* -import org.lwjgl.vulkan.VK13.* - -import java.nio.ByteBuffer - -/** @author - * MarconZet Created 15.04.2020 - */ -private[cyfra] class SequenceExecutor(computeSequence: ComputationSequence, context: VulkanContext): - import context.given - - private val queue: Queue = context.computeQueue - private val descriptorPool: DescriptorPool = context.descriptorPool - private val commandPool: CommandPool = context.commandPool - - private val pipelineToDescriptorSets: Map[ComputePipeline, Seq[DescriptorSet]] = pushStack: stack => - val pipelines = computeSequence.sequence.collect: - case Compute(pipeline, _) => pipeline - - val rawSets = pipelines.map(_.layoutInfo.sets) - val numbered = rawSets.flatten.zipWithIndex - val numberedSets = rawSets - .foldLeft((numbered, Seq.empty[Seq[(LayoutSet, Int)]])) { case ((remaining, acc), sequence) => - val (current, rest) = remaining.splitAt(sequence.length) - (rest, acc :+ current) - } - ._2 - - val pipelineToIndex = pipelines.zipWithIndex.toMap - val dependencies = computeSequence.dependencies.map { case Dependency(from, fromSet, to, toSet) => - (pipelineToIndex(from), fromSet, pipelineToIndex(to), toSet) - } - val resolvedSets = dependencies - .foldLeft(numberedSets.map(_.toArray)) { case (sets, (from, fromSet, to, toSet)) => - val a = sets(from)(fromSet) - val b = sets(to)(toSet) - assert(a._1.bindings == b._1.bindings) - val nextIndex = a._2 min b._2 - sets(from).update(fromSet, (a._1, nextIndex)) - sets(to).update(toSet, (b._1, nextIndex)) - sets - } - .map(_.toSeq.map(_._2)) - - val descriptorSetMap = resolvedSets - .zip(pipelines.map(_.descriptorSetLayouts)) - .flatMap { case (sets, layouts) => - sets.zip(layouts) - } - .distinctBy(_._1) - .map { case (set, (id, layout)) => - (set, new DescriptorSet(id, layout.bindings, descriptorPool)) - } - .toMap - - pipelines.zip(resolvedSets.map(_.map(descriptorSetMap(_)))).toMap - - private val descriptorSets = pipelineToDescriptorSets.toSeq.flatMap(_._2).distinctBy(_.get) - - private def recordCommandBuffer() = pushStack: stack => - val pipelinesHasDependencies = computeSequence.dependencies.map(_.to).toSet - val commandBuffer = commandPool.createCommandBuffer() - - val commandBufferBeginInfo = VkCommandBufferBeginInfo - .calloc(stack) - .sType$Default() - .flags(0) - - check(vkBeginCommandBuffer(commandBuffer, commandBufferBeginInfo), "Failed to begin recording command buffer") - - computeSequence.sequence.foreach { case Compute(pipeline, _) => - if pipelinesHasDependencies(pipeline) then - val memoryBarrier = VkMemoryBarrier2 - .calloc(1, stack) - .sType$Default() - .srcStageMask(VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT) - .srcAccessMask(VK_ACCESS_2_SHADER_WRITE_BIT) - .dstStageMask(VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT) - .dstAccessMask(VK_ACCESS_2_SHADER_READ_BIT) - - val dependencyInfo = VkDependencyInfo - .calloc(stack) - .sType$Default() - .pMemoryBarriers(memoryBarrier) - - vkCmdPipelineBarrier2KHR(commandBuffer, dependencyInfo) - - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get) - - val pDescriptorSets = stack.longs(pipelineToDescriptorSets(pipeline).map(_.get)*) - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.pipelineLayout, 0, pDescriptorSets, null) - - vkCmdDispatch(commandBuffer, 8, 1, 1) - } - - check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") - commandBuffer - - private def createBuffers(): Map[DescriptorSet, Seq[Buffer]] = - - val setToActions = computeSequence.sequence - .collect { case Compute(pipeline, bufferActions) => - pipelineToDescriptorSets(pipeline).zipWithIndex.map { case (descriptorSet, i) => - val descriptorBufferActions = descriptorSet.bindings - .map(_.id) - .map(LayoutLocation(i, _)) - .map(bufferActions.getOrElse(_, BufferAction.DoNothing)) - (descriptorSet, descriptorBufferActions) - } - } - .flatten - .groupMapReduce(_._1)(_._2)((a, b) => a.zip(b).map(x => x._1 | x._2)) - - val setToBuffers = descriptorSets - .map(set => - val actions = setToActions(set) - val buffers = set.bindings.zip(actions).map { case (binding, action) => - binding.size match - case InputBufferSize(elemSize) => - new Buffer.DeviceBuffer(elemSize * 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | action.action) - case UniformSize(size) => - new Buffer.DeviceBuffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | action.action) - } - set.update(buffers) - (set, buffers), - ) - .toMap - - setToBuffers - - def execute(inputs: Seq[ByteBuffer]): Seq[ByteBuffer] = pushStack: stack => - timed("Vulkan full execute"): - val setToBuffers = createBuffers() - - def buffersWithAction(bufferAction: BufferAction): Seq[Buffer] = - computeSequence.sequence.collect { case x: Compute => - pipelineToDescriptorSets(x.pipeline) - .map(setToBuffers) - .zip(x.pumpLayoutLocations) - .flatMap(x => x._1.zip(x._2)) - .collect: - case (buffer, action) if (action.action & bufferAction.action) != 0 => buffer - }.flatten - - val stagingBuffer = - new Buffer.HostBuffer(inputs.map(_.remaining()).max, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - - buffersWithAction(BufferAction.LoadTo).zipWithIndex.foreach { case (buffer, i) => - Buffer.copyBuffer(inputs(i), stagingBuffer, buffer.size) - Buffer.copyBuffer(stagingBuffer, buffer, buffer.size, commandPool).block().destroy() - } - - val fence = new Fence() - val commandBuffer = recordCommandBuffer() - val pCommandBuffer = stack.callocPointer(1).put(0, commandBuffer) - val submitInfo = VkSubmitInfo - .calloc(stack) - .sType$Default() - .pCommandBuffers(pCommandBuffer) - - timed("Vulkan render command"): - check(vkQueueSubmit(queue.get, submitInfo, fence.get), "Failed to submit command buffer to queue") - fence.block().destroy() - - val output = buffersWithAction(BufferAction.LoadFrom).map { buffer => - Buffer.copyBuffer(buffer, stagingBuffer, buffer.size, commandPool).block().destroy() - val out = BufferUtils.createByteBuffer(buffer.size) - Buffer.copyBuffer(stagingBuffer, out, buffer.size) - out - } - - stagingBuffer.destroy() - commandPool.freeCommandBuffer(commandBuffer) - setToBuffers.flatMap(_._2).foreach(_.destroy()) - - output - - def destroy(): Unit = - descriptorSets.foreach(_.destroy()) - -object SequenceExecutor: - private[cyfra] case class ComputationSequence(sequence: Seq[ComputationStep], dependencies: Seq[Dependency]) - - private[cyfra] sealed trait ComputationStep - case class Compute(pipeline: ComputePipeline, bufferActions: Map[LayoutLocation, BufferAction]) extends ComputationStep: - def pumpLayoutLocations: Seq[Seq[BufferAction]] = - pipeline.layoutInfo.sets - .map(x => x.bindings.map(y => (x.id, y.id)).map(x => bufferActions.getOrElse(LayoutLocation.apply.tupled(x), BufferAction.DoNothing))) - - case class LayoutLocation(set: Int, binding: Int) - - case class Dependency(from: ComputePipeline, fromSet: Int, to: ComputePipeline, toSet: Int) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala index 60ecb48a..f8926e3d 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala @@ -15,7 +15,7 @@ import java.nio.ByteBuffer * MarconZet Created 11.05.2019 */ -private[cyfra] sealed class Buffer private (val size: Int, usage: Int, flags: Int)(using allocator: Allocator) extends VulkanObjectHandle: +private[cyfra] sealed abstract class Buffer private (val size: Int, usage: Int, flags: Int)(using allocator: Allocator) extends VulkanObjectHandle: val (handle, allocation) = pushStack: stack => val bufferInfo = VkBufferCreateInfo .calloc(stack) @@ -58,20 +58,20 @@ object Buffer: if flush then vmaFlushAllocation(this.allocator.get, this.allocation, 0, size) vmaUnmapMemory(this.allocator.get, this.allocation) - def copyBuffer(src: ByteBuffer, dst: HostBuffer, bytes: Long): Unit = + def copyBuffer(src: ByteBuffer, dst: HostBuffer, srcOffset: Int, dstOffset: Int, bytes: Int): Unit = dst.mapped: destination => - memCopy(memAddress(src), memAddress(destination), bytes) + memCopy(memAddress(src) + srcOffset, memAddress(destination) + dstOffset, bytes) - def copyBuffer(src: HostBuffer, dst: ByteBuffer, bytes: Long): Unit = + def copyBuffer(src: HostBuffer, dst: ByteBuffer, srcOffset: Int, dstOffset: Int, bytes: Int): Unit = src.mappedNoFlush: source => - memCopy(memAddress(source), memAddress(dst), bytes) + memCopy(memAddress(source) + srcOffset, memAddress(dst) + dstOffset, bytes) - def copyBuffer(src: Buffer, dst: Buffer, bytes: Long, commandPool: CommandPool): Fence = + def copyBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool): Fence = commandPool.executeCommand: commandBuffer => pushStack: stack => val copyRegion = VkBufferCopy .calloc(1, stack) - .srcOffset(0) - .dstOffset(0) + .srcOffset(srcOffset) + .dstOffset(dstOffset) .size(bytes) vkCmdCopyBuffer(commandBuffer, src.get, dst.get, copyRegion) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala index 4cb57928..093fb350 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala @@ -1,5 +1,6 @@ package io.computenode.cyfra.vulkan.memory +import io.computenode.cyfra.vulkan.compute.ComputePipeline.DescriptorSetLayout import io.computenode.cyfra.vulkan.core.Device import io.computenode.cyfra.vulkan.memory.DescriptorPool.MAX_SETS import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} @@ -14,12 +15,18 @@ object DescriptorPool: val MAX_SETS = 100 private[cyfra] class DescriptorPool(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => - val descriptorPoolSize = VkDescriptorPoolSize.calloc(1, stack) + val descriptorPoolSize = VkDescriptorPoolSize.calloc(2, stack) descriptorPoolSize - .get(0) - .`type`(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) // TODO this is sus when using with uniform buffers + .get() + .`type`(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) .descriptorCount(2 * MAX_SETS) + descriptorPoolSize + .get() + .`type`(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) + .descriptorCount(2 * MAX_SETS) + descriptorPoolSize.rewind() + val descriptorPoolCreateInfo = VkDescriptorPoolCreateInfo .calloc(stack) .sType$Default() @@ -31,5 +38,7 @@ private[cyfra] class DescriptorPool(using device: Device) extends VulkanObjectHa check(vkCreateDescriptorPool(device.get, descriptorPoolCreateInfo, null, pDescriptorPool), "Failed to create descriptor pool") pDescriptorPool.get() + def allocate(descriptorSetLayout: DescriptorSetLayout): DescriptorSet = DescriptorSet(descriptorSetLayout, this) + override protected def close(): Unit = vkDestroyDescriptorPool(device.get, handle, null) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala index 52e001a0..bd33df63 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala @@ -1,6 +1,6 @@ package io.computenode.cyfra.vulkan.memory -import io.computenode.cyfra.vulkan.compute.{Binding, InputBufferSize, LayoutSet, UniformSize} +import io.computenode.cyfra.vulkan.compute.ComputePipeline.{BindingType, DescriptorSetInfo, DescriptorSetLayout} import io.computenode.cyfra.vulkan.core.Device import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObjectHandle @@ -10,11 +10,11 @@ import org.lwjgl.vulkan.{VkDescriptorBufferInfo, VkDescriptorSetAllocateInfo, Vk /** @author * MarconZet Created 15.04.2020 */ -private[cyfra] class DescriptorSet(descriptorSetLayout: Long, val bindings: Seq[Binding], descriptorPool: DescriptorPool)(using device: Device) +private[cyfra] class DescriptorSet(descriptorSetLayout: DescriptorSetLayout, descriptorPool: DescriptorPool)(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => - val pSetLayout = stack.callocLong(1).put(0, descriptorSetLayout) + val pSetLayout = stack.callocLong(1).put(0, descriptorSetLayout.id) val descriptorSetAllocateInfo = VkDescriptorSetAllocateInfo .calloc(stack) .sType$Default() @@ -26,22 +26,23 @@ private[cyfra] class DescriptorSet(descriptorSetLayout: Long, val bindings: Seq[ pDescriptorSet.get() def update(buffers: Seq[Buffer]): Unit = pushStack: stack => + val bindings = descriptorSetLayout.set.descriptors assert(buffers.length == bindings.length, s"Number of buffers (${buffers.length}) does not match number of bindings (${bindings.length})") val writeDescriptorSet = VkWriteDescriptorSet.calloc(buffers.length, stack) - buffers.zip(bindings).foreach { case (buffer, binding) => + buffers.zip(bindings).zipWithIndex.foreach { case ((buffer, binding), idx) => val descriptorBufferInfo = VkDescriptorBufferInfo .calloc(1, stack) .buffer(buffer.get) .offset(0) .range(VK_WHOLE_SIZE) - val descriptorType = binding.size match - case InputBufferSize(elemSize) => VK_DESCRIPTOR_TYPE_STORAGE_BUFFER - case UniformSize(size) => VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER + val descriptorType = binding.kind match + case BindingType.StorageBuffer => VK_DESCRIPTOR_TYPE_STORAGE_BUFFER + case BindingType.Uniform => VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER writeDescriptorSet .get() .sType$Default() .dstSet(handle) - .dstBinding(binding.id) + .dstBinding(idx) .descriptorCount(1) .descriptorType(descriptorType) .pBufferInfo(descriptorBufferInfo) diff --git a/cyfra-vulkan/src/test/resources/copy_test.comp b/cyfra-vulkan/src/test/resources/copy_test.comp deleted file mode 100644 index 13f55532..00000000 --- a/cyfra-vulkan/src/test/resources/copy_test.comp +++ /dev/null @@ -1,15 +0,0 @@ -#version 450 - -layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in; - -layout (binding = 0, set = 0) buffer InputBuffer { - int inArray[]; -}; -layout (binding = 0, set = 1) buffer OutputBuffer { - int outArray[]; -}; - -void main(void){ - uint index = gl_GlobalInvocationID.x; - outArray[index] = inArray[index] + 10000; -} diff --git a/cyfra-vulkan/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala b/cyfra-vulkan/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala deleted file mode 100644 index 14ab3e46..00000000 --- a/cyfra-vulkan/src/test/scala/io/computenode/cyfra/vulkan/SequenceExecutorTest.scala +++ /dev/null @@ -1,35 +0,0 @@ -package io.computenode.cyfra.vulkan - -import io.computenode.cyfra.vulkan.VulkanContext -import io.computenode.cyfra.vulkan.compute.* -import io.computenode.cyfra.vulkan.core.Device -import io.computenode.cyfra.vulkan.executor.BufferAction.{LoadFrom, LoadTo} -import io.computenode.cyfra.vulkan.executor.SequenceExecutor -import io.computenode.cyfra.vulkan.executor.SequenceExecutor.{ComputationSequence, Compute, Dependency, LayoutLocation} -import munit.FunSuite -import org.lwjgl.BufferUtils - -class SequenceExecutorTest extends FunSuite: - val vulkanContext = VulkanContext() - import vulkanContext.given - - test("Memory barrier"): - val code = ComputePipeline.loadShader("copy_test.spv").get - val layout = LayoutInfo(Seq(LayoutSet(0, Seq(Binding(0, InputBufferSize(4)))), LayoutSet(1, Seq(Binding(0, InputBufferSize(4)))))) - val copy1 = new ComputePipeline(code, "main", layout) - val copy2 = new ComputePipeline(code, "main", layout) - - val sequence = - ComputationSequence( - Seq(Compute(copy1, Map(LayoutLocation(0, 0) -> LoadTo)), Compute(copy2, Map(LayoutLocation(1, 0) -> LoadFrom))), - Seq(Dependency(copy1, 1, copy2, 0)), - ) - val sequenceExecutor = new SequenceExecutor(sequence, vulkanContext) - val input = 0 until 1024 - val buffer = BufferUtils.createByteBuffer(input.length * 4) - input.foreach(buffer.putInt) - buffer.flip() - val res = sequenceExecutor.execute(Seq(buffer)) - val output = input.map(_ => res.head.getInt) - - assertEquals(input.map(_ + 20000).toList, output.toList) diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..2468070f --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1735563628, + "narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..b3691241 --- /dev/null +++ b/flake.nix @@ -0,0 +1,33 @@ +{ + description = "Dev shell for Vulkan + Java 21"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + jdk = pkgs.jdk21; + in { + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + jdk + sbt + vulkan-tools + vulkan-loader + vulkan-validation-layers + glslang + pkg-config + ]; + + JAVA_HOME = jdk; + VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d"; + LD_LIBRARY_PATH="${pkgs.vulkan-loader}/lib:${pkgs.vulkan-validation-layers}/lib:$LD_LIBRARY_PATH"; + + }; + }); +} + From da9862918aa14bb04aec5a5db0060c46c928cffa Mon Sep 17 00:00:00 2001 From: spamegg Date: Sun, 27 Jul 2025 14:25:46 +0300 Subject: [PATCH 11/59] interpreter --- .github/workflows/ci.yml | 2 + build.sbt | 8 +- .../e2e/interpreter/InterpreterTests.scala | 16 ++ .../cyfra/e2e/interpreter/SimulateTests.scala | 85 +++++++++ .../e2e/interpreter/SimulateWhenTests.scala | 93 +++++++++ .../cyfra/interpreter/Interpreter.scala | 46 +++++ .../cyfra/interpreter/Result.scala | 94 +++++++++ .../cyfra/interpreter/ScalarResult.scala | 92 +++++++++ .../cyfra/interpreter/SimContext.scala | 43 +++++ .../cyfra/interpreter/Simulate.scala | 178 ++++++++++++++++++ .../cyfra/interpreter/VectorResult.scala | 23 +++ 11 files changed, 678 insertions(+), 2 deletions(-) create mode 100644 cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala create mode 100644 cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala create mode 100644 cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Result.scala create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ScalarResult.scala create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/VectorResult.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c47d94a8..e0807fa9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,8 @@ on: tags: - "v*" pull_request: + branches: + - dev jobs: format_and_compile: diff --git a/build.sbt b/build.sbt index 35a46c2c..57673c1a 100644 --- a/build.sbt +++ b/build.sbt @@ -97,13 +97,17 @@ lazy val vscode = (project in file("cyfra-vscode")) .settings(commonSettings) .dependsOn(foton) +lazy val interpreter = (project in file("cyfra-interpreter")) + .settings(commonSettings) + .dependsOn(dsl, compiler) + lazy val e2eTest = (project in file("cyfra-e2e-test")) .settings(commonSettings, runnerSettings) - .dependsOn(runtime) + .dependsOn(runtime, interpreter) lazy val root = (project in file(".")) .settings(name := "Cyfra") - .aggregate(compiler, dsl, foton, core, runtime, vulkan, examples) + .aggregate(compiler, dsl, foton, core, runtime, vulkan, examples, interpreter) e2eTest / Test / javaOptions ++= Seq("-Dorg.lwjgl.system.stackSize=1024", "-DuniqueLibraryNames=true") diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala new file mode 100644 index 00000000..27483c16 --- /dev/null +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala @@ -0,0 +1,16 @@ +package io.computenode.cyfra.e2e.interpreter + +import io.computenode.cyfra.interpreter.*, Result.* +import io.computenode.cyfra.dsl.{*, given} +import binding.*, Value.*, gio.GIO, GIO.* +import Value.FromExpr.fromExpr, control.Scope + +class InterpreterE2eTest extends munit.FunSuite: + test("interpret should not stack overflow"): + val pure = Pure(0) + var gio = FlatMap(pure, pure) + for _ <- 0 until 1000000 do gio = FlatMap(pure, gio) + val result = Interpreter.interpret(gio, 0) + val res = 0 + val exp = 0 + assert(res == exp, s"Expected $exp, got $res") diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala new file mode 100644 index 00000000..c561c59c --- /dev/null +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala @@ -0,0 +1,85 @@ +package io.computenode.cyfra.e2e.interpreter + +import io.computenode.cyfra.interpreter.*, Result.* +import io.computenode.cyfra.dsl.{*, given}, binding.{ReadBuffer, GBuffer} +import Value.FromExpr.fromExpr, control.Scope +import izumi.reflect.Tag + +class SimulateE2eTest extends munit.FunSuite: + test("simulate binary operation arithmetic"): + val a: Int32 = 1 + val b: Int32 = 2 + val c: Int32 = 3 + val d: Int32 = 4 + val e: Int32 = 5 + val f: Int32 = 6 + val e1 = Diff(a, b) + val e2 = Sum(fromExpr(e1), c) + val e3 = Mul(f, fromExpr(e2)) + val e4 = Div(fromExpr(e3), d) + val expr = Mod(e, fromExpr(e4)) // 5 % ((6 * ((1 - 2) + 3)) / 4) + val (result, _) = Simulate.sim(expr, SimContext()) + val expected = 2 + assert(result == expected, s"Expected $expected, got $result") + + test("simulate vec4, scalar, dot, extract scalar"): + val v1 = ComposeVec4[Float32](1f, 2f, 3f, 4f) + val (res1, _) = Simulate.sim(v1, SimContext()) + val exp1 = Vector(1f, 2f, 3f, 4f) + assert(res1 == exp1, s"Expected $exp1, got $res1") + + val i: Int32 = 2 + val expr = ExtractScalar(fromExpr(v1), i) + val (res, _) = Simulate.sim(expr, SimContext()) + val exp = 3f + assert(res == exp, s"Expected $exp, got $res") + + val v2 = ScalarProd(fromExpr(v1), -1f) + val (res2, _) = Simulate.sim(v2, SimContext()) + val exp2 = Vector(-1f, -2f, -3f, -4f) + assert(res2 == exp2, s"Expected $exp2, got $res2") + + val v3 = ComposeVec4[Float32](-4f, -3f, 2f, 1f) + val dot = DotProd(fromExpr(v1), fromExpr(v3)) + val (res3a, _) = Simulate.sim(dot, SimContext()) + val res3 = res3a.asInstanceOf[Float] + val exp3 = 0f + assert(Math.abs(res3 - exp3) < 0.001f, s"Expected $exp3, got $res3") + + test("simulate bitwise ops"): + val a: Int32 = 5 + val by: UInt32 = 3 + val aNot = BitwiseNot(a) + val left = ShiftLeft(fromExpr(aNot), by) + val right = ShiftRight(fromExpr(aNot), by) + val and = BitwiseAnd(fromExpr(left), fromExpr(right)) + val or = BitwiseOr(fromExpr(left), fromExpr(right)) + val xor = BitwiseXor(fromExpr(and), fromExpr(or)) + + val (res, _) = Simulate.sim(xor, SimContext()) + val exp = ((~5 << 3) & (~5 >> 3)) ^ ((~5 << 3) | (~5 >> 3)) + assert(res == exp, s"Expected $exp, got $res") + + test("simulate should not stack overflow"): + val a: Int32 = 1 + var sum = Sum(a, a) // 2 + for _ <- 0 until 1000000 do sum = Sum(a, fromExpr(sum)) + val (res, _) = Simulate.sim(sum, SimContext()) + val exp = 1000002 + assert(res == exp, s"Expected $exp, got $res") + + test("simulate ReadBuffer"): + // We fake a GBuffer with an array + case class SimGBuffer[T <: Value: Tag: FromExpr]() extends GBuffer[T] + val buffer = SimGBuffer[Int32]() + val array = (0 until 1024).toArray[Result] + + val sc = SimContext().addBuffer(buffer, array) + + val expr = ReadBuffer(buffer, 128) + val (res, newSc) = Simulate.sim(expr, sc) + val exp = 128 + assert(res == exp, s"Expected $exp, got $res") + + // the context should keep track of the read + assert(newSc.reads.contains(ReadBuf(buffer, 128)), "missing read") diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala new file mode 100644 index 00000000..0026ebf5 --- /dev/null +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala @@ -0,0 +1,93 @@ +package io.computenode.cyfra.e2e.interpreter + +import io.computenode.cyfra.interpreter.*, Result.* +import io.computenode.cyfra.dsl.{*, given} +import Value.FromExpr.fromExpr, control.Scope, binding.{GBuffer, ReadBuffer} +import izumi.reflect.Tag + +class SimulateWhenE2eTest extends munit.FunSuite: + test("simulate when"): + val expr1 = WhenExpr( + when = 2 >= 1, // true + thenCode = Scope(ConstInt32(1)), + otherConds = List(Scope(ConstGB(3 == 2)), Scope(ConstGB(1 <= 3))), + otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), + otherwise = Scope(ConstInt32(3)), + ) + val (res1, _) = Simulate.sim(expr1, SimContext()) + val exp1 = 1 + assert(res1 == exp1, s"Expected $exp1, got $res1") + + test("simulate elseWhen first"): + val expr2 = WhenExpr( + when = 2 <= 1, // false + thenCode = Scope(ConstInt32(1)), + otherConds = List(Scope(ConstGB(3 >= 2)) /*true*/, Scope(ConstGB(1 <= 3))), + otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), + otherwise = Scope(ConstInt32(3)), + ) + val (res2, _) = Simulate.sim(expr2, SimContext()) + val exp2 = 2 + assert(res2 == exp2, s"Expected $exp2, got $res2") + + test("simulate elseWhen second"): + val expr3 = WhenExpr( + when = 2 <= 1, // false + thenCode = Scope(ConstInt32(1)), + otherConds = List(Scope(ConstGB(3 == 2)) /*false*/, Scope(ConstGB(1 <= 3))), // true + otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), + otherwise = Scope(ConstInt32(3)), + ) + val (res3, _) = Simulate.sim(expr3, SimContext()) + val exp3 = 4 + assert(res3 == exp3, s"Expected $exp3, got $res3") + + test("simulate otherwise"): + val expr4 = WhenExpr( + when = 2 <= 1, // false + thenCode = Scope(ConstInt32(1)), + otherConds = List(Scope(ConstGB(3 == 2)) /*false*/, Scope(ConstGB(1 >= 3))), // false + otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), + otherwise = Scope(ConstInt32(3)), + ) + val (res4, _) = Simulate.sim(expr4, SimContext()) + val exp4 = 3 + assert(res4 == exp4, s"Expected $exp4, got $res4") + + test("simulate mixed arithmetic, reads and when"): + case class SimGBuffer[T <: Value: Tag: FromExpr]() extends GBuffer[T] + val buffer = SimGBuffer[Int32]() + val array = (128 until 0 by -1).toArray[Result] + + val sc = SimContext().addBuffer(buffer, array) + + val a: Int32 = 32 + val b: Int32 = 64 + val c: Int32 = 4 + + val readExpr1 = ReadBuffer(buffer, a) // 96 + val expr1 = Mul(c, fromExpr(readExpr1)) // 4 * 96 = 384 + + val readExpr2 = ReadBuffer(buffer, b) // 64 + val expr2 = Sum(c, fromExpr(readExpr2)) // 4 + 64 = 68 + + val expr3 = Mod(fromExpr(expr2), 5) // 68 % 5 = 3 + + val cond1 = fromExpr(expr1) <= fromExpr(expr2) // 384 <= 68 false + val cond2 = Equal(fromExpr(expr1), fromExpr(expr2)) // 384 == 68 false + val cond3 = GreaterThanEqual(fromExpr(expr3), fromExpr(expr2)) // 3 >= 68 false + + val expr = WhenExpr( + when = cond1, // false + thenCode = Scope(expr1), + otherConds = List(Scope(cond2), Scope(cond3)), // false false + otherCaseCodes = List(Scope(expr1), Scope(expr2)), // 384, 68 + otherwise = Scope(expr3), // 3 + ) + val (res, newSc) = Simulate.sim(expr, sc) + val exp = 3 + assert(res == exp, s"Expected $exp, got $res") + + // There should be 2 reads in the simulation context + assert(newSc.reads.contains(ReadBuf(buffer, 32))) + assert(newSc.reads.contains(ReadBuf(buffer, 64))) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala new file mode 100644 index 00000000..2d53b58b --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala @@ -0,0 +1,46 @@ +package io.computenode.cyfra.interpreter + +import io.computenode.cyfra.dsl.{*, given} +import binding.*, Value.*, gio.GIO, GIO.* +import Result.Result +import izumi.reflect.Tag + +object Interpreter: + private def interpretPure(gio: Pure[?], sc: SimContext): SimContext = gio match + case Pure(value) => + val (result, newSc) = Simulate.sim(value.asInstanceOf[Value], sc) // TODO needs fixing + newSc.addResult(result) + + private def interpretWriteBuffer(gio: WriteBuffer[?], sc: SimContext): SimContext = gio match + case WriteBuffer(buffer, index, value) => + val (n, _) = Simulate.sim(index, SimContext()) // Int32, no reads/writes here, don't need resulting context + val i = n.asInstanceOf[Int] + val (res, newSc) = Simulate.sim(value, sc) + newSc.addWrite(WriteBuf(buffer, i, res)) + + private def interpretWriteUniform(gio: WriteUniform[?], sc: SimContext): SimContext = gio match + case WriteUniform(uniform, value) => + val (result, newSc) = Simulate.sim(value, sc) + newSc.addWrite(WriteUni(uniform, result)) + + private def interpretOne(gio: GIO[?], sc: SimContext): SimContext = gio match + case p: Pure[?] => interpretPure(p, sc) + case wb: WriteBuffer[?] => interpretWriteBuffer(wb, sc) + case wu: WriteUniform[?] => interpretWriteUniform(wu, sc) + case _ => throw IllegalArgumentException("interpretOne: invalid GIO") + + @annotation.tailrec + private def interpretMany(gios: List[GIO[?]], sc: SimContext): SimContext = gios match + case FlatMap(gio, next) :: tail => interpretMany(gio :: next :: tail, sc) + case Repeat(n, f) :: tail => + val (i, _) = Simulate.sim(n, SimContext()) // just Int32, no reads/writes + val int = i.asInstanceOf[Int] + val newGios = (0 until int).map(i => f(i)).toList + interpretMany(newGios ::: tail, sc) + case head :: tail => + val newSc = interpretOne(head, sc) + interpretMany(tail, newSc) + case Nil => sc + + def interpret(gio: GIO[?], invocId: Int) = InvocResult(invocId, interpretMany(List(gio), SimContext())) + def interpret(gio: GIO[?], invocIds: List[Int]): List[InvocResult] = invocIds.map(interpret(gio, _)) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Result.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Result.scala new file mode 100644 index 00000000..ad3d7634 --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Result.scala @@ -0,0 +1,94 @@ +package io.computenode.cyfra.interpreter + +object Result: + export ScalarResult.*, VectorResult.* + + type Result = ScalarRes | Vector[ScalarRes] + + extension (r: Result) + def negate: Result = r match + case s: ScalarRes => s.neg + case v: Vector[ScalarRes] => v.map(_.neg) // this is like ScalarProd + + def bitNeg: Int = r match + case sr: ScalarRes => ~sr + case _ => throw IllegalArgumentException("bitNeg: wrong argument type") + + def shiftLeft(by: Result): Int = (r, by) match + case (n: ScalarRes, b: ScalarRes) => n << b + case _ => throw IllegalArgumentException("shiftLeft: incompatible argument types") + + def shiftRight(by: Result): Int = (r, by) match + case (n: ScalarRes, b: ScalarRes) => n >> b + case _ => throw IllegalArgumentException("shiftRight: incompatible argument types") + + def bitAnd(that: Result): Int = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s & t + case _ => throw IllegalArgumentException("bitAnd: incompatible argument types") + + def bitOr(that: Result): Int = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s | t + case _ => throw IllegalArgumentException("bitOr: incompatible argument types") + + def bitXor(that: Result): Int = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s ^ t + case _ => throw IllegalArgumentException("bitXor: incompatible argument types") + + def add(that: Result): Result = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s + t + case (v: Vector[ScalarRes], t: Vector[ScalarRes]) => v add t + case _ => throw IllegalArgumentException("add: incompatible argument types") + + def sub(that: Result): Result = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s - t + case (v: Vector[ScalarRes], t: Vector[ScalarRes]) => v sub t + case _ => throw IllegalArgumentException("sub: incompatible argument types") + + def mul(that: Result): Result = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s * t + case _ => throw IllegalArgumentException("mul: incompatible argument types") + + def div(that: Result): Result = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s / t + case _ => throw IllegalArgumentException("div: incompatible argument types") + + def mod(that: Result): Result = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s % t + case _ => throw IllegalArgumentException("mod: incompatible argument types") + + def scale(that: Result): Result = (r, that) match + case (v: Vector[ScalarRes], t: ScalarRes) => v scale t + case _ => throw IllegalArgumentException("scale: incompatible argument types") + + def dot(that: Result): Result = (r, that) match + case (v: Vector[ScalarRes], t: Vector[ScalarRes]) => v dot t + case _ => throw IllegalArgumentException("dot: incompatible argument types") + + def &&(that: Result): Result = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s && t + case _ => throw IllegalArgumentException("&&: incompatible argument types") + + def ||(that: Result): Result = (r, that) match + case (s: ScalarRes, t: ScalarRes) => s || t + case _ => throw IllegalArgumentException("||: incompatible argument types") + + def gt(that: Result): Boolean = (r, that) match + case (sr: ScalarRes, t: ScalarRes) => sr > t + case _ => throw IllegalArgumentException("gt: incompatible argument types") + + def lt(that: Result): Boolean = (r, that) match + case (sr: ScalarRes, t: ScalarRes) => sr < t + case _ => throw IllegalArgumentException("lt: incompatible argument types") + + def gteq(that: Result): Boolean = (r, that) match + case (sr: ScalarRes, t: ScalarRes) => sr >= t + case _ => throw IllegalArgumentException("gteq: incompatible argument types") + + def lteq(that: Result): Boolean = (r, that) match + case (sr: ScalarRes, t: ScalarRes) => sr <= t + case _ => throw IllegalArgumentException("lteq: incompatible argument types") + + def eql(that: Result): Boolean = (r, that) match + case (sr: ScalarRes, t: ScalarRes) => sr === t + case (v: Vector[ScalarRes], t: Vector[ScalarRes]) => v eql t + case _ => throw IllegalArgumentException("eql: incompatible argument types") diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ScalarResult.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ScalarResult.scala new file mode 100644 index 00000000..8d3e537f --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ScalarResult.scala @@ -0,0 +1,92 @@ +package io.computenode.cyfra.interpreter + +object ScalarResult: + type ScalarRes = Float | Int | Boolean + + extension (sr: ScalarRes) + def neg: ScalarRes = sr match + case f: Float => -f + case n: Int => -n + case b: Boolean => !b + + infix def unary_~ : Int = sr match + case n: Int => ~n + case _ => throw IllegalArgumentException("~: wrong argument type") + + infix def <<(by: ScalarRes): Int = (sr, by) match + case (n: Int, b: Int) => n << b + case _ => throw IllegalArgumentException("<<: incompatible argument types") + + infix def >>(by: ScalarRes): Int = (sr, by) match + case (n: Int, b: Int) => n >> b + case _ => throw IllegalArgumentException(">>: incompatible argument types") + + infix def &(that: ScalarRes): Int = (sr, that) match + case (m: Int, n: Int) => m & n + case _ => throw IllegalArgumentException("&: incompatible argument types") + + infix def |(that: ScalarRes): Int = (sr, that) match + case (m: Int, n: Int) => m | n + case _ => throw IllegalArgumentException("|: incompatible argument types") + + infix def ^(that: ScalarRes): Int = (sr, that) match + case (m: Int, n: Int) => m ^ n + case _ => throw IllegalArgumentException("^: incompatible argument types") + + infix def +(that: ScalarRes): Float | Int = (sr, that) match + case (f: Float, t: Float) => f + t + case (n: Int, t: Int) => n + t + case _ => throw IllegalArgumentException("+: incompatible argument types") + + infix def -(that: ScalarRes): Float | Int = (sr, that) match + case (f: Float, t: Float) => f - t + case (n: Int, t: Int) => n - t + case _ => throw IllegalArgumentException("-: incompatible argument types") + + infix def *(that: ScalarRes): Float | Int = (sr, that) match + case (f: Float, t: Float) => f * t + case (n: Int, t: Int) => n * t + case _ => throw IllegalArgumentException("*: incompatible argument types") + + infix def /(that: ScalarRes): Float | Int = (sr, that) match + case (f: Float, t: Float) => f / t + case (n: Int, t: Int) => n / t + case _ => throw IllegalArgumentException("/: incompatible argument types") + + infix def %(that: ScalarRes): Int = (sr, that) match + case (n: Int, t: Int) => n % t + case _ => throw IllegalArgumentException("%: incompatible argument types") + + infix def &&(that: ScalarRes): Boolean = (sr, that) match + case (b: Boolean, t: Boolean) => b && t + case _ => throw IllegalArgumentException("&&: incompatible argument types") + + infix def ||(that: ScalarRes): Boolean = (sr, that) match + case (b: Boolean, t: Boolean) => b || t + case _ => throw IllegalArgumentException("||: incompatible argument types") + + infix def >(that: ScalarRes): Boolean = (sr, that) match + case (f: Float, t: Float) => f > t + case (n: Int, t: Int) => n > t + case _ => throw IllegalArgumentException(">: incompatible argument types") + + infix def <(that: ScalarRes): Boolean = (sr, that) match + case (f: Float, t: Float) => f < t + case (n: Int, t: Int) => n < t + case _ => throw IllegalArgumentException("<: incompatible argument types") + + infix def >=(that: ScalarRes): Boolean = (sr, that) match + case (f: Float, t: Float) => f >= t + case (n: Int, t: Int) => n >= t + case _ => throw IllegalArgumentException(">=: incompatible argument types") + + infix def <=(that: ScalarRes): Boolean = (sr, that) match + case (f: Float, t: Float) => f <= t + case (n: Int, t: Int) => n <= t + case _ => throw IllegalArgumentException("<=: incompatible argument types") + + infix def ===(that: ScalarRes): Boolean = (sr, that) match + case (f: Float, t: Float) => Math.abs(f - t) < 0.001f + case (n: Int, t: Int) => n == t + case (b: Boolean, t: Boolean) => b == t + case _ => throw IllegalArgumentException("===: incompatible argument types") diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala new file mode 100644 index 00000000..bd4fca94 --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala @@ -0,0 +1,43 @@ +package io.computenode.cyfra.interpreter + +import io.computenode.cyfra.dsl.{*, given} +import binding.{GBuffer, GUniform} +import Result.Result + +enum Reads: + case ReadBuf(buffer: GBuffer[?], index: Int) + case ReadUni(uniform: GUniform[?]) +export Reads.* + +enum Writes: + case WriteBuf(buffer: GBuffer[?], index: Int, value: Result) + case WriteUni(uni: GUniform[?], value: Result) +export Writes.* + +case class InvocResult(invocId: Int, sc: SimContext) + +case class SimContext( + bufMap: Map[GBuffer[?], Array[Result]] = Map(), + uniMap: Map[GUniform[?], Result] = Map(), + values: List[Result] = Nil, + writes: List[Writes] = Nil, + reads: List[Reads] = Nil, +): + def addBuffer(buffer: GBuffer[?], array: Array[Result]): SimContext = copy(bufMap = bufMap + (buffer -> array)) + + def addRead(read: Reads): SimContext = read match + case ReadBuf(buffer, index) => copy(reads = ReadBuf(buffer, index) :: reads) + case ReadUni(uniform) => copy(reads = ReadUni(uniform) :: reads) + + def addWrite(write: Writes): SimContext = write match + case WriteBuf(buffer, index, value) => + val newArray = bufMap(buffer).updated(index, value) + val newWrites = WriteBuf(buffer, index, value) :: writes + copy(bufMap = bufMap.updated(buffer, newArray), writes = newWrites) + case WriteUni(uni, value) => + val newWrites = WriteUni(uni, value) :: writes + copy(uniMap = uniMap.updated(uni, value), writes = newWrites) + + def addResult(res: Result) = copy(values = res :: values) + def lookup(buffer: GBuffer[?], index: Int): Result = bufMap(buffer)(index) + def lookupUni(uniform: GUniform[?]): Result = uniMap(uniform) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala new file mode 100644 index 00000000..16a09fdc --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala @@ -0,0 +1,178 @@ +package io.computenode.cyfra.interpreter + +import io.computenode.cyfra.dsl.{*, given} +import binding.*, macros.FnCall.FnIdentifier, control.Scope +import collections.*, GArray.GArrayElem, GSeq.{CurrentElem, AggregateElem, FoldSeq} +import struct.*, GStruct.{ComposeStruct, GetField} +import io.computenode.cyfra.spirv.BlockBuilder.buildBlock + +object Simulate: + import Result.* + + def simGroup(invocIds: List[Int], e: Expression[?]): List[InvocResult] = + val topoSortedExpressions = buildBlock(e) + invocIds.map: id => + val (res, sc) = simIterate(topoSortedExpressions, SimContext())(using Map()) + InvocResult(id, sc) + def sim(v: Value, sc: SimContext): (Result, SimContext) = sim(v.tree, sc) + def sim(e: Expression[?], sc: SimContext = SimContext()): (Result, SimContext) = simIterate(buildBlock(e), sc)(using Map()) + + @annotation.tailrec + def simIterate(blocks: List[Expression[?]], sc: SimContext)(using exprMap: Map[Int, Result]): (Result, SimContext) = blocks match + case head :: Nil => simOne(head, sc) + case head :: next => + val (result, newSc) = simOne(head, sc) // context updated if there are reads/writes + val newExprMap = exprMap + (head.treeid -> result) // update map with new result + simIterate(next, newSc)(using newExprMap) + case Nil => ??? // should not happen + + def simOne(e: Expression[?], sc: SimContext)(using exprMap: Map[Int, Result]): (Result, SimContext) = e match + case e: PhantomExpression[?] => (simPhantom(e), sc) + case Negate(a) => (simValue(a).negate, sc) + case e: BinaryOpExpression[?] => (simBinOp(e), sc) + case ScalarProd(a, b) => (simVector(a).scale(simScalar(b)), sc) + case DotProd(a, b) => (simVector(a).dot(simVector(b)), sc) + case e: BitwiseOpExpression[?] => (simBitwiseOp(e), sc) + case e: ComparisonOpExpression[?] => (simCompareOp(e), sc) + case And(a, b) => (simScalar(a) && simScalar(b), sc) + case Or(a, b) => (simScalar(a) || simScalar(b), sc) + case Not(a) => (simScalar(a).negate, sc) + case ExtractScalar(a, i) => (simVector(a).apply(simValue(i).asInstanceOf[Int]), sc) + case e: ConvertExpression[?, ?] => (simConvert(e), sc) + case e: Const[?] => (simConst(e), sc) + case ComposeVec2(a, b) => (Vector(simScalar(a), simScalar(b)), sc) + case ComposeVec3(a, b, c) => (Vector(simScalar(a), simScalar(b), simScalar(c)), sc) + case ComposeVec4(a, b, c, d) => (Vector(simScalar(a), simScalar(b), simScalar(c), simScalar(d)), sc) + case ExtFunctionCall(fn, args) => ??? // simExtFunc(fn, args.map(simValue), sc) + case FunctionCall(fn, body, args) => ??? // simFunc(fn, simScope(body), args.map(simValue), sc) + case InvocationId => ??? + case Pass(value) => ??? + case Dynamic(source) => ??? + case e: WhenExpr[?] => simWhen(e, sc) // returns new SimContext + case e: ReadBuffer[?] => simReadBuffer(e, sc) // returns new SimContext + case e: ReadUniform[?] => simReadUniform(e, sc) // returns new SimContext + case e: GArrayElem[?] => simGArrayElem(e) + case e: FoldSeq[?, ?] => simFoldSeq(e) + case e: ComposeStruct[?] => simComposeStruct(e) + case e: GetField[?, ?] => simGetField(e) + case _ => throw IllegalArgumentException("sim: wrong argument") + + private def simPhantom(e: PhantomExpression[?]): Result = e match + case CurrentElem(tid: Int) => ??? + case AggregateElem(tid: Int) => ??? + + private def simBinOp(e: BinaryOpExpression[?])(using exprMap: Map[Int, Result]): Result = e match + case Sum(a, b) => simValue(a).add(simValue(b)) // scalar or vector + case Diff(a, b) => simValue(a).sub(simValue(b)) // scalar or vector + case Mul(a, b) => simScalar(a).mul(simScalar(b)) + case Div(a, b) => simScalar(a).div(simScalar(b)) + case Mod(a, b) => simScalar(a).mod(simScalar(b)) + + private def simBitwiseOp(e: BitwiseOpExpression[?])(using exprMap: Map[Int, Result]): Int = e match + case e: BitwiseBinaryOpExpression[?] => simBitwiseBinOp(e) + case BitwiseNot(a) => simScalar(a).bitNeg + case ShiftLeft(a, by) => simScalar(a).shiftLeft(simScalar(by)) + case ShiftRight(a, by) => simScalar(a).shiftRight(simScalar(by)) + + private def simBitwiseBinOp(e: BitwiseBinaryOpExpression[?])(using exprMap: Map[Int, Result]): Int = e match + case BitwiseAnd(a, b) => simScalar(a).bitAnd(simScalar(b)) + case BitwiseOr(a, b) => simScalar(a).bitOr(simScalar(b)) + case BitwiseXor(a, b) => simScalar(a).bitXor(simScalar(b)) + + private def simCompareOp(e: ComparisonOpExpression[?])(using exprMap: Map[Int, Result]): Boolean = e match + case GreaterThan(a, b) => simScalar(a).gt(simScalar(b)) + case LessThan(a, b) => simScalar(a).lt(simScalar(b)) + case GreaterThanEqual(a, b) => simScalar(a).gteq(simScalar(b)) + case LessThanEqual(a, b) => simScalar(a).lteq(simScalar(b)) + case Equal(a, b) => simScalar(a).eql(simScalar(b)) + + private def simConvert(e: ConvertExpression[?, ?])(using exprMap: Map[Int, Result]): Float | Int = e match + case ToFloat32(a) => + exprMap(a.treeid) match + case f: Float => f + case _ => throw IllegalArgumentException("ToFloat32: wrong argument type") + case ToInt32(a) => + exprMap(a.treeid) match + case n: Int => n + case _ => throw IllegalArgumentException("ToInt32: wrong argument type") + case ToUInt32(a) => + exprMap(a.treeid) match + case n: Int => n + case _ => throw IllegalArgumentException("ToUInt32: wrong argument type") + + private def simConst(e: Const[?]): ScalarRes = e match + case ConstFloat32(value) => value + case ConstInt32(value) => value + case ConstUInt32(value) => value + case ConstGB(value) => value + + private def simValue(v: Value)(using exprMap: Map[Int, Result]): Result = v match + case v: Scalar => simScalar(v) + case v: Vec[?] => simVector(v) + + private def simScalar(v: Scalar)(using exprMap: Map[Int, Result]): ScalarRes = v match + case v: FloatType => exprMap(v.tree.treeid).asInstanceOf[Float] + case v: IntType => exprMap(v.tree.treeid).asInstanceOf[Int] + case v: UIntType => exprMap(v.tree.treeid).asInstanceOf[Int] + case GBoolean(source) => exprMap(source.treeid).asInstanceOf[Boolean] + + private def simVector(v: Vec[?])(using exprMap: Map[Int, Result]): Vector[ScalarRes] = v match + case Vec2(tree) => exprMap(tree.treeid).asInstanceOf[Vector[ScalarRes]] + case Vec3(tree) => exprMap(tree.treeid).asInstanceOf[Vector[ScalarRes]] + case Vec4(tree) => exprMap(tree.treeid).asInstanceOf[Vector[ScalarRes]] + + private def simExtFunc(fn: FunctionName, args: List[Result], sc: SimContext): (Result, SimContext) = ??? + private def simFunc(fn: FnIdentifier, body: Result, args: List[Result], sc: SimContext): (Result, SimContext) = ??? + + @annotation.tailrec + private def whenHelper( + when: Expression[GBoolean], + thenCode: Scope[?], + otherConds: List[Scope[GBoolean]], + otherCaseCodes: List[Scope[?]], + otherwise: Scope[?], + sc: SimContext, + ): (Result, SimContext) = + // scopes are not included in the "main" exprMap, they have to be simulated from scratch. + // there could be reads/writes happening in scopes, SimContext has to be updated. + val (boolRes, newSc) = sim(when, sc) + if boolRes.asInstanceOf[Boolean] then sim(thenCode.expr, newSc) + else + otherConds.headOption match + case None => sim(otherwise.expr, newSc) + case Some(cond) => + whenHelper( + when = cond.expr, + thenCode = otherCaseCodes.head, + otherConds = otherConds.tail, + otherCaseCodes = otherCaseCodes.tail, + otherwise = otherwise, + sc = newSc, + ) + + private def simWhen(e: WhenExpr[?], sc: SimContext): (Result, SimContext) = e match + case WhenExpr(when, thenCode, otherConds, otherCaseCodes, otherwise) => + whenHelper(when.tree, thenCode, otherConds, otherCaseCodes, otherwise, sc) + + private def simReadBuffer(e: ReadBuffer[?], sc: SimContext)(using exprMap: Map[Int, Result]): (Result, SimContext) = e match + case ReadBuffer(buffer, index) => + val i = exprMap(index.tree.treeid).asInstanceOf[Int] + val newSc = sc.addRead(ReadBuf(buffer, i)) + (newSc.lookup(buffer, i), newSc) + + private def simReadUniform(uni: ReadUniform[?], sc: SimContext): (Result, SimContext) = uni match + case ReadUniform(uniform) => + val newSc = sc.addRead(ReadUni(uniform)) + (newSc.lookupUni(uniform), newSc) + + private def simGArrayElem(gElem: GArrayElem[?]): (Result, SimContext) = gElem match + case GArrayElem(index, i) => ??? + + private def simFoldSeq(seq: FoldSeq[?, ?]): (Result, SimContext) = seq match + case FoldSeq(zero, fn, seq) => ??? + + private def simComposeStruct(cs: ComposeStruct[?]): (Result, SimContext) = cs match + case ComposeStruct(fields, resultSchema) => ??? + + private def simGetField(gf: GetField[?, ?]): (Result, SimContext) = gf match + case GetField(struct, fieldIndex) => ??? diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/VectorResult.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/VectorResult.scala new file mode 100644 index 00000000..dde9ce36 --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/VectorResult.scala @@ -0,0 +1,23 @@ +package io.computenode.cyfra.interpreter + +object VectorResult: + import ScalarResult.* + + extension (v: Vector[ScalarRes]) + infix def add(that: Vector[ScalarRes]) = v.zip(that).map(_ + _) + infix def sub(that: Vector[ScalarRes]) = v.zip(that).map(_ - _) + infix def eql(that: Vector[ScalarRes]): Boolean = v.zip(that).forall(_ === _) + infix def scale(s: ScalarRes) = v.map(_ * s) + + def sumRes: Float | Int = v.headOption match + case None => 0 + case Some(value) => + value match + case f: Float => v.asInstanceOf[Vector[Float]].sum + case n: Int => v.asInstanceOf[Vector[Int]].sum + case b: Boolean => throw IllegalArgumentException("sumRes: cannot add booleans") + + infix def dot(that: Vector[ScalarRes]): Float | Int = v + .zip(that) + .map(_ * _) + .sumRes From 24678fc4fab27fdef49de97a5070c8cb030c48d7 Mon Sep 17 00:00:00 2001 From: spamegg Date: Sun, 27 Jul 2025 14:43:59 +0300 Subject: [PATCH 12/59] Fs2 interop --- .github/workflows/ci.yml | 2 + build.sbt | 10 ++- .../cyfra/core/layout/LayoutStruct.scala | 4 +- .../cyfra/e2e/fs2interop/Fs2Tests.scala | 84 +++++++++++++++++ .../computenode/cyfra/fs2interop/Bridge.scala | 58 ++++++++++++ .../computenode/cyfra/fs2interop/GPipe.scala | 90 +++++++++++++++++++ 6 files changed, 244 insertions(+), 4 deletions(-) create mode 100644 cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala create mode 100644 cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala create mode 100644 cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c47d94a8..e0807fa9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,8 @@ on: tags: - "v*" pull_request: + branches: + - dev jobs: format_and_compile: diff --git a/build.sbt b/build.sbt index 35a46c2c..d9e1687c 100644 --- a/build.sbt +++ b/build.sbt @@ -58,6 +58,8 @@ lazy val commonSettings = Seq( lazy val runnerSettings = Seq(libraryDependencies += "org.apache.logging.log4j" % "log4j-slf4j2-impl" % "2.24.3") +lazy val fs2Settings = Seq(libraryDependencies ++= Seq("co.fs2" %% "fs2-core" % "3.12.0", "co.fs2" %% "fs2-io" % "3.12.0")) + lazy val utility = (project in file("cyfra-utility")) .settings(commonSettings) @@ -97,13 +99,17 @@ lazy val vscode = (project in file("cyfra-vscode")) .settings(commonSettings) .dependsOn(foton) +lazy val fs2interop = (project in file("cyfra-fs2")) + .settings(commonSettings, fs2Settings) + .dependsOn(runtime) + lazy val e2eTest = (project in file("cyfra-e2e-test")) .settings(commonSettings, runnerSettings) - .dependsOn(runtime) + .dependsOn(runtime, fs2interop) lazy val root = (project in file(".")) .settings(name := "Cyfra") - .aggregate(compiler, dsl, foton, core, runtime, vulkan, examples) + .aggregate(compiler, dsl, foton, core, runtime, vulkan, examples, fs2interop) e2eTest / Test / javaOptions ++= Seq("-Dorg.lwjgl.system.stackSize=1024", "-DuniqueLibraryNames=true") diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala index 3d79b409..f9bd8247 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala @@ -60,11 +60,11 @@ object LayoutStruct: ftype match case '[type tg <: GBuffer[?]; tg] => '{ - BufferRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }) + BufferRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using ${ tag.asExprOf[Tag[t]] }, ${ fromExpr.asExprOf[FromExpr[t]] }) } case '[type tg <: GUniform[?]; tg] => '{ - UniformRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }) + UniformRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using ${ tag.asExprOf[Tag[t]] }, ${ fromExpr.asExprOf[FromExpr[t]] }) } val constructor = sym.primaryConstructor diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala new file mode 100644 index 00000000..2339a22f --- /dev/null +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala @@ -0,0 +1,84 @@ +package io.computenode.cyfra.e2e.fs2interop + +import io.computenode.cyfra.core.archive.*, mem.*, GMem.fRGBA +import io.computenode.cyfra.dsl.{*, given}, algebra.VectorAlgebra +import io.computenode.cyfra.fs2interop.*, GPipe.*, Bridge.given +import io.computenode.cyfra.core.CyfraRuntime +import io.computenode.cyfra.runtime.VkCyfraRuntime + +import fs2.{io as fs2io, *} + +extension (f: fRGBA) + def neg = (-f._1, -f._2, -f._3, -f._4) + def scl(s: Float) = (f._1 * s, f._2 * s, f._3 * s, f._4 * s) + def add(g: fRGBA) = (f._1 + g._1, f._2 + g._2, f._3 + g._3, f._4 + g._4) + def close(g: fRGBA)(eps: Float): Boolean = + Math.abs(f._1 - g._1) < eps && Math.abs(f._2 - g._2) < eps && Math.abs(f._3 - g._3) < eps && Math.abs(f._4 - g._4) < eps + +class Fs2Tests extends munit.FunSuite: + given cr: CyfraRuntime = VkCyfraRuntime() + + test("fs2 through gPipeMap, just ints"): + val inSeq = (0 until 256).toSeq + val stream = Stream.emits(inSeq) + val pipe = gPipeMap[Pure, Int32, Int](_ + 1) + val result = stream.through(pipe).compile.toList + val expected = inSeq.map(_ + 1) + result + .zip(expected) + .foreach: (res, exp) => + assert(res == exp, s"Expected $exp, got $res") + + test("fs2 through gPipeMap, floats and vectors"): + val inSeq = (0 to 255).map(_.toFloat).toSeq + val stream = Stream.emits(inSeq) + val pipe = gPipeMap[Pure, Float32, Vec4[Float32], Float, fRGBA](f => (f, f + 1f, f + 2f, f + 3f)) + val result = stream.through(pipe).compile.toList + val expected = inSeq.map(f => (f, f + 1f, f + 2f, f + 3f)) + result + .zip(expected) + .foreach: (res, exp) => + assert(res.close(exp)(0.001f), s"Expected $exp, got $res") + +class Fs2LegacyTests extends munit.FunSuite: + given gc: GContext = GContext() + + test("fs2 Float stream (legacy)"): + val inSeq = (0 to 255).map(_.toFloat) + val inStream = Stream.emits(inSeq) + val outStream = inStream.gPipeFloat(_ + 1f).toList + val expected = inStream.map(_ + 1f).toList + outStream + .zip(expected) + .foreach: (res, exp) => + assert(Math.abs(res - exp) < 0.001f, s"Expected $exp but got $res") + + test("fs2 Int stream (legacy)"): + val inSeq = 0 to 255 + val inStream = Stream.emits(inSeq) + val outStream = inStream.gPipeInt(_ + 1).toList + val expected = inStream.map(_ + 1).toList + outStream + .zip(expected) + .foreach: (res, exp) => + assert(res == exp, s"Expected $exp but got $res") + + test("fs2 Vec4Float stream (legacy)"): + val k = -2.1f + val f = (1.2f, 2.3f, 3.4f, 4.5f) + val v = VectorAlgebra.vec4.tupled(f) + + val inSeq: Seq[fRGBA] = (0 to 1023) + .map(_.toFloat) + .grouped(4) + .map: + case Seq(a, b, c, d) => (a, b, c, d) + .toSeq + val inStream = Stream.emits(inSeq) + val outStream = inStream.gPipeVec4(vec => (-vec).*(k).+(v)).toList + val expected = inStream.map(vec => vec.neg.scl(k).add(f)).toList + + outStream + .zip(expected) + .foreach: (res, exp) => + assert(res.close(exp)(0.001f), s"Expected $exp but got $res") diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala new file mode 100644 index 00000000..41d366c3 --- /dev/null +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala @@ -0,0 +1,58 @@ +package io.computenode.cyfra.fs2interop + +import io.computenode.cyfra.core.archive.mem.GMem.fRGBA +import io.computenode.cyfra.dsl.* + +import fs2.* +import java.nio.ByteBuffer +import org.lwjgl.BufferUtils +import izumi.reflect.Tag + +import scala.reflect.ClassTag + +trait Bridge[CyfraType <: Value: FromExpr: Tag, ScalaType: ClassTag]: + def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[ScalaType]): ByteBuffer + def fromByteBuffer(outBuf: ByteBuffer, arr: Array[ScalaType]): Array[ScalaType] + +object Bridge: + given Bridge[Int32, Int]: + def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[Int]): ByteBuffer = + inBuf.asIntBuffer().put(chunk.toArray[Int]).flip() + inBuf + def fromByteBuffer(outBuf: ByteBuffer, arr: Array[Int]): Array[Int] = + outBuf.asIntBuffer().get(arr).flip() + arr + + given Bridge[Float32, Float]: + def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[Float]): ByteBuffer = + inBuf.asFloatBuffer().put(chunk.toArray[Float]).flip() + inBuf + def fromByteBuffer(outBuf: ByteBuffer, arr: Array[Float]): Array[Float] = + outBuf.asFloatBuffer().get(arr).flip() + arr + + given Bridge[Vec4[Float32], fRGBA]: + def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[fRGBA]): ByteBuffer = + val vecs = chunk.toArray[fRGBA] + vecs.foreach: + case (x, y, z, a) => + inBuf.putFloat(x) + inBuf.putFloat(y) + inBuf.putFloat(z) + inBuf.putFloat(a) + inBuf.flip() + inBuf + + def fromByteBuffer(outBuf: ByteBuffer, arr: Array[fRGBA]): Array[fRGBA] = + val res = outBuf.asFloatBuffer() + for i <- 0 until arr.size do arr(i) = (res.get(), res.get(), res.get(), res.get()) + outBuf.flip() + arr + + given Bridge[GBoolean, Boolean]: + def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[Boolean]): ByteBuffer = + inBuf.put(chunk.toArray.asInstanceOf[Array[Byte]]).flip() + inBuf + def fromByteBuffer(outBuf: ByteBuffer, arr: Array[Boolean]): Array[Boolean] = + outBuf.get(arr.asInstanceOf[Array[Byte]]).flip() + arr diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala new file mode 100644 index 00000000..d3868465 --- /dev/null +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -0,0 +1,90 @@ +package io.computenode.cyfra.fs2interop + +import io.computenode.cyfra.core.archive.*, mem.*, GMem.fRGBA +import io.computenode.cyfra.core.{Allocation, layout}, layout.Layout +import io.computenode.cyfra.core.{CyfraRuntime, GBufferRegion, GExecution, GProgram} +import io.computenode.cyfra.dsl.{*, given}, gio.GIO, binding.GBuffer +import io.computenode.cyfra.spirv.SpirvTypes.typeStride +import struct.GStruct, GStruct.Empty, Empty.given + +import fs2.* +import java.nio.ByteBuffer +import org.lwjgl.BufferUtils +import izumi.reflect.Tag + +import scala.reflect.ClassTag + +object GPipe: + def gPipeMap[F[_], C1 <: Value: FromExpr: Tag, C2 <: Value: FromExpr: Tag, S1: ClassTag, S2: ClassTag]( + f: C1 => C2, + )(using cr: CyfraRuntime, bridge1: Bridge[C1, S1], bridge2: Bridge[C2, S2]): Pipe[F, S1, S2] = + (stream: Stream[F, S1]) => + case class Params(inSize: Int) + case class PLayout(in: GBuffer[C1], out: GBuffer[C2]) extends Layout + case class PResult(out: GBuffer[C2]) extends Layout + + val params = Params(inSize = 256) + val inTypeSize = typeStride(Tag.apply[C1]) + val outTypeSize = typeStride(Tag.apply[C2]) + + val gProg = GProgram[Params, PLayout]( + layout = params => PLayout(in = GBuffer[C1](params.inSize), out = GBuffer[C2](params.inSize)), + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), + ): layout => + val invocId = GIO.invocationId + val element = GIO.read[C1](layout.in, invocId) + GIO.write[C2](layout.out, invocId, f(element)) // implicit bug + + val execution = GExecution[Params, PLayout]() + .addProgram(gProg)(params => Params(params.inSize), layout => PLayout(layout.in, layout.out)) + + val region = GBufferRegion + .allocate[PLayout] // implicit bug + .map: pLayout => + execution.execute(params, pLayout) // implicit bug + + // these are allocated once, reused for many chunks + val inBuf = BufferUtils.createByteBuffer(params.inSize * inTypeSize) + val outBuf = BufferUtils.createByteBuffer(params.inSize * outTypeSize) + + stream + .chunkMin(params.inSize) + .flatMap: chunk => + bridge1.toByteBuffer(inBuf, chunk) + region.runUnsafe(init = PLayout(in = GBuffer[C1](inBuf), out = GBuffer[C2](outBuf)), onDone = layout => layout.out.read(outBuf)) // implicit bug + Stream.emits(bridge2.fromByteBuffer(outBuf, new Array[S2](params.inSize))) + + // Syntax sugar for convenient single type version + def gPipeMap[F[_], C <: Value: FromExpr: Tag, S: ClassTag](f: C => C)(using CyfraRuntime, Bridge[C, S]): Pipe[F, S, S] = + gPipeMap[F, C, C, S, S](f) + + // legacy stuff working with GFunction + extension (stream: Stream[Pure, Float]) + def gPipeFloat(fn: Float32 => Float32)(using GContext): Stream[Pure, Float] = + val gf: GFunction[Empty, Float32, Float32] = GFunction(fn) + stream + .chunkMin(256) + .flatMap: chunk => + val gmem = FloatMem(chunk.toArray) + val res = gmem.map(gf).asInstanceOf[FloatMem].toArray + Stream.emits(res) + + extension (stream: Stream[Pure, Int]) + def gPipeInt(fn: Int32 => Int32)(using GContext): Stream[Pure, Int] = + val gf: GFunction[Empty, Int32, Int32] = GFunction(fn) + stream + .chunkMin(256) + .flatMap: chunk => + val gmem = IntMem(chunk.toArray) + val res = gmem.map(gf).asInstanceOf[IntMem].toArray + Stream.emits(res) + + extension (stream: Stream[Pure, fRGBA]) + def gPipeVec4(fn: Vec4[Float32] => Vec4[Float32])(using GContext): Stream[Pure, fRGBA] = + val gf: GFunction[Empty, Vec4[Float32], Vec4[Float32]] = GFunction(fn) + stream + .chunkMin(256) + .flatMap: chunk => + val gmem = Vec4FloatMem(chunk.toArray) + val res = gmem.map(gf).asInstanceOf[Vec4FloatMem].toArray + Stream.emits(res) From ff40778ea4e49626e2eaa4243626010b4069998f Mon Sep 17 00:00:00 2001 From: spamegg Date: Thu, 31 Jul 2025 18:11:46 +0300 Subject: [PATCH 13/59] redesign and big refactor, finish when simulation --- .../cyfra/interpreter/Interpreter.scala | 24 +- .../cyfra/interpreter/ReadWrite.scala | 14 + .../cyfra/interpreter/Record.scala | 28 ++ .../cyfra/interpreter/Result.scala | 4 +- .../cyfra/interpreter/ScalarResult.scala | 4 +- .../cyfra/interpreter/SimContext.scala | 44 +-- .../cyfra/interpreter/SimRes.scala | 11 + .../cyfra/interpreter/Simulate.scala | 252 ++++++++++-------- 8 files changed, 215 insertions(+), 166 deletions(-) create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimRes.scala diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala index 2d53b58b..57d9caa5 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala @@ -2,26 +2,28 @@ package io.computenode.cyfra.interpreter import io.computenode.cyfra.dsl.{*, given} import binding.*, Value.*, gio.GIO, GIO.* -import Result.Result import izumi.reflect.Tag object Interpreter: private def interpretPure(gio: Pure[?], sc: SimContext): SimContext = gio match case Pure(value) => - val (result, newSc) = Simulate.sim(value.asInstanceOf[Value], sc) // TODO needs fixing - newSc.addResult(result) + val SimRes(results, records, newSc) = Simulate.sim(value.asInstanceOf[Value]) // TODO needs fixing + // newSc.addResult(result) + ??? private def interpretWriteBuffer(gio: WriteBuffer[?], sc: SimContext): SimContext = gio match case WriteBuffer(buffer, index, value) => - val (n, _) = Simulate.sim(index, SimContext()) // Int32, no reads/writes here, don't need resulting context + val SimRes(n, _, _) = Simulate.sim(index) // Int32, no reads/writes here, don't need resulting context val i = n.asInstanceOf[Int] - val (res, newSc) = Simulate.sim(value, sc) - newSc.addWrite(WriteBuf(buffer, i, res)) + val SimRes(res, _, newSc) = Simulate.sim(value) + // newSc.addWrite(WriteBuf(buffer, i, res)) + ??? private def interpretWriteUniform(gio: WriteUniform[?], sc: SimContext): SimContext = gio match case WriteUniform(uniform, value) => - val (result, newSc) = Simulate.sim(value, sc) - newSc.addWrite(WriteUni(uniform, result)) + val SimRes(result, _, newSc) = Simulate.sim(value) + // newSc.addWrite(WriteUni(uniform, result)) + ??? private def interpretOne(gio: GIO[?], sc: SimContext): SimContext = gio match case p: Pure[?] => interpretPure(p, sc) @@ -33,7 +35,7 @@ object Interpreter: private def interpretMany(gios: List[GIO[?]], sc: SimContext): SimContext = gios match case FlatMap(gio, next) :: tail => interpretMany(gio :: next :: tail, sc) case Repeat(n, f) :: tail => - val (i, _) = Simulate.sim(n, SimContext()) // just Int32, no reads/writes + val SimRes(i, _, _) = Simulate.sim(n) // just Int32, no reads/writes val int = i.asInstanceOf[Int] val newGios = (0 until int).map(i => f(i)).toList interpretMany(newGios ::: tail, sc) @@ -42,5 +44,5 @@ object Interpreter: interpretMany(tail, newSc) case Nil => sc - def interpret(gio: GIO[?], invocId: Int) = InvocResult(invocId, interpretMany(List(gio), SimContext())) - def interpret(gio: GIO[?], invocIds: List[Int]): List[InvocResult] = invocIds.map(interpret(gio, _)) + def interpret(gio: GIO[?], invocId: Int) = (invocId, interpretMany(List(gio), SimContext())) + def interpret(gio: GIO[?], invocIds: List[Int]): List[(Int, SimContext)] = invocIds.map(interpret(gio, _)) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala new file mode 100644 index 00000000..614d502e --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala @@ -0,0 +1,14 @@ +package io.computenode.cyfra.interpreter + +import io.computenode.cyfra.dsl.{*, given} +import binding.{GBuffer, GUniform} + +enum Read: + case ReadBuf(id: Int, buffer: GBuffer[?], index: Int, value: Result) + case ReadUni(id: Int, uniform: GUniform[?], value: Result) +export Read.* + +enum Write: + case WriteBuf(id: Int, buffer: GBuffer[?], index: Int, value: Result) + case WriteUni(id: Int, uni: GUniform[?], value: Result) +export Write.* diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala new file mode 100644 index 00000000..6bbe111e --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala @@ -0,0 +1,28 @@ +package io.computenode.cyfra.interpreter + +import io.computenode.cyfra.dsl.{*, given} +import binding.{GBuffer, GUniform} + +type TreeId = Int +type Cache = Map[TreeId, Result] + +type InvocId = Int +type Records = Map[InvocId, Record] + +case class Record(cache: Cache = Map(), writes: List[Write] = Nil, reads: List[Read] = Nil): + def addRead(read: Read): Record = read match + case ReadBuf(_, _, _, _) => copy(reads = read :: reads) + case ReadUni(_, _, _) => copy(reads = read :: reads) + + def addWrite(write: Write): Record = write match + case WriteBuf(_, _, _, _) => copy(writes = write :: writes) + case WriteUni(_, _, _) => copy(writes = write :: writes) + + def addResult(treeId: TreeId, res: Result) = copy(cache = cache.updated(treeId, res)) + +extension (records: Records) + def updateResults(treeid: TreeId, results: Results): Records = + records.map: (invocId, record) => + results.get(invocId) match + case None => invocId -> record + case Some(value) => invocId -> record.addResult(treeid, value) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Result.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Result.scala index ad3d7634..233eac74 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Result.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Result.scala @@ -1,10 +1,10 @@ package io.computenode.cyfra.interpreter +type Result = ScalarRes | Vector[ScalarRes] + object Result: export ScalarResult.*, VectorResult.* - type Result = ScalarRes | Vector[ScalarRes] - extension (r: Result) def negate: Result = r match case s: ScalarRes => s.neg diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ScalarResult.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ScalarResult.scala index 8d3e537f..03b61802 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ScalarResult.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ScalarResult.scala @@ -1,8 +1,8 @@ package io.computenode.cyfra.interpreter -object ScalarResult: - type ScalarRes = Float | Int | Boolean +type ScalarRes = Float | Int | Boolean +object ScalarResult: extension (sr: ScalarRes) def neg: ScalarRes = sr match case f: Float => -f diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala index bd4fca94..4df3096a 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala @@ -2,42 +2,16 @@ package io.computenode.cyfra.interpreter import io.computenode.cyfra.dsl.{*, given} import binding.{GBuffer, GUniform} -import Result.Result -enum Reads: - case ReadBuf(buffer: GBuffer[?], index: Int) - case ReadUni(uniform: GUniform[?]) -export Reads.* +case class SimContext(bufMap: Map[GBuffer[?], Array[Result]] = Map(), uniMap: Map[GUniform[?], Result] = Map()): + def addBuffer(buffer: GBuffer[?], array: Array[Result]) = copy(bufMap = bufMap + (buffer -> array)) + def addUniform(uniform: GUniform[?], value: Result) = copy(uniMap = uniMap + (uniform -> value)) -enum Writes: - case WriteBuf(buffer: GBuffer[?], index: Int, value: Result) - case WriteUni(uni: GUniform[?], value: Result) -export Writes.* - -case class InvocResult(invocId: Int, sc: SimContext) - -case class SimContext( - bufMap: Map[GBuffer[?], Array[Result]] = Map(), - uniMap: Map[GUniform[?], Result] = Map(), - values: List[Result] = Nil, - writes: List[Writes] = Nil, - reads: List[Reads] = Nil, -): - def addBuffer(buffer: GBuffer[?], array: Array[Result]): SimContext = copy(bufMap = bufMap + (buffer -> array)) - - def addRead(read: Reads): SimContext = read match - case ReadBuf(buffer, index) => copy(reads = ReadBuf(buffer, index) :: reads) - case ReadUni(uniform) => copy(reads = ReadUni(uniform) :: reads) - - def addWrite(write: Writes): SimContext = write match - case WriteBuf(buffer, index, value) => - val newArray = bufMap(buffer).updated(index, value) - val newWrites = WriteBuf(buffer, index, value) :: writes - copy(bufMap = bufMap.updated(buffer, newArray), writes = newWrites) - case WriteUni(uni, value) => - val newWrites = WriteUni(uni, value) :: writes - copy(uniMap = uniMap.updated(uni, value), writes = newWrites) - - def addResult(res: Result) = copy(values = res :: values) def lookup(buffer: GBuffer[?], index: Int): Result = bufMap(buffer)(index) def lookupUni(uniform: GUniform[?]): Result = uniMap(uniform) + + def addWrite(write: Write): SimContext = write match + case WriteBuf(_, buffer, index, value) => + val newArray = bufMap(buffer).updated(index, value) + copy(bufMap = bufMap.updated(buffer, newArray)) + case WriteUni(_, uni, value) => copy(uniMap = uniMap.updated(uni, value)) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimRes.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimRes.scala new file mode 100644 index 00000000..4b039a66 --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimRes.scala @@ -0,0 +1,11 @@ +package io.computenode.cyfra.interpreter + +type Results = Map[InvocId, Result] + +extension (r: Results) + // assumes both results have the same set of keys. + def join(that: Results)(op: (Result, Result) => Result): Results = + r.map: (invocId, res) => + invocId -> op(res, that(invocId)) + +case class SimRes(results: Results = Map(), records: Records = Map(), sc: SimContext = SimContext()) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala index 16a09fdc..d7f9fdf9 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala @@ -9,137 +9,150 @@ import io.computenode.cyfra.spirv.BlockBuilder.buildBlock object Simulate: import Result.* - def simGroup(invocIds: List[Int], e: Expression[?]): List[InvocResult] = - val topoSortedExpressions = buildBlock(e) - invocIds.map: id => - val (res, sc) = simIterate(topoSortedExpressions, SimContext())(using Map()) - InvocResult(id, sc) - def sim(v: Value, sc: SimContext): (Result, SimContext) = sim(v.tree, sc) - def sim(e: Expression[?], sc: SimContext = SimContext()): (Result, SimContext) = simIterate(buildBlock(e), sc)(using Map()) + def sim(v: Value, records: Records = Map())(using sc: SimContext = SimContext()): SimRes = sim(v.tree, records) + def sim(e: Expression[?], records: Records)(using SimContext): SimRes = simIterate(buildBlock(e), records) @annotation.tailrec - def simIterate(blocks: List[Expression[?]], sc: SimContext)(using exprMap: Map[Int, Result]): (Result, SimContext) = blocks match - case head :: Nil => simOne(head, sc) - case head :: next => - val (result, newSc) = simOne(head, sc) // context updated if there are reads/writes - val newExprMap = exprMap + (head.treeid -> result) // update map with new result - simIterate(next, newSc)(using newExprMap) - case Nil => ??? // should not happen - - def simOne(e: Expression[?], sc: SimContext)(using exprMap: Map[Int, Result]): (Result, SimContext) = e match - case e: PhantomExpression[?] => (simPhantom(e), sc) - case Negate(a) => (simValue(a).negate, sc) - case e: BinaryOpExpression[?] => (simBinOp(e), sc) - case ScalarProd(a, b) => (simVector(a).scale(simScalar(b)), sc) - case DotProd(a, b) => (simVector(a).dot(simVector(b)), sc) - case e: BitwiseOpExpression[?] => (simBitwiseOp(e), sc) - case e: ComparisonOpExpression[?] => (simCompareOp(e), sc) - case And(a, b) => (simScalar(a) && simScalar(b), sc) - case Or(a, b) => (simScalar(a) || simScalar(b), sc) - case Not(a) => (simScalar(a).negate, sc) - case ExtractScalar(a, i) => (simVector(a).apply(simValue(i).asInstanceOf[Int]), sc) - case e: ConvertExpression[?, ?] => (simConvert(e), sc) - case e: Const[?] => (simConst(e), sc) - case ComposeVec2(a, b) => (Vector(simScalar(a), simScalar(b)), sc) - case ComposeVec3(a, b, c) => (Vector(simScalar(a), simScalar(b), simScalar(c)), sc) - case ComposeVec4(a, b, c, d) => (Vector(simScalar(a), simScalar(b), simScalar(c), simScalar(d)), sc) - case ExtFunctionCall(fn, args) => ??? // simExtFunc(fn, args.map(simValue), sc) - case FunctionCall(fn, body, args) => ??? // simFunc(fn, simScope(body), args.map(simValue), sc) - case InvocationId => ??? + def simIterate(blocks: List[Expression[?]], records: Records, results: Results = Map())(using sc: SimContext): SimRes = blocks match + case head :: next => // reads have to be treated specially, since they will update the records + val (newResults, records1) = head match + case e: ReadBuffer[?] => simReadBuffer(e, records) // records updated with reads + case e: ReadUniform[?] => simReadUniform(e, records) // records updated with reads + case e: WhenExpr[?] => simWhen(e, records) + case _ => (simOne(head)(using records), records) // no reads, records not updated + val newRecords = records1.updateResults(head.treeid, newResults) // update caches with new results + simIterate(next, newRecords, newResults) + case Nil => SimRes(results, records, sc) + + def simOne(e: Expression[?])(using records: Records, sc: SimContext): Results = e match + case e: PhantomExpression[?] => simPhantom(e) + case Negate(a) => simValue(a).view.mapValues(_.negate).toMap + case e: BinaryOpExpression[?] => simBinOp(e) + case ScalarProd(a, b) => simVector(a).join(simScalar(b))(_.scale(_)) + case DotProd(a, b) => simVector(a).join(simVector(b))(_.dot(_)) + case e: BitwiseOpExpression[?] => simBitwiseOp(e) + case e: ComparisonOpExpression[?] => simCompareOp(e) + case And(a, b) => simScalar(a).join(simScalar(b))(_ && _) + case Or(a, b) => simScalar(a).join(simScalar(b))(_ || _) + case Not(a) => simScalar(a).view.mapValues(_.negate).toMap + case ExtractScalar(a, i) => + val (aRes, iRes) = (simVector(a), simValue(i)) + aRes.map((invocId, vector) => invocId -> vector.apply(iRes(invocId).asInstanceOf[Int])) + case e: ConvertExpression[?, ?] => simConvert(e) + case e: Const[?] => simConst(e) + case ComposeVec2(a, b) => + val (aRes, bRes) = (simScalar(a), simScalar(b)) + aRes.map((invocId, ar) => invocId -> Vector(ar, bRes(invocId))) + case ComposeVec3(a, b, c) => + val (aRes, bRes, cRes) = (simScalar(a), simScalar(b), simScalar(c)) + records.keys + .map: invocId => + invocId -> Vector(aRes(invocId), bRes(invocId), cRes(invocId)) + .toMap + case ComposeVec4(a, b, c, d) => + val (aRes, bRes, cRes, dRes) = (simScalar(a), simScalar(b), simScalar(c), simScalar(d)) + records.keys + .map: invocId => + invocId -> Vector(aRes(invocId), bRes(invocId), cRes(invocId), dRes(invocId)) + .toMap + case ExtFunctionCall(fn, args) => ??? // simExtFunc(fn, args.map(simValue) + case FunctionCall(fn, body, args) => ??? // simFunc(fn, simScope(body), args.map(simValue) + case InvocationId => simInvocId(records) case Pass(value) => ??? case Dynamic(source) => ??? - case e: WhenExpr[?] => simWhen(e, sc) // returns new SimContext - case e: ReadBuffer[?] => simReadBuffer(e, sc) // returns new SimContext - case e: ReadUniform[?] => simReadUniform(e, sc) // returns new SimContext case e: GArrayElem[?] => simGArrayElem(e) case e: FoldSeq[?, ?] => simFoldSeq(e) case e: ComposeStruct[?] => simComposeStruct(e) case e: GetField[?, ?] => simGetField(e) case _ => throw IllegalArgumentException("sim: wrong argument") - private def simPhantom(e: PhantomExpression[?]): Result = e match + private def simPhantom(e: PhantomExpression[?])(using Records): Results = e match case CurrentElem(tid: Int) => ??? case AggregateElem(tid: Int) => ??? - private def simBinOp(e: BinaryOpExpression[?])(using exprMap: Map[Int, Result]): Result = e match - case Sum(a, b) => simValue(a).add(simValue(b)) // scalar or vector - case Diff(a, b) => simValue(a).sub(simValue(b)) // scalar or vector - case Mul(a, b) => simScalar(a).mul(simScalar(b)) - case Div(a, b) => simScalar(a).div(simScalar(b)) - case Mod(a, b) => simScalar(a).mod(simScalar(b)) + private def simBinOp(e: BinaryOpExpression[?])(using Records): Results = e match + case Sum(a, b) => simValue(a).join(simValue(b))(_.add(_)) // scalar or vector + case Diff(a, b) => simValue(a).join(simValue(b))(_.sub(_)) // scalar or vector + case Mul(a, b) => simScalar(a).join(simScalar(b))(_.mul(_)) + case Div(a, b) => simScalar(a).join(simScalar(b))(_.div(_)) + case Mod(a, b) => simScalar(a).join(simScalar(b))(_.mod(_)) - private def simBitwiseOp(e: BitwiseOpExpression[?])(using exprMap: Map[Int, Result]): Int = e match + private def simBitwiseOp(e: BitwiseOpExpression[?])(using Records): Results = e match case e: BitwiseBinaryOpExpression[?] => simBitwiseBinOp(e) - case BitwiseNot(a) => simScalar(a).bitNeg - case ShiftLeft(a, by) => simScalar(a).shiftLeft(simScalar(by)) - case ShiftRight(a, by) => simScalar(a).shiftRight(simScalar(by)) - - private def simBitwiseBinOp(e: BitwiseBinaryOpExpression[?])(using exprMap: Map[Int, Result]): Int = e match - case BitwiseAnd(a, b) => simScalar(a).bitAnd(simScalar(b)) - case BitwiseOr(a, b) => simScalar(a).bitOr(simScalar(b)) - case BitwiseXor(a, b) => simScalar(a).bitXor(simScalar(b)) - - private def simCompareOp(e: ComparisonOpExpression[?])(using exprMap: Map[Int, Result]): Boolean = e match - case GreaterThan(a, b) => simScalar(a).gt(simScalar(b)) - case LessThan(a, b) => simScalar(a).lt(simScalar(b)) - case GreaterThanEqual(a, b) => simScalar(a).gteq(simScalar(b)) - case LessThanEqual(a, b) => simScalar(a).lteq(simScalar(b)) - case Equal(a, b) => simScalar(a).eql(simScalar(b)) - - private def simConvert(e: ConvertExpression[?, ?])(using exprMap: Map[Int, Result]): Float | Int = e match - case ToFloat32(a) => - exprMap(a.treeid) match - case f: Float => f - case _ => throw IllegalArgumentException("ToFloat32: wrong argument type") - case ToInt32(a) => - exprMap(a.treeid) match - case n: Int => n - case _ => throw IllegalArgumentException("ToInt32: wrong argument type") - case ToUInt32(a) => - exprMap(a.treeid) match - case n: Int => n - case _ => throw IllegalArgumentException("ToUInt32: wrong argument type") - - private def simConst(e: Const[?]): ScalarRes = e match - case ConstFloat32(value) => value - case ConstInt32(value) => value - case ConstUInt32(value) => value - case ConstGB(value) => value - - private def simValue(v: Value)(using exprMap: Map[Int, Result]): Result = v match + case BitwiseNot(a) => simScalar(a).view.mapValues(_.bitNeg).toMap + case ShiftLeft(a, by) => simScalar(a).join(simScalar(by))(_.shiftLeft(_)) + case ShiftRight(a, by) => simScalar(a).join(simScalar(by))(_.shiftRight(_)) + + private def simBitwiseBinOp(e: BitwiseBinaryOpExpression[?])(using Records): Results = e match + case BitwiseAnd(a, b) => simScalar(a).join(simScalar(b))(_.bitAnd(_)) + case BitwiseOr(a, b) => simScalar(a).join(simScalar(b))(_.bitOr(_)) + case BitwiseXor(a, b) => simScalar(a).join(simScalar(b))(_.bitXor(_)) + + private def simCompareOp(e: ComparisonOpExpression[?])(using Records): Results = e match + case GreaterThan(a, b) => simScalar(a).join(simScalar(b))(_.gt(_)) + case LessThan(a, b) => simScalar(a).join(simScalar(b))(_.lt(_)) + case GreaterThanEqual(a, b) => simScalar(a).join(simScalar(b))(_.gteq(_)) + case LessThanEqual(a, b) => simScalar(a).join(simScalar(b))(_.lteq(_)) + case Equal(a, b) => simScalar(a).join(simScalar(b))(_.eql(_)) + + private def simConvert(e: ConvertExpression[?, ?])(using records: Records): Results = e match + case ToFloat32(a) => records.view.mapValues(_.cache(a.treeid).asInstanceOf[Float]).toMap + case ToInt32(a) => records.view.mapValues(_.cache(a.treeid).asInstanceOf[Int]).toMap + case ToUInt32(a) => records.view.mapValues(_.cache(a.treeid).asInstanceOf[Int]).toMap + + private def simConst(e: Const[?])(using records: Records): Results = e match + case ConstFloat32(value) => records.view.mapValues(_ => value).toMap + case ConstInt32(value) => records.view.mapValues(_ => value).toMap + case ConstUInt32(value) => records.view.mapValues(_ => value).toMap + case ConstGB(value) => records.view.mapValues(_ => value).toMap + + private def simValue(v: Value)(using Records): Results = v match case v: Scalar => simScalar(v) case v: Vec[?] => simVector(v) - private def simScalar(v: Scalar)(using exprMap: Map[Int, Result]): ScalarRes = v match - case v: FloatType => exprMap(v.tree.treeid).asInstanceOf[Float] - case v: IntType => exprMap(v.tree.treeid).asInstanceOf[Int] - case v: UIntType => exprMap(v.tree.treeid).asInstanceOf[Int] - case GBoolean(source) => exprMap(source.treeid).asInstanceOf[Boolean] + private def simScalar(v: Scalar)(using records: Records): Map[InvocId, ScalarRes] = v match + case v: FloatType => records.view.mapValues(_.cache(v.tree.treeid).asInstanceOf[Float]).toMap + case v: IntType => records.view.mapValues(_.cache(v.tree.treeid).asInstanceOf[Int]).toMap + case v: UIntType => records.view.mapValues(_.cache(v.tree.treeid).asInstanceOf[Int]).toMap + case GBoolean(source) => records.view.mapValues(_.cache(source.treeid).asInstanceOf[Boolean]).toMap - private def simVector(v: Vec[?])(using exprMap: Map[Int, Result]): Vector[ScalarRes] = v match - case Vec2(tree) => exprMap(tree.treeid).asInstanceOf[Vector[ScalarRes]] - case Vec3(tree) => exprMap(tree.treeid).asInstanceOf[Vector[ScalarRes]] - case Vec4(tree) => exprMap(tree.treeid).asInstanceOf[Vector[ScalarRes]] + private def simVector(v: Vec[?])(using records: Records): Map[InvocId, Vector[ScalarRes]] = v match + case Vec2(tree) => records.view.mapValues(_.cache(tree.treeid).asInstanceOf[Vector[ScalarRes]]).toMap + case Vec3(tree) => records.view.mapValues(_.cache(tree.treeid).asInstanceOf[Vector[ScalarRes]]).toMap + case Vec4(tree) => records.view.mapValues(_.cache(tree.treeid).asInstanceOf[Vector[ScalarRes]]).toMap - private def simExtFunc(fn: FunctionName, args: List[Result], sc: SimContext): (Result, SimContext) = ??? - private def simFunc(fn: FnIdentifier, body: Result, args: List[Result], sc: SimContext): (Result, SimContext) = ??? + private def simExtFunc(fn: FunctionName, args: List[Result], records: Records): (Result, Records) = ??? + private def simFunc(fn: FnIdentifier, body: Result, args: List[Result], records: Records): (Result, Records) = ??? + private def simInvocId(records: Records): Results = records.map((invocId, _) => invocId -> invocId) - @annotation.tailrec + // @annotation.tailrec private def whenHelper( when: Expression[GBoolean], thenCode: Scope[?], otherConds: List[Scope[GBoolean]], otherCaseCodes: List[Scope[?]], otherwise: Scope[?], - sc: SimContext, - ): (Result, SimContext) = - // scopes are not included in the "main" exprMap, they have to be simulated from scratch. - // there could be reads/writes happening in scopes, SimContext has to be updated. - val (boolRes, newSc) = sim(when, sc) - if boolRes.asInstanceOf[Boolean] then sim(thenCode.expr, newSc) + resultsSoFar: Results, + finishedRecords: Records, + pendingRecords: Records, + )(using SimContext): (Results, Records) = + if pendingRecords.isEmpty then (resultsSoFar, finishedRecords) else + // scopes are not included in caches, they have to be simulated from scratch. + // there could be reads happening in scopes, records have to be updated. + // scopes can still read from the outer SimContext. + val SimRes(boolResults, records1, _) = sim(when, pendingRecords) // SimContext does not change. + + // Split invocations that enter this branch. + val (enterRecords, newPendingRecords) = records1.partition((invocId, _) => boolResults(invocId).asInstanceOf[Boolean]) + + // Only those invocs that enter the branch will have their records updated with thenCode result. + val SimRes(thenResults, thenRecords, _) = sim(thenCode.expr, enterRecords) + otherConds.headOption match - case None => sim(otherwise.expr, newSc) + case None => // run pending invocs on otherwise, collect all results and records, done + val SimRes(owResults, owRecords, _) = sim(otherwise.expr, newPendingRecords) + (resultsSoFar ++ thenResults ++ owResults, finishedRecords ++ thenRecords ++ owRecords) case Some(cond) => whenHelper( when = cond.expr, @@ -147,32 +160,39 @@ object Simulate: otherConds = otherConds.tail, otherCaseCodes = otherCaseCodes.tail, otherwise = otherwise, - sc = newSc, + resultsSoFar = resultsSoFar ++ thenResults, + finishedRecords = finishedRecords ++ thenRecords, + pendingRecords = newPendingRecords, ) - private def simWhen(e: WhenExpr[?], sc: SimContext): (Result, SimContext) = e match + private def simWhen(e: WhenExpr[?], records: Records)(using SimContext): (Results, Records) = e match case WhenExpr(when, thenCode, otherConds, otherCaseCodes, otherwise) => - whenHelper(when.tree, thenCode, otherConds, otherCaseCodes, otherwise, sc) + whenHelper(when.tree, thenCode, otherConds, otherCaseCodes, otherwise, Map(), Map(), records) - private def simReadBuffer(e: ReadBuffer[?], sc: SimContext)(using exprMap: Map[Int, Result]): (Result, SimContext) = e match + private def simReadBuffer(e: ReadBuffer[?], records: Records)(using sc: SimContext): (Results, Records) = e match case ReadBuffer(buffer, index) => - val i = exprMap(index.tree.treeid).asInstanceOf[Int] - val newSc = sc.addRead(ReadBuf(buffer, i)) - (newSc.lookup(buffer, i), newSc) + val indices = records.view.mapValues(_.cache(index.tree.treeid).asInstanceOf[Int]).toMap + val readValues = indices.view.mapValues(i => sc.lookup(buffer, i)).toMap + val newRecords = records.map: (invocId, record) => + invocId -> record.addRead(ReadBuf(e.treeid, buffer, indices(invocId), readValues(invocId))) + (readValues, newRecords) - private def simReadUniform(uni: ReadUniform[?], sc: SimContext): (Result, SimContext) = uni match + private def simReadUniform(e: ReadUniform[?], records: Records)(using sc: SimContext): (Results, Records) = e match case ReadUniform(uniform) => - val newSc = sc.addRead(ReadUni(uniform)) - (newSc.lookupUni(uniform), newSc) + val readValue = sc.lookupUni(uniform) // same for all invocs + val newResults = records.map((invocId, _) => invocId -> readValue) + val newRecords = records.map: (invocId, record) => + invocId -> record.addRead(ReadUni(e.treeid, uniform, readValue)) + (newResults, newRecords) - private def simGArrayElem(gElem: GArrayElem[?]): (Result, SimContext) = gElem match + private def simGArrayElem(gElem: GArrayElem[?]): Results = gElem match case GArrayElem(index, i) => ??? - private def simFoldSeq(seq: FoldSeq[?, ?]): (Result, SimContext) = seq match + private def simFoldSeq(seq: FoldSeq[?, ?]): Results = seq match case FoldSeq(zero, fn, seq) => ??? - private def simComposeStruct(cs: ComposeStruct[?]): (Result, SimContext) = cs match + private def simComposeStruct(cs: ComposeStruct[?]): Results = cs match case ComposeStruct(fields, resultSchema) => ??? - private def simGetField(gf: GetField[?, ?]): (Result, SimContext) = gf match + private def simGetField(gf: GetField[?, ?]): Results = gf match case GetField(struct, fieldIndex) => ??? From 3f4c515f673e4c71d50a9e7ab18fa414771ca767 Mon Sep 17 00:00:00 2001 From: spamegg Date: Fri, 1 Aug 2025 15:45:30 +0300 Subject: [PATCH 14/59] fix simulate tests --- .../cyfra/e2e/interpreter/SimulateTests.scala | 88 ++++++++++++------ .../e2e/interpreter/SimulateWhenTests.scala | 91 ++++++++++--------- .../cyfra/interpreter/Record.scala | 1 + .../cyfra/interpreter/Simulate.scala | 3 +- 4 files changed, 110 insertions(+), 73 deletions(-) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala index c561c59c..082d5c4d 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala @@ -6,47 +6,72 @@ import Value.FromExpr.fromExpr, control.Scope import izumi.reflect.Tag class SimulateE2eTest extends munit.FunSuite: - test("simulate binary operation arithmetic"): + test("simulate binary operation arithmetic, record cache"): + given SimContext = SimContext() // no buffers, reads/writes here + val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val a: Int32 = 1 val b: Int32 = 2 val c: Int32 = 3 val d: Int32 = 4 val e: Int32 = 5 val f: Int32 = 6 - val e1 = Diff(a, b) - val e2 = Sum(fromExpr(e1), c) - val e3 = Mul(f, fromExpr(e2)) - val e4 = Div(fromExpr(e3), d) + val e1 = Diff(a, b) // -1 + val e2 = Sum(fromExpr(e1), c) // 2 + val e3 = Mul(f, fromExpr(e2)) // 12 + val e4 = Div(fromExpr(e3), d) // 3 val expr = Mod(e, fromExpr(e4)) // 5 % ((6 * ((1 - 2) + 3)) / 4) - val (result, _) = Simulate.sim(expr, SimContext()) + + val SimRes(results, records, _) = Simulate.sim(expr, startingRecords) val expected = 2 - assert(result == expected, s"Expected $expected, got $result") + assert(results(0) == expected, s"Expected $expected, got $results") + + // records cache should have kept track of intermediate expression results correctly + // 0 -> 1 a + // 1 -> 2 b + // 2 -> 3 c + // 3 -> 4 d + // 4 -> 5 e + // 5 -> 6 f + // 6 -> -1 e1 + // 7 -> 2 e2 + // 8 -> 12 e3 + // 9 -> 3 e4 + // 10 -> 2 expr + val map = Map(0 -> 1, 1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5, 5 -> 6, 6 -> -1, 7 -> 2, 8 -> 12, 9 -> 3, 10 -> 2) + assert(records(0).cache == map) + + test("simulate Vec4, scalar, dot, extract scalar"): + given SimContext = SimContext() // no buffers, reads/writes here + val startingRecords = Map(0 -> Record()) // running with only 1 invocation - test("simulate vec4, scalar, dot, extract scalar"): val v1 = ComposeVec4[Float32](1f, 2f, 3f, 4f) - val (res1, _) = Simulate.sim(v1, SimContext()) + val SimRes(res1, records1, _) = Simulate.sim(v1, startingRecords) val exp1 = Vector(1f, 2f, 3f, 4f) - assert(res1 == exp1, s"Expected $exp1, got $res1") + assert(res1(0) == exp1, s"Expected $exp1, got ${res1(0)}") val i: Int32 = 2 val expr = ExtractScalar(fromExpr(v1), i) - val (res, _) = Simulate.sim(expr, SimContext()) - val exp = 3f - assert(res == exp, s"Expected $exp, got $res") + val SimRes(res2, records2, _) = Simulate.sim(expr, records1) + val exp2 = 3f + assert(res2(0) == exp2, s"Expected $exp2, got ${res2(0)}") val v2 = ScalarProd(fromExpr(v1), -1f) - val (res2, _) = Simulate.sim(v2, SimContext()) - val exp2 = Vector(-1f, -2f, -3f, -4f) - assert(res2 == exp2, s"Expected $exp2, got $res2") + val SimRes(res3, records3, _) = Simulate.sim(v2, records2) + val exp3 = Vector(-1f, -2f, -3f, -4f) + assert(res3(0) == exp3, s"Expected $exp3, got ${res3(0)}") val v3 = ComposeVec4[Float32](-4f, -3f, 2f, 1f) val dot = DotProd(fromExpr(v1), fromExpr(v3)) - val (res3a, _) = Simulate.sim(dot, SimContext()) - val res3 = res3a.asInstanceOf[Float] - val exp3 = 0f - assert(Math.abs(res3 - exp3) < 0.001f, s"Expected $exp3, got $res3") + val SimRes(results, records4, _) = Simulate.sim(dot, records3) + val exp4 = 0f + val res4 = results(0).asInstanceOf[Float] + assert(Math.abs(res4 - exp4) < 0.001f, s"Expected $exp4, got $res4") test("simulate bitwise ops"): + given SimContext = SimContext() // no buffers, reads/writes here + val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val a: Int32 = 5 val by: UInt32 = 3 val aNot = BitwiseNot(a) @@ -56,17 +81,20 @@ class SimulateE2eTest extends munit.FunSuite: val or = BitwiseOr(fromExpr(left), fromExpr(right)) val xor = BitwiseXor(fromExpr(and), fromExpr(or)) - val (res, _) = Simulate.sim(xor, SimContext()) + val SimRes(res, records1, _) = Simulate.sim(xor, startingRecords) val exp = ((~5 << 3) & (~5 >> 3)) ^ ((~5 << 3) | (~5 >> 3)) - assert(res == exp, s"Expected $exp, got $res") + assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate should not stack overflow"): + given SimContext = SimContext() // no buffers, reads/writes here + val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val a: Int32 = 1 var sum = Sum(a, a) // 2 for _ <- 0 until 1000000 do sum = Sum(a, fromExpr(sum)) - val (res, _) = Simulate.sim(sum, SimContext()) + val SimRes(res, records, _) = Simulate.sim(sum, startingRecords) val exp = 1000002 - assert(res == exp, s"Expected $exp, got $res") + assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate ReadBuffer"): // We fake a GBuffer with an array @@ -74,12 +102,14 @@ class SimulateE2eTest extends munit.FunSuite: val buffer = SimGBuffer[Int32]() val array = (0 until 1024).toArray[Result] - val sc = SimContext().addBuffer(buffer, array) + given SimContext = SimContext().addBuffer(buffer, array) + val startingRecords = Map(0 -> Record()) // running with only 1 invocation val expr = ReadBuffer(buffer, 128) - val (res, newSc) = Simulate.sim(expr, sc) + val SimRes(res, records, _) = Simulate.sim(expr, startingRecords) val exp = 128 - assert(res == exp, s"Expected $exp, got $res") + assert(res(0) == exp, s"Expected $exp, got $res") - // the context should keep track of the read - assert(newSc.reads.contains(ReadBuf(buffer, 128)), "missing read") + // the records should keep track of the read + val read = ReadBuf(expr.treeid, buffer, 128, 128) // 128 has treeid 0, so expr has treeid 1 + assert(records(0).reads.contains(read), "missing read") diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala index 0026ebf5..cb73d395 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala @@ -7,87 +7,92 @@ import izumi.reflect.Tag class SimulateWhenE2eTest extends munit.FunSuite: test("simulate when"): - val expr1 = WhenExpr( + given SimContext = SimContext() // no buffers, reads/writes here + val startingRecords = Map(0 -> Record()) // running with only 1 invocation + + val expr = WhenExpr( when = 2 >= 1, // true thenCode = Scope(ConstInt32(1)), otherConds = List(Scope(ConstGB(3 == 2)), Scope(ConstGB(1 <= 3))), otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val (res1, _) = Simulate.sim(expr1, SimContext()) - val exp1 = 1 - assert(res1 == exp1, s"Expected $exp1, got $res1") + val SimRes(res, _, _) = Simulate.sim(expr, startingRecords) + val exp = 1 + assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate elseWhen first"): - val expr2 = WhenExpr( + given SimContext = SimContext() // no buffers, reads/writes here + val startingRecords = Map(0 -> Record()) // running with only 1 invocation + + val expr = WhenExpr( when = 2 <= 1, // false thenCode = Scope(ConstInt32(1)), otherConds = List(Scope(ConstGB(3 >= 2)) /*true*/, Scope(ConstGB(1 <= 3))), otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val (res2, _) = Simulate.sim(expr2, SimContext()) - val exp2 = 2 - assert(res2 == exp2, s"Expected $exp2, got $res2") + val SimRes(res, _, _) = Simulate.sim(expr, startingRecords) + val exp = 2 + assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate elseWhen second"): - val expr3 = WhenExpr( + given SimContext = SimContext() // no buffers, reads/writes here + val startingRecords = Map(0 -> Record()) // running with only 1 invocation + + val expr = WhenExpr( when = 2 <= 1, // false thenCode = Scope(ConstInt32(1)), otherConds = List(Scope(ConstGB(3 == 2)) /*false*/, Scope(ConstGB(1 <= 3))), // true otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val (res3, _) = Simulate.sim(expr3, SimContext()) - val exp3 = 4 - assert(res3 == exp3, s"Expected $exp3, got $res3") + val SimRes(res, _, _) = Simulate.sim(expr, startingRecords) + val exp = 4 + assert(res(0) == exp, s"Expected $exp, got $res") test("simulate otherwise"): - val expr4 = WhenExpr( + given SimContext = SimContext() // no buffers, reads/writes here + val startingRecords = Map(0 -> Record()) // running with only 1 invocation + + val expr = WhenExpr( when = 2 <= 1, // false thenCode = Scope(ConstInt32(1)), otherConds = List(Scope(ConstGB(3 == 2)) /*false*/, Scope(ConstGB(1 >= 3))), // false otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val (res4, _) = Simulate.sim(expr4, SimContext()) - val exp4 = 3 - assert(res4 == exp4, s"Expected $exp4, got $res4") + val SimRes(res, _, _) = Simulate.sim(expr, startingRecords) + val exp = 3 + assert(res(0) == exp, s"Expected $exp, got $res") - test("simulate mixed arithmetic, reads and when"): + test("simulate mixed arithmetic, buffer reads and when"): case class SimGBuffer[T <: Value: Tag: FromExpr]() extends GBuffer[T] val buffer = SimGBuffer[Int32]() - val array = (128 until 0 by -1).toArray[Result] - - val sc = SimContext().addBuffer(buffer, array) + val array = (0 until 3).toArray[Result] - val a: Int32 = 32 - val b: Int32 = 64 - val c: Int32 = 4 + given SimContext = SimContext().addBuffer(buffer, array) + val startingRecords = Map(0 -> Record(), 1 -> Record(), 2 -> Record()) // running 3 invocations - val readExpr1 = ReadBuffer(buffer, a) // 96 - val expr1 = Mul(c, fromExpr(readExpr1)) // 4 * 96 = 384 + val a: Int32 = 4 + val invocId = InvocationId + val readExpr = ReadBuffer(buffer, fromExpr(invocId)) // 0,1,2 - val readExpr2 = ReadBuffer(buffer, b) // 64 - val expr2 = Sum(c, fromExpr(readExpr2)) // 4 + 64 = 68 + val expr1 = Mul(a, fromExpr(readExpr)) // 4*0 = 0, 4*1 = 4, 4*2 = 8 + val expr2 = Sum(a, fromExpr(expr1)) // 4+0 = 4, 4+4 = 8, 4+8 = 12 + val expr3 = Mod(fromExpr(expr2), 5) // 4%5 = 4, 8%5 = 3, 12%5 = 2 - val expr3 = Mod(fromExpr(expr2), 5) // 68 % 5 = 3 - - val cond1 = fromExpr(expr1) <= fromExpr(expr2) // 384 <= 68 false - val cond2 = Equal(fromExpr(expr1), fromExpr(expr2)) // 384 == 68 false - val cond3 = GreaterThanEqual(fromExpr(expr3), fromExpr(expr2)) // 3 >= 68 false + val cond1 = fromExpr(expr1) <= fromExpr(expr3) + val cond2 = Equal(fromExpr(expr3), fromExpr(readExpr)) + // invoc 0 enters when, invoc2 enters elseWhen, invoc1 enters otherwise val expr = WhenExpr( - when = cond1, // false - thenCode = Scope(expr1), - otherConds = List(Scope(cond2), Scope(cond3)), // false false - otherCaseCodes = List(Scope(expr1), Scope(expr2)), // 384, 68 - otherwise = Scope(expr3), // 3 + when = cond1, // true false false + thenCode = Scope(expr1), // 0 _ _ + otherConds = List(Scope(cond2)), // _ false true + otherCaseCodes = List(Scope(expr2)), // _ _ 12 + otherwise = Scope(expr3), // _ 3 _ ) - val (res, newSc) = Simulate.sim(expr, sc) - val exp = 3 + val SimRes(res, records, _) = Simulate.sim(expr, startingRecords) + val exp = Map(0 -> 0, 1 -> 3, 2 -> 12) assert(res == exp, s"Expected $exp, got $res") - - // There should be 2 reads in the simulation context - assert(newSc.reads.contains(ReadBuf(buffer, 32))) - assert(newSc.reads.contains(ReadBuf(buffer, 64))) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala index 6bbe111e..cdaa3e04 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala @@ -21,6 +21,7 @@ case class Record(cache: Cache = Map(), writes: List[Write] = Nil, reads: List[R def addResult(treeId: TreeId, res: Result) = copy(cache = cache.updated(treeId, res)) extension (records: Records) + def apply(invocIds: Seq[InvocId]): Records = invocIds.map(invocId => invocId -> Record()).toMap def updateResults(treeid: TreeId, results: Results): Records = records.map: (invocId, record) => results.get(invocId) match diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala index d7f9fdf9..1072cf2a 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala @@ -24,6 +24,7 @@ object Simulate: simIterate(next, newRecords, newResults) case Nil => SimRes(results, records, sc) + // in these cases, the records don't change since there are no reads. def simOne(e: Expression[?])(using records: Records, sc: SimContext): Results = e match case e: PhantomExpression[?] => simPhantom(e) case Negate(a) => simValue(a).view.mapValues(_.negate).toMap @@ -123,7 +124,7 @@ object Simulate: private def simExtFunc(fn: FunctionName, args: List[Result], records: Records): (Result, Records) = ??? private def simFunc(fn: FnIdentifier, body: Result, args: List[Result], records: Records): (Result, Records) = ??? - private def simInvocId(records: Records): Results = records.map((invocId, _) => invocId -> invocId) + private def simInvocId(records: Records): Map[InvocId, InvocId] = records.map((invocId, _) => invocId -> invocId) // @annotation.tailrec private def whenHelper( From 113bbbe4985f6d11ef2588703d41e4c06d80bf6b Mon Sep 17 00:00:00 2001 From: spamegg Date: Fri, 1 Aug 2025 22:56:10 +0300 Subject: [PATCH 15/59] change design a bit, rename classes better --- .../e2e/interpreter/InterpreterTests.scala | 2 +- .../cyfra/e2e/interpreter/SimulateTests.scala | 26 ++++++------ .../e2e/interpreter/SimulateWhenTests.scala | 20 ++++----- .../cyfra/interpreter/Interpreter.scala | 25 +++++------ .../cyfra/interpreter/SimContext.scala | 20 ++++----- .../cyfra/interpreter/SimData.scala | 17 ++++++++ .../cyfra/interpreter/SimRes.scala | 11 ----- .../cyfra/interpreter/Simulate.scala | 42 +++++++++---------- 8 files changed, 80 insertions(+), 83 deletions(-) create mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimData.scala delete mode 100644 cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimRes.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala index 27483c16..5b04c654 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala @@ -10,7 +10,7 @@ class InterpreterE2eTest extends munit.FunSuite: val pure = Pure(0) var gio = FlatMap(pure, pure) for _ <- 0 until 1000000 do gio = FlatMap(pure, gio) - val result = Interpreter.interpret(gio, 0) + val result = Interpreter.interpret(gio, SimContext()) val res = 0 val exp = 0 assert(res == exp, s"Expected $exp, got $res") diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala index 082d5c4d..4ea40487 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala @@ -7,7 +7,7 @@ import izumi.reflect.Tag class SimulateE2eTest extends munit.FunSuite: test("simulate binary operation arithmetic, record cache"): - given SimContext = SimContext() // no buffers, reads/writes here + given SimData = SimData() // no buffers, reads/writes here val startingRecords = Map(0 -> Record()) // running with only 1 invocation val a: Int32 = 1 @@ -22,7 +22,7 @@ class SimulateE2eTest extends munit.FunSuite: val e4 = Div(fromExpr(e3), d) // 3 val expr = Mod(e, fromExpr(e4)) // 5 % ((6 * ((1 - 2) + 3)) / 4) - val SimRes(results, records, _) = Simulate.sim(expr, startingRecords) + val SimContext(results, records, _) = Simulate.sim(expr, startingRecords) val expected = 2 assert(results(0) == expected, s"Expected $expected, got $results") @@ -42,34 +42,34 @@ class SimulateE2eTest extends munit.FunSuite: assert(records(0).cache == map) test("simulate Vec4, scalar, dot, extract scalar"): - given SimContext = SimContext() // no buffers, reads/writes here + given SimData = SimData() // no buffers, reads/writes here val startingRecords = Map(0 -> Record()) // running with only 1 invocation val v1 = ComposeVec4[Float32](1f, 2f, 3f, 4f) - val SimRes(res1, records1, _) = Simulate.sim(v1, startingRecords) + val SimContext(res1, records1, _) = Simulate.sim(v1, startingRecords) val exp1 = Vector(1f, 2f, 3f, 4f) assert(res1(0) == exp1, s"Expected $exp1, got ${res1(0)}") val i: Int32 = 2 val expr = ExtractScalar(fromExpr(v1), i) - val SimRes(res2, records2, _) = Simulate.sim(expr, records1) + val SimContext(res2, records2, _) = Simulate.sim(expr, records1) val exp2 = 3f assert(res2(0) == exp2, s"Expected $exp2, got ${res2(0)}") val v2 = ScalarProd(fromExpr(v1), -1f) - val SimRes(res3, records3, _) = Simulate.sim(v2, records2) + val SimContext(res3, records3, _) = Simulate.sim(v2, records2) val exp3 = Vector(-1f, -2f, -3f, -4f) assert(res3(0) == exp3, s"Expected $exp3, got ${res3(0)}") val v3 = ComposeVec4[Float32](-4f, -3f, 2f, 1f) val dot = DotProd(fromExpr(v1), fromExpr(v3)) - val SimRes(results, records4, _) = Simulate.sim(dot, records3) + val SimContext(results, records4, _) = Simulate.sim(dot, records3) val exp4 = 0f val res4 = results(0).asInstanceOf[Float] assert(Math.abs(res4 - exp4) < 0.001f, s"Expected $exp4, got $res4") test("simulate bitwise ops"): - given SimContext = SimContext() // no buffers, reads/writes here + given SimData = SimData() // no buffers, reads/writes here val startingRecords = Map(0 -> Record()) // running with only 1 invocation val a: Int32 = 5 @@ -81,18 +81,18 @@ class SimulateE2eTest extends munit.FunSuite: val or = BitwiseOr(fromExpr(left), fromExpr(right)) val xor = BitwiseXor(fromExpr(and), fromExpr(or)) - val SimRes(res, records1, _) = Simulate.sim(xor, startingRecords) + val SimContext(res, records1, _) = Simulate.sim(xor, startingRecords) val exp = ((~5 << 3) & (~5 >> 3)) ^ ((~5 << 3) | (~5 >> 3)) assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate should not stack overflow"): - given SimContext = SimContext() // no buffers, reads/writes here + given SimData = SimData() // no buffers, reads/writes here val startingRecords = Map(0 -> Record()) // running with only 1 invocation val a: Int32 = 1 var sum = Sum(a, a) // 2 for _ <- 0 until 1000000 do sum = Sum(a, fromExpr(sum)) - val SimRes(res, records, _) = Simulate.sim(sum, startingRecords) + val SimContext(res, records, _) = Simulate.sim(sum, startingRecords) val exp = 1000002 assert(res(0) == exp, s"Expected $exp, got ${res(0)}") @@ -102,11 +102,11 @@ class SimulateE2eTest extends munit.FunSuite: val buffer = SimGBuffer[Int32]() val array = (0 until 1024).toArray[Result] - given SimContext = SimContext().addBuffer(buffer, array) + given SimData = SimData().addBuffer(buffer, array) val startingRecords = Map(0 -> Record()) // running with only 1 invocation val expr = ReadBuffer(buffer, 128) - val SimRes(res, records, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, records, _) = Simulate.sim(expr, startingRecords) val exp = 128 assert(res(0) == exp, s"Expected $exp, got $res") diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala index cb73d395..371fb9ec 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala @@ -7,7 +7,7 @@ import izumi.reflect.Tag class SimulateWhenE2eTest extends munit.FunSuite: test("simulate when"): - given SimContext = SimContext() // no buffers, reads/writes here + given SimData = SimData() // no buffers, reads/writes here val startingRecords = Map(0 -> Record()) // running with only 1 invocation val expr = WhenExpr( @@ -17,12 +17,12 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val SimRes(res, _, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, _, _) = Simulate.sim(expr, startingRecords) val exp = 1 assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate elseWhen first"): - given SimContext = SimContext() // no buffers, reads/writes here + given SimData = SimData() // no buffers, reads/writes here val startingRecords = Map(0 -> Record()) // running with only 1 invocation val expr = WhenExpr( @@ -32,12 +32,12 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val SimRes(res, _, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, _, _) = Simulate.sim(expr, startingRecords) val exp = 2 assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate elseWhen second"): - given SimContext = SimContext() // no buffers, reads/writes here + given SimData = SimData() // no buffers, reads/writes here val startingRecords = Map(0 -> Record()) // running with only 1 invocation val expr = WhenExpr( @@ -47,12 +47,12 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val SimRes(res, _, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, _, _) = Simulate.sim(expr, startingRecords) val exp = 4 assert(res(0) == exp, s"Expected $exp, got $res") test("simulate otherwise"): - given SimContext = SimContext() // no buffers, reads/writes here + given SimData = SimData() // no buffers, reads/writes here val startingRecords = Map(0 -> Record()) // running with only 1 invocation val expr = WhenExpr( @@ -62,7 +62,7 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val SimRes(res, _, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, _, _) = Simulate.sim(expr, startingRecords) val exp = 3 assert(res(0) == exp, s"Expected $exp, got $res") @@ -71,7 +71,7 @@ class SimulateWhenE2eTest extends munit.FunSuite: val buffer = SimGBuffer[Int32]() val array = (0 until 3).toArray[Result] - given SimContext = SimContext().addBuffer(buffer, array) + given SimData = SimData().addBuffer(buffer, array) val startingRecords = Map(0 -> Record(), 1 -> Record(), 2 -> Record()) // running 3 invocations val a: Int32 = 4 @@ -93,6 +93,6 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(expr2)), // _ _ 12 otherwise = Scope(expr3), // _ 3 _ ) - val SimRes(res, records, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, records, _) = Simulate.sim(expr, startingRecords) val exp = Map(0 -> 0, 1 -> 3, 2 -> 12) assert(res == exp, s"Expected $exp, got $res") diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala index 57d9caa5..4a93284c 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala @@ -7,21 +7,21 @@ import izumi.reflect.Tag object Interpreter: private def interpretPure(gio: Pure[?], sc: SimContext): SimContext = gio match case Pure(value) => - val SimRes(results, records, newSc) = Simulate.sim(value.asInstanceOf[Value]) // TODO needs fixing + val SimContext(results, records, _) = Simulate.sim(value.asInstanceOf[Value], sc.records)(using sc.data) // TODO needs fixing // newSc.addResult(result) ??? private def interpretWriteBuffer(gio: WriteBuffer[?], sc: SimContext): SimContext = gio match case WriteBuffer(buffer, index, value) => - val SimRes(n, _, _) = Simulate.sim(index) // Int32, no reads/writes here, don't need resulting context + val SimContext(n, _, _) = Simulate.sim(index, sc.records)(using sc.data) // Int32, no reads/writes here, don't need resulting context val i = n.asInstanceOf[Int] - val SimRes(res, _, newSc) = Simulate.sim(value) + val SimContext(res, _, newSc) = Simulate.sim(value, sc.records)(using sc.data) // newSc.addWrite(WriteBuf(buffer, i, res)) ??? private def interpretWriteUniform(gio: WriteUniform[?], sc: SimContext): SimContext = gio match case WriteUniform(uniform, value) => - val SimRes(result, _, newSc) = Simulate.sim(value) + val SimContext(results, records, newSc) = Simulate.sim(value, sc.records)(using sc.data) // newSc.addWrite(WriteUni(uniform, result)) ??? @@ -34,15 +34,12 @@ object Interpreter: @annotation.tailrec private def interpretMany(gios: List[GIO[?]], sc: SimContext): SimContext = gios match case FlatMap(gio, next) :: tail => interpretMany(gio :: next :: tail, sc) - case Repeat(n, f) :: tail => - val SimRes(i, _, _) = Simulate.sim(n) // just Int32, no reads/writes - val int = i.asInstanceOf[Int] - val newGios = (0 until int).map(i => f(i)).toList + case Repeat(n, f) :: tail => // is this n ever a complex expression? Or just a plain int? + val SimContext(results, _, _) = Simulate.sim(n, sc.records)(using sc.data) // just Int32, no reads/writes + val repeat = results(0).asInstanceOf[Int] + val newGios = (0 until repeat).map(i => f(i)).toList interpretMany(newGios ::: tail, sc) - case head :: tail => - val newSc = interpretOne(head, sc) - interpretMany(tail, newSc) - case Nil => sc + case head :: tail => interpretMany(tail, interpretOne(head, sc)) + case Nil => sc - def interpret(gio: GIO[?], invocId: Int) = (invocId, interpretMany(List(gio), SimContext())) - def interpret(gio: GIO[?], invocIds: List[Int]): List[(Int, SimContext)] = invocIds.map(interpret(gio, _)) + def interpret(gio: GIO[?], sc: SimContext): SimContext = interpretMany(List(gio), sc) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala index 4df3096a..4622ae82 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala @@ -1,17 +1,11 @@ package io.computenode.cyfra.interpreter -import io.computenode.cyfra.dsl.{*, given} -import binding.{GBuffer, GUniform} +type Results = Map[InvocId, Result] -case class SimContext(bufMap: Map[GBuffer[?], Array[Result]] = Map(), uniMap: Map[GUniform[?], Result] = Map()): - def addBuffer(buffer: GBuffer[?], array: Array[Result]) = copy(bufMap = bufMap + (buffer -> array)) - def addUniform(uniform: GUniform[?], value: Result) = copy(uniMap = uniMap + (uniform -> value)) +extension (r: Results) + // assumes both results have the same set of keys. + def join(that: Results)(op: (Result, Result) => Result): Results = + r.map: (invocId, res) => + invocId -> op(res, that(invocId)) - def lookup(buffer: GBuffer[?], index: Int): Result = bufMap(buffer)(index) - def lookupUni(uniform: GUniform[?]): Result = uniMap(uniform) - - def addWrite(write: Write): SimContext = write match - case WriteBuf(_, buffer, index, value) => - val newArray = bufMap(buffer).updated(index, value) - copy(bufMap = bufMap.updated(buffer, newArray)) - case WriteUni(_, uni, value) => copy(uniMap = uniMap.updated(uni, value)) +case class SimContext(results: Results = Map(), records: Records = Map(), data: SimData = SimData()) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimData.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimData.scala new file mode 100644 index 00000000..301e68bc --- /dev/null +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimData.scala @@ -0,0 +1,17 @@ +package io.computenode.cyfra.interpreter + +import io.computenode.cyfra.dsl.{*, given} +import binding.{GBuffer, GUniform} + +case class SimData(bufMap: Map[GBuffer[?], Array[Result]] = Map(), uniMap: Map[GUniform[?], Result] = Map()): + def addBuffer(buffer: GBuffer[?], array: Array[Result]) = copy(bufMap = bufMap + (buffer -> array)) + def addUniform(uniform: GUniform[?], value: Result) = copy(uniMap = uniMap + (uniform -> value)) + + def lookup(buffer: GBuffer[?], index: Int): Result = bufMap(buffer)(index) + def lookupUni(uniform: GUniform[?]): Result = uniMap(uniform) + + def addWrite(write: Write): SimData = write match + case WriteBuf(_, buffer, index, value) => + val newArray = bufMap(buffer).updated(index, value) + copy(bufMap = bufMap.updated(buffer, newArray)) + case WriteUni(_, uni, value) => copy(uniMap = uniMap.updated(uni, value)) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimRes.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimRes.scala deleted file mode 100644 index 4b039a66..00000000 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimRes.scala +++ /dev/null @@ -1,11 +0,0 @@ -package io.computenode.cyfra.interpreter - -type Results = Map[InvocId, Result] - -extension (r: Results) - // assumes both results have the same set of keys. - def join(that: Results)(op: (Result, Result) => Result): Results = - r.map: (invocId, res) => - invocId -> op(res, that(invocId)) - -case class SimRes(results: Results = Map(), records: Records = Map(), sc: SimContext = SimContext()) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala index 1072cf2a..3a90fbb0 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala @@ -9,23 +9,23 @@ import io.computenode.cyfra.spirv.BlockBuilder.buildBlock object Simulate: import Result.* - def sim(v: Value, records: Records = Map())(using sc: SimContext = SimContext()): SimRes = sim(v.tree, records) - def sim(e: Expression[?], records: Records)(using SimContext): SimRes = simIterate(buildBlock(e), records) + def sim(v: Value, records: Records)(using data: SimData = SimData()): SimContext = sim(v.tree, records) + def sim(e: Expression[?], records: Records)(using SimData): SimContext = simIterate(buildBlock(e), records) @annotation.tailrec - def simIterate(blocks: List[Expression[?]], records: Records, results: Results = Map())(using sc: SimContext): SimRes = blocks match + def simIterate(blocks: List[Expression[?]], records: Records, results: Results = Map())(using data: SimData): SimContext = blocks match case head :: next => // reads have to be treated specially, since they will update the records val (newResults, records1) = head match case e: ReadBuffer[?] => simReadBuffer(e, records) // records updated with reads case e: ReadUniform[?] => simReadUniform(e, records) // records updated with reads - case e: WhenExpr[?] => simWhen(e, records) + case e: WhenExpr[?] => simWhen(e, records) // records updated with reads case _ => (simOne(head)(using records), records) // no reads, records not updated val newRecords = records1.updateResults(head.treeid, newResults) // update caches with new results simIterate(next, newRecords, newResults) - case Nil => SimRes(results, records, sc) + case Nil => SimContext(results, records, data) // in these cases, the records don't change since there are no reads. - def simOne(e: Expression[?])(using records: Records, sc: SimContext): Results = e match + def simOne(e: Expression[?])(using records: Records, data: SimData): Results = e match case e: PhantomExpression[?] => simPhantom(e) case Negate(a) => simValue(a).view.mapValues(_.negate).toMap case e: BinaryOpExpression[?] => simBinOp(e) @@ -56,8 +56,8 @@ object Simulate: .map: invocId => invocId -> Vector(aRes(invocId), bRes(invocId), cRes(invocId), dRes(invocId)) .toMap - case ExtFunctionCall(fn, args) => ??? // simExtFunc(fn, args.map(simValue) - case FunctionCall(fn, body, args) => ??? // simFunc(fn, simScope(body), args.map(simValue) + case ExtFunctionCall(fn, args) => ??? // simExtFunc(fn, args.map(simValue)) + case FunctionCall(fn, body, args) => ??? // simFunc(fn, simScope(body), args.map(simValue)) case InvocationId => simInvocId(records) case Pass(value) => ??? case Dynamic(source) => ??? @@ -122,11 +122,11 @@ object Simulate: case Vec3(tree) => records.view.mapValues(_.cache(tree.treeid).asInstanceOf[Vector[ScalarRes]]).toMap case Vec4(tree) => records.view.mapValues(_.cache(tree.treeid).asInstanceOf[Vector[ScalarRes]]).toMap - private def simExtFunc(fn: FunctionName, args: List[Result], records: Records): (Result, Records) = ??? - private def simFunc(fn: FnIdentifier, body: Result, args: List[Result], records: Records): (Result, Records) = ??? + private def simExtFunc(fn: FunctionName, args: List[Result], records: Records): Results = ??? + private def simFunc(fn: FnIdentifier, body: Result, args: List[Result], records: Records): Results = ??? private def simInvocId(records: Records): Map[InvocId, InvocId] = records.map((invocId, _) => invocId -> invocId) - // @annotation.tailrec + @annotation.tailrec private def whenHelper( when: Expression[GBoolean], thenCode: Scope[?], @@ -136,23 +136,23 @@ object Simulate: resultsSoFar: Results, finishedRecords: Records, pendingRecords: Records, - )(using SimContext): (Results, Records) = + )(using SimData): (Results, Records) = if pendingRecords.isEmpty then (resultsSoFar, finishedRecords) else // scopes are not included in caches, they have to be simulated from scratch. // there could be reads happening in scopes, records have to be updated. - // scopes can still read from the outer SimContext. - val SimRes(boolResults, records1, _) = sim(when, pendingRecords) // SimContext does not change. + // scopes can still read from the outer SimData. + val SimContext(boolResults, records1, _) = sim(when, pendingRecords) // SimData does not change. // Split invocations that enter this branch. val (enterRecords, newPendingRecords) = records1.partition((invocId, _) => boolResults(invocId).asInstanceOf[Boolean]) // Only those invocs that enter the branch will have their records updated with thenCode result. - val SimRes(thenResults, thenRecords, _) = sim(thenCode.expr, enterRecords) + val SimContext(thenResults, thenRecords, _) = sim(thenCode.expr, enterRecords) otherConds.headOption match case None => // run pending invocs on otherwise, collect all results and records, done - val SimRes(owResults, owRecords, _) = sim(otherwise.expr, newPendingRecords) + val SimContext(owResults, owRecords, _) = sim(otherwise.expr, newPendingRecords) (resultsSoFar ++ thenResults ++ owResults, finishedRecords ++ thenRecords ++ owRecords) case Some(cond) => whenHelper( @@ -166,21 +166,21 @@ object Simulate: pendingRecords = newPendingRecords, ) - private def simWhen(e: WhenExpr[?], records: Records)(using SimContext): (Results, Records) = e match + private def simWhen(e: WhenExpr[?], records: Records)(using SimData): (Results, Records) = e match case WhenExpr(when, thenCode, otherConds, otherCaseCodes, otherwise) => whenHelper(when.tree, thenCode, otherConds, otherCaseCodes, otherwise, Map(), Map(), records) - private def simReadBuffer(e: ReadBuffer[?], records: Records)(using sc: SimContext): (Results, Records) = e match + private def simReadBuffer(e: ReadBuffer[?], records: Records)(using data: SimData): (Results, Records) = e match case ReadBuffer(buffer, index) => val indices = records.view.mapValues(_.cache(index.tree.treeid).asInstanceOf[Int]).toMap - val readValues = indices.view.mapValues(i => sc.lookup(buffer, i)).toMap + val readValues = indices.view.mapValues(i => data.lookup(buffer, i)).toMap val newRecords = records.map: (invocId, record) => invocId -> record.addRead(ReadBuf(e.treeid, buffer, indices(invocId), readValues(invocId))) (readValues, newRecords) - private def simReadUniform(e: ReadUniform[?], records: Records)(using sc: SimContext): (Results, Records) = e match + private def simReadUniform(e: ReadUniform[?], records: Records)(using data: SimData): (Results, Records) = e match case ReadUniform(uniform) => - val readValue = sc.lookupUni(uniform) // same for all invocs + val readValue = data.lookupUni(uniform) // same for all invocs val newResults = records.map((invocId, _) => invocId -> readValue) val newRecords = records.map: (invocId, record) => invocId -> record.addRead(ReadUni(e.treeid, uniform, readValue)) From 37a5291c18bd452c76e87cf82051998bae8b0079 Mon Sep 17 00:00:00 2001 From: spamegg Date: Sat, 2 Aug 2025 14:24:52 +0300 Subject: [PATCH 16/59] implement writes in Interpreter --- .../e2e/interpreter/InterpreterTests.scala | 10 ++--- .../cyfra/interpreter/Interpreter.scala | 45 ++++++++++++------- .../cyfra/interpreter/ReadWrite.scala | 4 +- .../cyfra/interpreter/Record.scala | 13 ++++-- .../cyfra/interpreter/SimContext.scala | 2 +- .../cyfra/interpreter/SimData.scala | 13 ++++-- .../cyfra/interpreter/Simulate.scala | 10 +++-- 7 files changed, 64 insertions(+), 33 deletions(-) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala index 5b04c654..094f6718 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala @@ -7,10 +7,10 @@ import Value.FromExpr.fromExpr, control.Scope class InterpreterE2eTest extends munit.FunSuite: test("interpret should not stack overflow"): - val pure = Pure(0) + val fakeContext = SimContext(Map(), Map(), SimData()) + val n: Int32 = 0 + val pure = Pure(n) var gio = FlatMap(pure, pure) for _ <- 0 until 1000000 do gio = FlatMap(pure, gio) - val result = Interpreter.interpret(gio, SimContext()) - val res = 0 - val exp = 0 - assert(res == exp, s"Expected $exp, got $res") + val result = Interpreter.interpret(gio, fakeContext) + println("all good, interpret did not stack overflow!") diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala index 4a93284c..9c033244 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala @@ -6,24 +6,35 @@ import izumi.reflect.Tag object Interpreter: private def interpretPure(gio: Pure[?], sc: SimContext): SimContext = gio match - case Pure(value) => - val SimContext(results, records, _) = Simulate.sim(value.asInstanceOf[Value], sc.records)(using sc.data) // TODO needs fixing - // newSc.addResult(result) - ??? + // TODO needs fixing, throws ClassCastException, Pure[T] should be Pure[T <: Value] + case Pure(value) => Simulate.sim(value.asInstanceOf[Value], sc) // no writes here private def interpretWriteBuffer(gio: WriteBuffer[?], sc: SimContext): SimContext = gio match case WriteBuffer(buffer, index, value) => - val SimContext(n, _, _) = Simulate.sim(index, sc.records)(using sc.data) // Int32, no reads/writes here, don't need resulting context - val i = n.asInstanceOf[Int] - val SimContext(res, _, newSc) = Simulate.sim(value, sc.records)(using sc.data) - // newSc.addWrite(WriteBuf(buffer, i, res)) - ??? + val sc1 = Simulate.sim(index, sc) // get the write index for each invocation + val SimContext(writeVals, records, data) = Simulate.sim(value, sc1) // get the values to be written + + // write the values to the buffer, update records with writes + val indices = sc1.results + val newData = data.writeToBuffer(buffer, indices, writeVals) + val writes = indices.map: (invocId, ind) => + invocId -> WriteBuf(buffer, ind.asInstanceOf[Int], writeVals(invocId)) + val newRecords = records.addWrites(writes) + + SimContext(writeVals, newRecords, newData) private def interpretWriteUniform(gio: WriteUniform[?], sc: SimContext): SimContext = gio match case WriteUniform(uniform, value) => - val SimContext(results, records, newSc) = Simulate.sim(value, sc.records)(using sc.data) - // newSc.addWrite(WriteUni(uniform, result)) - ??? + // get the uniform value to be written (same for all invocations) + val SimContext(writeVals, records, data) = Simulate.sim(value, sc) + + // write the (single) value to the uniform, update records with writes + val uniVal = writeVals.values.head + val writes = writeVals.map((invocId, res) => invocId -> WriteUni(uniform, res)) + val newData = data.write(WriteUni(uniform, uniVal)) + val newRecords = records.addWrites(writes) + + SimContext(writeVals, newRecords, newData) private def interpretOne(gio: GIO[?], sc: SimContext): SimContext = gio match case p: Pure[?] => interpretPure(p, sc) @@ -34,11 +45,13 @@ object Interpreter: @annotation.tailrec private def interpretMany(gios: List[GIO[?]], sc: SimContext): SimContext = gios match case FlatMap(gio, next) :: tail => interpretMany(gio :: next :: tail, sc) - case Repeat(n, f) :: tail => // is this n ever a complex expression? Or just a plain int? - val SimContext(results, _, _) = Simulate.sim(n, sc.records)(using sc.data) // just Int32, no reads/writes - val repeat = results(0).asInstanceOf[Int] + case Repeat(n, f) :: tail => + // does the value of n vary by invocation? + // can different invocations run different numbers of GIOs? + val newSc = Simulate.sim(n, sc) + val repeat = newSc.results.values.head.asInstanceOf[Int] val newGios = (0 until repeat).map(i => f(i)).toList - interpretMany(newGios ::: tail, sc) + interpretMany(newGios ::: tail, newSc) case head :: tail => interpretMany(tail, interpretOne(head, sc)) case Nil => sc diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala index 614d502e..893f9919 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala @@ -9,6 +9,6 @@ enum Read: export Read.* enum Write: - case WriteBuf(id: Int, buffer: GBuffer[?], index: Int, value: Result) - case WriteUni(id: Int, uni: GUniform[?], value: Result) + case WriteBuf(buffer: GBuffer[?], index: Int, value: Result) + case WriteUni(uni: GUniform[?], value: Result) export Write.* diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala index cdaa3e04..0971d3d6 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala @@ -15,15 +15,22 @@ case class Record(cache: Cache = Map(), writes: List[Write] = Nil, reads: List[R case ReadUni(_, _, _) => copy(reads = read :: reads) def addWrite(write: Write): Record = write match - case WriteBuf(_, _, _, _) => copy(writes = write :: writes) - case WriteUni(_, _, _) => copy(writes = write :: writes) + case WriteBuf(_, _, _) => copy(writes = write :: writes) + case WriteUni(_, _) => copy(writes = write :: writes) def addResult(treeId: TreeId, res: Result) = copy(cache = cache.updated(treeId, res)) extension (records: Records) def apply(invocIds: Seq[InvocId]): Records = invocIds.map(invocId => invocId -> Record()).toMap + def updateResults(treeid: TreeId, results: Results): Records = records.map: (invocId, record) => results.get(invocId) match + case None => invocId -> record + case Some(result) => invocId -> record.addResult(treeid, result) + + def addWrites(writes: Map[InvocId, Write]) = + records.map: (invocId, record) => + writes.get(invocId) match + case Some(write) => invocId -> record.addWrite(write) case None => invocId -> record - case Some(value) => invocId -> record.addResult(treeid, value) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala index 4622ae82..248ea76f 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala @@ -8,4 +8,4 @@ extension (r: Results) r.map: (invocId, res) => invocId -> op(res, that(invocId)) -case class SimContext(results: Results = Map(), records: Records = Map(), data: SimData = SimData()) +case class SimContext(results: Results, records: Records, data: SimData) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimData.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimData.scala index 301e68bc..8bb36dc0 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimData.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimData.scala @@ -10,8 +10,15 @@ case class SimData(bufMap: Map[GBuffer[?], Array[Result]] = Map(), uniMap: Map[G def lookup(buffer: GBuffer[?], index: Int): Result = bufMap(buffer)(index) def lookupUni(uniform: GUniform[?]): Result = uniMap(uniform) - def addWrite(write: Write): SimData = write match - case WriteBuf(_, buffer, index, value) => + def write(write: Write): SimData = write match + case WriteBuf(buffer, index, value) => val newArray = bufMap(buffer).updated(index, value) copy(bufMap = bufMap.updated(buffer, newArray)) - case WriteUni(_, uni, value) => copy(uniMap = uniMap.updated(uni, value)) + case WriteUni(uni, value) => copy(uniMap = uniMap.updated(uni, value)) + + def writeToBuffer(buffer: GBuffer[?], indices: Results, writeValues: Results): SimData = + val array = bufMap(buffer) + val newArray = array.clone() + for (invocId, writeIndex) <- indices do newArray(writeIndex.asInstanceOf[Int]) = writeValues(invocId) + val newBufMap = bufMap.updated(buffer, newArray) + copy(bufMap = newBufMap) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala index 3a90fbb0..88a7a085 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala @@ -9,7 +9,11 @@ import io.computenode.cyfra.spirv.BlockBuilder.buildBlock object Simulate: import Result.* + // Some helpful overloads to simulate values instead of expressions + def sim(v: Value, sc: SimContext): SimContext = sim(v, sc.records)(using sc.data) def sim(v: Value, records: Records)(using data: SimData = SimData()): SimContext = sim(v.tree, records) + + // for evaluating expressions that don't cause any writes (therefore don't change data) def sim(e: Expression[?], records: Records)(using SimData): SimContext = simIterate(buildBlock(e), records) @annotation.tailrec @@ -17,9 +21,9 @@ object Simulate: case head :: next => // reads have to be treated specially, since they will update the records val (newResults, records1) = head match case e: ReadBuffer[?] => simReadBuffer(e, records) // records updated with reads - case e: ReadUniform[?] => simReadUniform(e, records) // records updated with reads - case e: WhenExpr[?] => simWhen(e, records) // records updated with reads - case _ => (simOne(head)(using records), records) // no reads, records not updated + case e: ReadUniform[?] => simReadUniform(e, records) + case e: WhenExpr[?] => simWhen(e, records) + case _ => (simOne(head)(using records), records) // no reads, records don't change val newRecords = records1.updateResults(head.treeid, newResults) // update caches with new results simIterate(next, newRecords, newResults) case Nil => SimContext(results, records, data) From 95e514c4c1a3b688b092636181d475123ebc6244 Mon Sep 17 00:00:00 2001 From: spamegg Date: Mon, 4 Aug 2025 19:01:56 +0300 Subject: [PATCH 17/59] add coalesce write profile, interpreter tests --- .../e2e/interpreter/InterpreterTests.scala | 43 +++++++++- .../cyfra/e2e/interpreter/SimulateTests.scala | 69 ++++++++-------- .../e2e/interpreter/SimulateWhenTests.scala | 25 +++--- .../cyfra/interpreter/Interpreter.scala | 17 ++-- .../cyfra/interpreter/ReadWrite.scala | 16 ++++ .../cyfra/interpreter/SimContext.scala | 6 +- .../cyfra/interpreter/Simulate.scala | 79 +++++++++++-------- 7 files changed, 166 insertions(+), 89 deletions(-) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala index 094f6718..ee3e08a9 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala @@ -3,7 +3,8 @@ package io.computenode.cyfra.e2e.interpreter import io.computenode.cyfra.interpreter.*, Result.* import io.computenode.cyfra.dsl.{*, given} import binding.*, Value.*, gio.GIO, GIO.* -import Value.FromExpr.fromExpr, control.Scope +import FromExpr.fromExpr, control.Scope +import izumi.reflect.Tag class InterpreterE2eTest extends munit.FunSuite: test("interpret should not stack overflow"): @@ -14,3 +15,43 @@ class InterpreterE2eTest extends munit.FunSuite: for _ <- 0 until 1000000 do gio = FlatMap(pure, gio) val result = Interpreter.interpret(gio, fakeContext) println("all good, interpret did not stack overflow!") + + test("interpret mixed arithmetic, buffer reads/writes, uniform reads/writes, and when"): + case class SimGBuffer[T <: Value: Tag: FromExpr]() extends GBuffer[T] + val buffer = SimGBuffer[Int32]() + val array = (0 until 3).toArray[Result] + + case class SimGUniform[T <: Value: Tag: FromExpr]() extends GUniform[T] + val uniform = SimGUniform[Int32]() + val uniValue = 4 + + val data = SimData().addBuffer(buffer, array).addUniform(uniform, uniValue) + val startingRecords = Map(0 -> Record(), 1 -> Record(), 2 -> Record()) // running 3 invocations + val startingSc = SimContext(records = startingRecords, data = data) + + val a = ReadUniform(uniform) // 4 + val invocId = InvocationId + val readExpr = ReadBuffer(buffer, fromExpr(invocId)) // 0,1,2 + + val expr1 = Mul(fromExpr(a), fromExpr(readExpr)) // 4*0 = 0, 4*1 = 4, 4*2 = 8 + val expr2 = Sum(fromExpr(a), fromExpr(expr1)) // 4+0 = 4, 4+4 = 8, 4+8 = 12 + val expr3 = Mod(fromExpr(expr2), 5) // 4%5 = 4, 8%5 = 3, 12%5 = 2 + + val cond1 = fromExpr(expr1) <= fromExpr(expr3) + val cond2 = Equal(fromExpr(expr3), fromExpr(readExpr)) + + // invoc 0 enters when, invoc2 enters elseWhen, invoc1 enters otherwise + val expr = WhenExpr( + when = cond1, // true false false + thenCode = Scope(expr1), // 0 _ _ + otherConds = List(Scope(cond2)), // _ false true + otherCaseCodes = List(Scope(expr2)), // _ _ 12 + otherwise = Scope(expr3), // _ 3 _ + ) + + val writeBufGIO = WriteBuffer(buffer, fromExpr(invocId), fromExpr(expr)) + val writeUniGIO = WriteUniform(uniform, fromExpr(expr)) + val gio = FlatMap(writeBufGIO, writeUniGIO) + + val sc = Interpreter.interpret(gio, startingSc) + println(sc) // TODO not sure what/how to test for now. diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala index 4ea40487..4aca42df 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateTests.scala @@ -7,8 +7,7 @@ import izumi.reflect.Tag class SimulateE2eTest extends munit.FunSuite: test("simulate binary operation arithmetic, record cache"): - given SimData = SimData() // no buffers, reads/writes here - val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val startingSc = SimContext(records = Map(0 -> Record())) // running with only 1 invocation val a: Int32 = 1 val b: Int32 = 2 @@ -22,55 +21,58 @@ class SimulateE2eTest extends munit.FunSuite: val e4 = Div(fromExpr(e3), d) // 3 val expr = Mod(e, fromExpr(e4)) // 5 % ((6 * ((1 - 2) + 3)) / 4) - val SimContext(results, records, _) = Simulate.sim(expr, startingRecords) + val SimContext(results, records, _, _) = Simulate.sim(expr, startingSc) val expected = 2 assert(results(0) == expected, s"Expected $expected, got $results") // records cache should have kept track of intermediate expression results correctly - // 0 -> 1 a - // 1 -> 2 b - // 2 -> 3 c - // 3 -> 4 d - // 4 -> 5 e - // 5 -> 6 f - // 6 -> -1 e1 - // 7 -> 2 e2 - // 8 -> 12 e3 - // 9 -> 3 e4 - // 10 -> 2 expr - val map = Map(0 -> 1, 1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5, 5 -> 6, 6 -> -1, 7 -> 2, 8 -> 12, 9 -> 3, 10 -> 2) - assert(records(0).cache == map) + val exp = Map( + a.treeid -> 1, + b.treeid -> 2, + c.treeid -> 3, + d.treeid -> 4, + e.treeid -> 5, + f.treeid -> 6, + e1.treeid -> -1, + e2.treeid -> 2, + e3.treeid -> 12, + e4.treeid -> 3, + expr.treeid -> 2, + ) + val res = records(0).cache + assert(res == exp, s"Expected $exp, got $res") test("simulate Vec4, scalar, dot, extract scalar"): - given SimData = SimData() // no buffers, reads/writes here - val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val startingSc = SimContext(records = Map(0 -> Record())) // running with only 1 invocation val v1 = ComposeVec4[Float32](1f, 2f, 3f, 4f) - val SimContext(res1, records1, _) = Simulate.sim(v1, startingRecords) + val sc1 = Simulate.sim(v1, startingSc) val exp1 = Vector(1f, 2f, 3f, 4f) - assert(res1(0) == exp1, s"Expected $exp1, got ${res1(0)}") + val res1 = sc1.results(0) + assert(res1 == exp1, s"Expected $exp1, got $res1") val i: Int32 = 2 val expr = ExtractScalar(fromExpr(v1), i) - val SimContext(res2, records2, _) = Simulate.sim(expr, records1) + val sc2 = Simulate.sim(expr, sc1) val exp2 = 3f - assert(res2(0) == exp2, s"Expected $exp2, got ${res2(0)}") + val res2 = sc2.results(0) + assert(res2 == exp2, s"Expected $exp2, got $res2") val v2 = ScalarProd(fromExpr(v1), -1f) - val SimContext(res3, records3, _) = Simulate.sim(v2, records2) + val sc3 = Simulate.sim(v2, sc2) val exp3 = Vector(-1f, -2f, -3f, -4f) - assert(res3(0) == exp3, s"Expected $exp3, got ${res3(0)}") + val res3 = sc3.results(0) + assert(res3 == exp3, s"Expected $exp3, got $res3") val v3 = ComposeVec4[Float32](-4f, -3f, 2f, 1f) val dot = DotProd(fromExpr(v1), fromExpr(v3)) - val SimContext(results, records4, _) = Simulate.sim(dot, records3) + val SimContext(results, _, _, _) = Simulate.sim(dot, sc3) val exp4 = 0f val res4 = results(0).asInstanceOf[Float] assert(Math.abs(res4 - exp4) < 0.001f, s"Expected $exp4, got $res4") test("simulate bitwise ops"): - given SimData = SimData() // no buffers, reads/writes here - val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val startingSc = SimContext(records = Map(0 -> Record())) // running with only 1 invocation val a: Int32 = 5 val by: UInt32 = 3 @@ -81,18 +83,17 @@ class SimulateE2eTest extends munit.FunSuite: val or = BitwiseOr(fromExpr(left), fromExpr(right)) val xor = BitwiseXor(fromExpr(and), fromExpr(or)) - val SimContext(res, records1, _) = Simulate.sim(xor, startingRecords) + val SimContext(res, _, _, _) = Simulate.sim(xor, startingSc) val exp = ((~5 << 3) & (~5 >> 3)) ^ ((~5 << 3) | (~5 >> 3)) assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate should not stack overflow"): - given SimData = SimData() // no buffers, reads/writes here - val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val startingSc = SimContext(records = Map(0 -> Record())) // running with only 1 invocation val a: Int32 = 1 var sum = Sum(a, a) // 2 for _ <- 0 until 1000000 do sum = Sum(a, fromExpr(sum)) - val SimContext(res, records, _) = Simulate.sim(sum, startingRecords) + val SimContext(res, _, _, _) = Simulate.sim(sum, startingSc) val exp = 1000002 assert(res(0) == exp, s"Expected $exp, got ${res(0)}") @@ -102,11 +103,11 @@ class SimulateE2eTest extends munit.FunSuite: val buffer = SimGBuffer[Int32]() val array = (0 until 1024).toArray[Result] - given SimData = SimData().addBuffer(buffer, array) - val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val data = SimData().addBuffer(buffer, array) + val startingSc = SimContext(records = Map(0 -> Record()), data = data) // running with only 1 invocation val expr = ReadBuffer(buffer, 128) - val SimContext(res, records, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, records, _, _) = Simulate.sim(expr, startingSc) val exp = 128 assert(res(0) == exp, s"Expected $exp, got $res") diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala index 371fb9ec..09619a7b 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/SimulateWhenTests.scala @@ -7,8 +7,7 @@ import izumi.reflect.Tag class SimulateWhenE2eTest extends munit.FunSuite: test("simulate when"): - given SimData = SimData() // no buffers, reads/writes here - val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val startingSc = SimContext(records = Map(0 -> Record())) // running with only 1 invocation val expr = WhenExpr( when = 2 >= 1, // true @@ -17,13 +16,12 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val SimContext(res, _, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, _, _, _) = Simulate.sim(expr, startingSc) val exp = 1 assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate elseWhen first"): - given SimData = SimData() // no buffers, reads/writes here - val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val startingSc = SimContext(records = Map(0 -> Record())) // running with only 1 invocation val expr = WhenExpr( when = 2 <= 1, // false @@ -32,13 +30,12 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val SimContext(res, _, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, _, _, _) = Simulate.sim(expr, startingSc) val exp = 2 assert(res(0) == exp, s"Expected $exp, got ${res(0)}") test("simulate elseWhen second"): - given SimData = SimData() // no buffers, reads/writes here - val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val startingSc = SimContext(records = Map(0 -> Record())) // running with only 1 invocation val expr = WhenExpr( when = 2 <= 1, // false @@ -47,13 +44,12 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val SimContext(res, _, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, _, _, _) = Simulate.sim(expr, startingSc) val exp = 4 assert(res(0) == exp, s"Expected $exp, got $res") test("simulate otherwise"): - given SimData = SimData() // no buffers, reads/writes here - val startingRecords = Map(0 -> Record()) // running with only 1 invocation + val startingSc = SimContext(records = Map(0 -> Record())) // running with only 1 invocation val expr = WhenExpr( when = 2 <= 1, // false @@ -62,7 +58,7 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(ConstInt32(2)), Scope(ConstInt32(4))), otherwise = Scope(ConstInt32(3)), ) - val SimContext(res, _, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, _, _, _) = Simulate.sim(expr, startingSc) val exp = 3 assert(res(0) == exp, s"Expected $exp, got $res") @@ -71,8 +67,9 @@ class SimulateWhenE2eTest extends munit.FunSuite: val buffer = SimGBuffer[Int32]() val array = (0 until 3).toArray[Result] - given SimData = SimData().addBuffer(buffer, array) + val data = SimData().addBuffer(buffer, array) val startingRecords = Map(0 -> Record(), 1 -> Record(), 2 -> Record()) // running 3 invocations + val startingSc = SimContext(records = startingRecords, data = data) val a: Int32 = 4 val invocId = InvocationId @@ -93,6 +90,6 @@ class SimulateWhenE2eTest extends munit.FunSuite: otherCaseCodes = List(Scope(expr2)), // _ _ 12 otherwise = Scope(expr3), // _ 3 _ ) - val SimContext(res, records, _) = Simulate.sim(expr, startingRecords) + val SimContext(res, _, _, _) = Simulate.sim(expr, startingSc) val exp = Map(0 -> 0, 1 -> 3, 2 -> 12) assert(res == exp, s"Expected $exp, got $res") diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala index 9c033244..52e2eaf2 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala @@ -11,22 +11,27 @@ object Interpreter: private def interpretWriteBuffer(gio: WriteBuffer[?], sc: SimContext): SimContext = gio match case WriteBuffer(buffer, index, value) => - val sc1 = Simulate.sim(index, sc) // get the write index for each invocation - val SimContext(writeVals, records, data) = Simulate.sim(value, sc1) // get the values to be written + val indexSc = Simulate.sim(index, sc) // get the write index for each invocation + val SimContext(writeVals, records, data, profs) = Simulate.sim(value, indexSc) // get the values to be written // write the values to the buffer, update records with writes - val indices = sc1.results + val indices = indexSc.results val newData = data.writeToBuffer(buffer, indices, writeVals) val writes = indices.map: (invocId, ind) => invocId -> WriteBuf(buffer, ind.asInstanceOf[Int], writeVals(invocId)) val newRecords = records.addWrites(writes) - SimContext(writeVals, newRecords, newData) + // check if the write addresses coalesced or not + val addresses = indices.values.toSeq.map(_.asInstanceOf[Int]) + val profile = WriteProfile(buffer, addresses) + val coalesceProfile = CoalesceProfile(addresses, profile) + + SimContext(writeVals, newRecords, newData, coalesceProfile :: profs) private def interpretWriteUniform(gio: WriteUniform[?], sc: SimContext): SimContext = gio match case WriteUniform(uniform, value) => // get the uniform value to be written (same for all invocations) - val SimContext(writeVals, records, data) = Simulate.sim(value, sc) + val SimContext(writeVals, records, data, profs) = Simulate.sim(value, sc) // write the (single) value to the uniform, update records with writes val uniVal = writeVals.values.head @@ -34,7 +39,7 @@ object Interpreter: val newData = data.write(WriteUni(uniform, uniVal)) val newRecords = records.addWrites(writes) - SimContext(writeVals, newRecords, newData) + SimContext(writeVals, newRecords, newData, profs) private def interpretOne(gio: GIO[?], sc: SimContext): SimContext = gio match case p: Pure[?] => interpretPure(p, sc) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala index 893f9919..528cb0b3 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala @@ -12,3 +12,19 @@ enum Write: case WriteBuf(buffer: GBuffer[?], index: Int, value: Result) case WriteUni(uni: GUniform[?], value: Result) export Write.* + +enum Profile: + case ReadProfile(treeid: TreeId, addresses: Seq[Int]) + case WriteProfile(buffer: GBuffer[?], addresses: Seq[Int]) +export Profile.* + +enum CoalesceProfile: + case Coalesced(startAddress: Int, endAddress: Int, profile: Profile) + case NotCoalesced(profile: Profile) +import CoalesceProfile.* + +object CoalesceProfile: + def apply(addresses: Seq[Int], profile: Profile): CoalesceProfile = + val (start, end) = (addresses.min, addresses.max) + val coalesced = end - start + 1 == addresses.length + if coalesced then Coalesced(start, end, profile) else NotCoalesced(profile) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala index 248ea76f..6da5faa8 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/SimContext.scala @@ -2,10 +2,10 @@ package io.computenode.cyfra.interpreter type Results = Map[InvocId, Result] -extension (r: Results) +extension (results: Results) // assumes both results have the same set of keys. def join(that: Results)(op: (Result, Result) => Result): Results = - r.map: (invocId, res) => + results.map: (invocId, res) => invocId -> op(res, that(invocId)) -case class SimContext(results: Results, records: Records, data: SimData) +case class SimContext(results: Results = Map(), records: Records, data: SimData = SimData(), profs: List[CoalesceProfile] = Nil) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala index 88a7a085..2ee72399 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala @@ -9,24 +9,27 @@ import io.computenode.cyfra.spirv.BlockBuilder.buildBlock object Simulate: import Result.* - // Some helpful overloads to simulate values instead of expressions - def sim(v: Value, sc: SimContext): SimContext = sim(v, sc.records)(using sc.data) - def sim(v: Value, records: Records)(using data: SimData = SimData()): SimContext = sim(v.tree, records) + // Helpful overload to simulate values instead of expressions + def sim(v: Value, sc: SimContext): SimContext = sim(v.tree, sc) // for evaluating expressions that don't cause any writes (therefore don't change data) - def sim(e: Expression[?], records: Records)(using SimData): SimContext = simIterate(buildBlock(e), records) + def sim(e: Expression[?], sc: SimContext): SimContext = simIterate(buildBlock(e), sc) @annotation.tailrec - def simIterate(blocks: List[Expression[?]], records: Records, results: Results = Map())(using data: SimData): SimContext = blocks match - case head :: next => // reads have to be treated specially, since they will update the records - val (newResults, records1) = head match - case e: ReadBuffer[?] => simReadBuffer(e, records) // records updated with reads - case e: ReadUniform[?] => simReadUniform(e, records) - case e: WhenExpr[?] => simWhen(e, records) - case _ => (simOne(head)(using records), records) // no reads, records don't change - val newRecords = records1.updateResults(head.treeid, newResults) // update caches with new results - simIterate(next, newRecords, newResults) - case Nil => SimContext(results, records, data) + def simIterate(blocks: List[Expression[?]], sc: SimContext): SimContext = + val SimContext(results, records, data, profs) = sc + blocks match + case head :: next => + val SimContext(newResults, records1, _, newProfs) = head match + case e: ReadBuffer[?] => simReadBuffer(e, sc) + case e: ReadUniform[?] => + val (res, rec) = simReadUniform(e, records)(using data) + SimContext(res, rec, data, profs) + case e: WhenExpr[?] => simWhen(e, sc) + case _ => SimContext(simOne(head)(using records, data), records, data, profs) + val newRecords = records1.updateResults(head.treeid, newResults) // update caches with new results + simIterate(next, SimContext(newResults, newRecords, data, newProfs)) + case Nil => sc // in these cases, the records don't change since there are no reads. def simOne(e: Expression[?])(using records: Records, data: SimData): Results = e match @@ -140,24 +143,29 @@ object Simulate: resultsSoFar: Results, finishedRecords: Records, pendingRecords: Records, - )(using SimData): (Results, Records) = - if pendingRecords.isEmpty then (resultsSoFar, finishedRecords) + sc: SimContext, + ): SimContext = + if pendingRecords.isEmpty then sc else // scopes are not included in caches, they have to be simulated from scratch. // there could be reads happening in scopes, records have to be updated. // scopes can still read from the outer SimData. - val SimContext(boolResults, records1, _) = sim(when, pendingRecords) // SimData does not change. + val pendingSc = SimContext(Map(), pendingRecords, sc.data, sc.profs) + val SimContext(boolResults, boolRecords, boolData, boolProfs) = sim(when, pendingSc) // Split invocations that enter this branch. - val (enterRecords, newPendingRecords) = records1.partition((invocId, _) => boolResults(invocId).asInstanceOf[Boolean]) + val (enterRecords, newPendingRecords) = boolRecords.partition((invocId, _) => boolResults(invocId).asInstanceOf[Boolean]) // Only those invocs that enter the branch will have their records updated with thenCode result. - val SimContext(thenResults, thenRecords, _) = sim(thenCode.expr, enterRecords) + val enterSc = SimContext(Map(), enterRecords, boolData, boolProfs) + val thenSc = sim(thenCode.expr, enterSc) + val SimContext(thenResults, thenRecords, thenData, thenProfs) = thenSc otherConds.headOption match case None => // run pending invocs on otherwise, collect all results and records, done - val SimContext(owResults, owRecords, _) = sim(otherwise.expr, newPendingRecords) - (resultsSoFar ++ thenResults ++ owResults, finishedRecords ++ thenRecords ++ owRecords) + val newPendingSc = SimContext(Map(), newPendingRecords, thenData, thenProfs) + val SimContext(owResults, owRecords, owData, owProfs) = sim(otherwise.expr, newPendingSc) + SimContext(resultsSoFar ++ thenResults ++ owResults, finishedRecords ++ thenRecords ++ owRecords, owData, owProfs) case Some(cond) => whenHelper( when = cond.expr, @@ -168,19 +176,28 @@ object Simulate: resultsSoFar = resultsSoFar ++ thenResults, finishedRecords = finishedRecords ++ thenRecords, pendingRecords = newPendingRecords, + sc = thenSc, ) - private def simWhen(e: WhenExpr[?], records: Records)(using SimData): (Results, Records) = e match + private def simWhen(e: WhenExpr[?], sc: SimContext): SimContext = e match case WhenExpr(when, thenCode, otherConds, otherCaseCodes, otherwise) => - whenHelper(when.tree, thenCode, otherConds, otherCaseCodes, otherwise, Map(), Map(), records) - - private def simReadBuffer(e: ReadBuffer[?], records: Records)(using data: SimData): (Results, Records) = e match - case ReadBuffer(buffer, index) => - val indices = records.view.mapValues(_.cache(index.tree.treeid).asInstanceOf[Int]).toMap - val readValues = indices.view.mapValues(i => data.lookup(buffer, i)).toMap - val newRecords = records.map: (invocId, record) => - invocId -> record.addRead(ReadBuf(e.treeid, buffer, indices(invocId), readValues(invocId))) - (readValues, newRecords) + whenHelper(when.tree, thenCode, otherConds, otherCaseCodes, otherwise, Map(), Map(), sc.records, sc) + + private def simReadBuffer(e: ReadBuffer[?], sc: SimContext): SimContext = + val SimContext(_, records, data, profs) = sc + e match + case ReadBuffer(buffer, index) => + val indices = records.view.mapValues(_.cache(index.tree.treeid).asInstanceOf[Int]).toMap + val readValues = indices.view.mapValues(i => data.lookup(buffer, i)).toMap + val newRecords = records.map: (invocId, record) => + invocId -> record.addRead(ReadBuf(e.treeid, buffer, indices(invocId), readValues(invocId))) + + // check if the read addresses coalesced or not + val addresses = indices.values.toSeq + val profile = ReadProfile(e.treeid, addresses) + val coalesceProfile = CoalesceProfile(addresses, profile) + + SimContext(readValues, newRecords, data, coalesceProfile :: profs) private def simReadUniform(e: ReadUniform[?], records: Records)(using data: SimData): (Results, Records) = e match case ReadUniform(uniform) => From 4a12a4e5c65bfa8625dc1f7bc0c0e915fce2662f Mon Sep 17 00:00:00 2001 From: spamegg Date: Sat, 9 Aug 2025 14:26:20 +0300 Subject: [PATCH 18/59] add race condition logic and Idle periods --- .../io/computenode/cyfra/interpreter/ReadWrite.scala | 12 +++++++++--- .../io/computenode/cyfra/interpreter/Record.scala | 8 ++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala index 528cb0b3..aacf6551 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala @@ -19,12 +19,18 @@ enum Profile: export Profile.* enum CoalesceProfile: + case RaceCondition(profile: Profile) case Coalesced(startAddress: Int, endAddress: Int, profile: Profile) case NotCoalesced(profile: Profile) import CoalesceProfile.* object CoalesceProfile: def apply(addresses: Seq[Int], profile: Profile): CoalesceProfile = - val (start, end) = (addresses.min, addresses.max) - val coalesced = end - start + 1 == addresses.length - if coalesced then Coalesced(start, end, profile) else NotCoalesced(profile) + val length = addresses.length + val distinct = addresses.distinct.length == length + if !distinct then RaceCondition(profile) + else + val (start, end) = (addresses.min, addresses.max) + val coalesced = end - start + 1 == length + if coalesced then Coalesced(start, end, profile) + else NotCoalesced(profile) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala index 0971d3d6..50f9e9b8 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala @@ -9,7 +9,9 @@ type Cache = Map[TreeId, Result] type InvocId = Int type Records = Map[InvocId, Record] -case class Record(cache: Cache = Map(), writes: List[Write] = Nil, reads: List[Read] = Nil): +case class Idle(treeid: TreeId, length: Int) + +case class Record(cache: Cache = Map(), writes: List[Write] = Nil, reads: List[Read] = Nil, idles: List[Idle] = Nil): def addRead(read: Read): Record = read match case ReadBuf(_, _, _, _) => copy(reads = read :: reads) case ReadUni(_, _, _) => copy(reads = read :: reads) @@ -18,7 +20,9 @@ case class Record(cache: Cache = Map(), writes: List[Write] = Nil, reads: List[R case WriteBuf(_, _, _) => copy(writes = write :: writes) case WriteUni(_, _) => copy(writes = write :: writes) - def addResult(treeId: TreeId, res: Result) = copy(cache = cache.updated(treeId, res)) + def addResult(treeid: TreeId, res: Result) = copy(cache = cache.updated(treeid, res)) + + def addIdle(treeid: TreeId, length: Int) = copy(idles = Idle(treeid, length) :: idles) extension (records: Records) def apply(invocIds: Seq[InvocId]): Records = invocIds.map(invocId => invocId -> Record()).toMap From db2eb0c1094b7d5f30a6fd081ef1992a32919212 Mon Sep 17 00:00:00 2001 From: spamegg Date: Tue, 12 Aug 2025 18:51:13 +0300 Subject: [PATCH 19/59] progress on filter: upsweep and downsweep --- .../computenode/cyfra/fs2interop/GPipe.scala | 75 ++++++++++++++++++- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index d3868465..2e0e6a28 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -3,7 +3,7 @@ package io.computenode.cyfra.fs2interop import io.computenode.cyfra.core.archive.*, mem.*, GMem.fRGBA import io.computenode.cyfra.core.{Allocation, layout}, layout.Layout import io.computenode.cyfra.core.{CyfraRuntime, GBufferRegion, GExecution, GProgram} -import io.computenode.cyfra.dsl.{*, given}, gio.GIO, binding.GBuffer +import io.computenode.cyfra.dsl.{*, given}, gio.GIO, binding.{GBuffer, GUniform, GBinding} import io.computenode.cyfra.spirv.SpirvTypes.typeStride import struct.GStruct, GStruct.Empty, Empty.given @@ -33,15 +33,15 @@ object GPipe: ): layout => val invocId = GIO.invocationId val element = GIO.read[C1](layout.in, invocId) - GIO.write[C2](layout.out, invocId, f(element)) // implicit bug + GIO.write[C2](layout.out, invocId, f(element)) val execution = GExecution[Params, PLayout]() .addProgram(gProg)(params => Params(params.inSize), layout => PLayout(layout.in, layout.out)) val region = GBufferRegion - .allocate[PLayout] // implicit bug + .allocate[PLayout] .map: pLayout => - execution.execute(params, pLayout) // implicit bug + execution.execute(params, pLayout) // these are allocated once, reused for many chunks val inBuf = BufferUtils.createByteBuffer(params.inSize * inTypeSize) @@ -58,6 +58,73 @@ object GPipe: def gPipeMap[F[_], C <: Value: FromExpr: Tag, S: ClassTag](f: C => C)(using CyfraRuntime, Bridge[C, S]): Pipe[F, S, S] = gPipeMap[F, C, C, S, S](f) + // https://developer.nvidia.com/gpugems/gpugems3/part-vi-gpu-computing/chapter-39-parallel-prefix-sum-scan-cuda + // Prefix Sum and Stream Compaction + // 11 + // 012345678901 index + // [abcdefghijkl] starting collection + // [tfftfftttftf] convert to booleans + // [100100111010] integer equivalent + // [0111222345566] scan prefixsum, last number tells us the size of filtered collection + // [x..x..xxx.x.] take the indexes where the next scan number is 1 bigger. + // [adhijl] compact the collection + // 012345 prefixsum results are the new indices in compacted collection + def gPipeFilter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: Bridge[C, S]): Pipe[F, S, S] = + (stream: Stream[F, S]) => + case class Params(inSize: Int, intervalSize: Int) + case class PredLayout(cIn: GBuffer[C], boolOut: GBuffer[Int32]) extends Layout + case class ScanArgs(intervalSize: Int32) extends GStruct[ScanArgs] + case class ScanLayout(intIn: GBuffer[Int32], intOut: GBuffer[Int32], intervalSize: GUniform[ScanArgs]) extends Layout + case class CompactionLayout(cIn: GBuffer[C], intIn: GBuffer[Int32], out: GBuffer[C]) extends Layout + case class FilterResult(cOut: GBuffer[C]) extends Layout + + val predicateProgram = GProgram[Params, PredLayout]( + layout = params => PredLayout(cIn = GBuffer[C](params.inSize), boolOut = GBuffer[Int32](params.inSize)), + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), + ): layout => + val invocId = GIO.invocationId + val element = GIO.read[C](layout.cIn, invocId) + GIO.write[Int32](layout.boolOut, invocId, when(pred(element))(1: Int32).otherwise(0)) + + val upsweep = GProgram[Params, ScanLayout]( + layout = params => + ScanLayout( + intIn = GBuffer[Int32](params.inSize / params.intervalSize), + intOut = GBuffer[Int32](params.inSize), + intervalSize = GUniform(ScanArgs(params.intervalSize)), + ), + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize, 1, 1)), + ): layout => + val ScanArgs(size) = layout.intervalSize.read + val invocId = GIO.invocationId + val root = invocId * size + val mid = root + (size / 2) - 1 + val end = root + size - 1 + val oldValue = GIO.read[Int32](layout.intOut, end) + val addValue = GIO.read[Int32](layout.intOut, mid) + val newValue = oldValue + addValue + GIO.write[Int32](layout.intOut, end, newValue) + + val downsweep = GProgram[Params, ScanLayout]( + layout = params => + ScanLayout( + intIn = GBuffer[Int32](params.inSize / params.intervalSize), + intOut = GBuffer[Int32](params.inSize), + intervalSize = GUniform(ScanArgs(params.intervalSize)), + ), + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize, 1, 1)), + ): layout => + val ScanArgs(size) = layout.intervalSize.read + val invocId = GIO.invocationId + val root = invocId * size - 1 // if invocId = 0, this is -1 (out of bounds) + val mid = root + (size / 2) + val oldValue = GIO.read[Int32](layout.intOut, mid) + val addValue = when(root > 0)(GIO.read[Int32](layout.intOut, root)).otherwise(0) + val newValue = oldValue + addValue + GIO.write[Int32](layout.intOut, mid, newValue) + + ??? + // legacy stuff working with GFunction extension (stream: Stream[Pure, Float]) def gPipeFloat(fn: Float32 => Float32)(using GContext): Stream[Pure, Float] = From 386e101a30741ff66518c6d0993ef4a66a9ca6df Mon Sep 17 00:00:00 2001 From: spamegg Date: Wed, 13 Aug 2025 18:49:34 +0300 Subject: [PATCH 20/59] progress on upsweep / downsweep phases --- .../computenode/cyfra/fs2interop/GPipe.scala | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 2e0e6a28..abc50120 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -61,21 +61,21 @@ object GPipe: // https://developer.nvidia.com/gpugems/gpugems3/part-vi-gpu-computing/chapter-39-parallel-prefix-sum-scan-cuda // Prefix Sum and Stream Compaction // 11 - // 012345678901 index - // [abcdefghijkl] starting collection - // [tfftfftttftf] convert to booleans - // [100100111010] integer equivalent - // [0111222345566] scan prefixsum, last number tells us the size of filtered collection - // [x..x..xxx.x.] take the indexes where the next scan number is 1 bigger. - // [adhijl] compact the collection - // 012345 prefixsum results are the new indices in compacted collection + // 012345678901 index + // [abcdefghijkl] starting collection + // [tfftfftttftf] convert to booleans + // [100100111010] integer equivalent + // [111222345566] prefixsum, last number tells us the size of filtered collection + // [x..x..xxx.x.] take the ones that are 1 bigger than previous. + // [adhijl] compact the collection + // 012345 (prefixsum result - 1) are the new indices in compacted collection def gPipeFilter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: Bridge[C, S]): Pipe[F, S, S] = (stream: Stream[F, S]) => case class Params(inSize: Int, intervalSize: Int) case class PredLayout(cIn: GBuffer[C], boolOut: GBuffer[Int32]) extends Layout case class ScanArgs(intervalSize: Int32) extends GStruct[ScanArgs] case class ScanLayout(intIn: GBuffer[Int32], intOut: GBuffer[Int32], intervalSize: GUniform[ScanArgs]) extends Layout - case class CompactionLayout(cIn: GBuffer[C], intIn: GBuffer[Int32], out: GBuffer[C]) extends Layout + case class CompactLayout(cIn: GBuffer[C], intIn: GBuffer[Int32], out: GBuffer[C]) extends Layout case class FilterResult(cOut: GBuffer[C]) extends Layout val predicateProgram = GProgram[Params, PredLayout]( @@ -86,6 +86,9 @@ object GPipe: val element = GIO.read[C](layout.cIn, invocId) GIO.write[Int32](layout.boolOut, invocId, when(pred(element))(1: Int32).otherwise(0)) + val predicateExec = GExecution[Params, PredLayout]() + .addProgram(predicateProgram)(params => Params(256, 2), layout => PredLayout(layout.cIn, layout.boolOut)) + val upsweep = GProgram[Params, ScanLayout]( layout = params => ScanLayout( @@ -123,6 +126,31 @@ object GPipe: val newValue = oldValue + addValue GIO.write[Int32](layout.intOut, mid, newValue) + @annotation.tailrec + def upsweepPhases(exec: GExecution[Params, ScanLayout, ?], inSize: Int, intervalSize: Int): GExecution[Params, ScanLayout, ?] = + if intervalSize >= inSize then exec + else + val newExec = exec.addProgram(upsweep)(params => Params(inSize, intervalSize), layout => layout) + upsweepPhases(newExec, inSize, intervalSize * 2) + + val upsweepInitialExec = GExecution[Params, ScanLayout]() + val upsweepExec = upsweepPhases(upsweepInitialExec, 256, 2) + + @annotation.tailrec + def downsweepPhases(exec: GExecution[Params, ScanLayout, ?], inSize: Int, intervalSize: Int): GExecution[Params, ScanLayout, ?] = + if intervalSize < 2 then exec + else + val newExec = exec.addProgram(downsweep)(params => Params(inSize, intervalSize), layout => layout) + downsweepPhases(newExec, inSize, intervalSize / 2) + + val downsweepExec = downsweepPhases(upsweepInitialExec, 256, 128) + + val startParams = Params(256, 2) + // val region = GBufferRegion + // .allocate[ScanLayout] + // .map: region => + // upsweepExec.execute(startParams, region) + ??? // legacy stuff working with GFunction From 3ea8eb9e31d1966d86259d18ecb59cef98c5ceee Mon Sep 17 00:00:00 2001 From: spamegg Date: Sat, 16 Aug 2025 15:36:48 +0300 Subject: [PATCH 21/59] factor out legacy gPipe code --- .../cyfra/e2e/fs2interop/Fs2Tests.scala | 1 + .../computenode/cyfra/fs2interop/GPipe.scala | 136 ++++++++---------- .../cyfra/fs2interop/GPipeLegacy.scala | 39 +++++ 3 files changed, 101 insertions(+), 75 deletions(-) create mode 100644 cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipeLegacy.scala diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala index 2339a22f..20c04b9d 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala @@ -42,6 +42,7 @@ class Fs2Tests extends munit.FunSuite: class Fs2LegacyTests extends munit.FunSuite: given gc: GContext = GContext() + import GPipeLegacy.* test("fs2 Float stream (legacy)"): val inSeq = (0 to 255).map(_.toFloat) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index abc50120..439973d6 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -51,7 +51,7 @@ object GPipe: .chunkMin(params.inSize) .flatMap: chunk => bridge1.toByteBuffer(inBuf, chunk) - region.runUnsafe(init = PLayout(in = GBuffer[C1](inBuf), out = GBuffer[C2](outBuf)), onDone = layout => layout.out.read(outBuf)) // implicit bug + region.runUnsafe(init = PLayout(in = GBuffer[C1](inBuf), out = GBuffer[C2](outBuf)), onDone = layout => layout.out.read(outBuf)) Stream.emits(bridge2.fromByteBuffer(outBuf, new Array[S2](params.inSize))) // Syntax sugar for convenient single type version @@ -71,31 +71,31 @@ object GPipe: // 012345 (prefixsum result - 1) are the new indices in compacted collection def gPipeFilter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: Bridge[C, S]): Pipe[F, S, S] = (stream: Stream[F, S]) => - case class Params(inSize: Int, intervalSize: Int) - case class PredLayout(cIn: GBuffer[C], boolOut: GBuffer[Int32]) extends Layout - case class ScanArgs(intervalSize: Int32) extends GStruct[ScanArgs] - case class ScanLayout(intIn: GBuffer[Int32], intOut: GBuffer[Int32], intervalSize: GUniform[ScanArgs]) extends Layout - case class CompactLayout(cIn: GBuffer[C], intIn: GBuffer[Int32], out: GBuffer[C]) extends Layout - case class FilterResult(cOut: GBuffer[C]) extends Layout - val predicateProgram = GProgram[Params, PredLayout]( - layout = params => PredLayout(cIn = GBuffer[C](params.inSize), boolOut = GBuffer[Int32](params.inSize)), + // Predicate mapping + case class PredParams(inSize: Int) + case class PredLayout(in: GBuffer[C], out: GBuffer[Int32]) extends Layout + + val predicateProgram = GProgram[PredParams, PredLayout]( + layout = params => PredLayout(in = GBuffer[C](params.inSize), out = GBuffer[Int32](params.inSize)), dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), ): layout => val invocId = GIO.invocationId - val element = GIO.read[C](layout.cIn, invocId) - GIO.write[Int32](layout.boolOut, invocId, when(pred(element))(1: Int32).otherwise(0)) - - val predicateExec = GExecution[Params, PredLayout]() - .addProgram(predicateProgram)(params => Params(256, 2), layout => PredLayout(layout.cIn, layout.boolOut)) - - val upsweep = GProgram[Params, ScanLayout]( - layout = params => - ScanLayout( - intIn = GBuffer[Int32](params.inSize / params.intervalSize), - intOut = GBuffer[Int32](params.inSize), - intervalSize = GUniform(ScanArgs(params.intervalSize)), - ), + val element = GIO.read[C](layout.in, invocId) + val result = when(pred(element))(1: Int32).otherwise(0) + GIO.write[Int32](layout.out, invocId, result) + + val predExec = GExecution[PredParams, PredLayout]() + .addProgram(predicateProgram)(params => params, layout => layout) + val predParams = PredParams(256) + + // Prefix sum (inclusive), upsweep/downsweep + case class ScanParams(inSize: Int, intervalSize: Int) + case class ScanArgs(intervalSize: Int32) extends GStruct[ScanArgs] + case class ScanLayout(ints: GBuffer[Int32], intervalSize: GUniform[ScanArgs]) extends Layout + + val upsweep = GProgram[ScanParams, ScanLayout]( + layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read @@ -103,83 +103,69 @@ object GPipe: val root = invocId * size val mid = root + (size / 2) - 1 val end = root + size - 1 - val oldValue = GIO.read[Int32](layout.intOut, end) - val addValue = GIO.read[Int32](layout.intOut, mid) + val oldValue = GIO.read[Int32](layout.ints, end) + val addValue = GIO.read[Int32](layout.ints, mid) val newValue = oldValue + addValue - GIO.write[Int32](layout.intOut, end, newValue) - - val downsweep = GProgram[Params, ScanLayout]( - layout = params => - ScanLayout( - intIn = GBuffer[Int32](params.inSize / params.intervalSize), - intOut = GBuffer[Int32](params.inSize), - intervalSize = GUniform(ScanArgs(params.intervalSize)), - ), + GIO.write[Int32](layout.ints, end, newValue) + + val downsweep = GProgram[ScanParams, ScanLayout]( + layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read val invocId = GIO.invocationId val root = invocId * size - 1 // if invocId = 0, this is -1 (out of bounds) val mid = root + (size / 2) - val oldValue = GIO.read[Int32](layout.intOut, mid) - val addValue = when(root > 0)(GIO.read[Int32](layout.intOut, root)).otherwise(0) + val oldValue = GIO.read[Int32](layout.ints, mid) + val addValue = when(root > 0)(GIO.read[Int32](layout.ints, root)).otherwise(0) val newValue = oldValue + addValue - GIO.write[Int32](layout.intOut, mid, newValue) + GIO.write[Int32](layout.ints, mid, newValue) @annotation.tailrec - def upsweepPhases(exec: GExecution[Params, ScanLayout, ?], inSize: Int, intervalSize: Int): GExecution[Params, ScanLayout, ?] = + def upsweepPhases(exec: GExecution[ScanParams, ScanLayout, ?], inSize: Int, intervalSize: Int): GExecution[ScanParams, ScanLayout, ?] = if intervalSize >= inSize then exec else - val newExec = exec.addProgram(upsweep)(params => Params(inSize, intervalSize), layout => layout) + val newExec = exec.addProgram(upsweep)(params => ScanParams(inSize, intervalSize), layout => layout) upsweepPhases(newExec, inSize, intervalSize * 2) - val upsweepInitialExec = GExecution[Params, ScanLayout]() + val upsweepInitialExec = GExecution[ScanParams, ScanLayout]() val upsweepExec = upsweepPhases(upsweepInitialExec, 256, 2) @annotation.tailrec - def downsweepPhases(exec: GExecution[Params, ScanLayout, ?], inSize: Int, intervalSize: Int): GExecution[Params, ScanLayout, ?] = + def downsweepPhases(exec: GExecution[ScanParams, ScanLayout, ?], inSize: Int, intervalSize: Int): GExecution[ScanParams, ScanLayout, ?] = if intervalSize < 2 then exec else - val newExec = exec.addProgram(downsweep)(params => Params(inSize, intervalSize), layout => layout) + val newExec = exec.addProgram(downsweep)(params => ScanParams(inSize, intervalSize), layout => layout) downsweepPhases(newExec, inSize, intervalSize / 2) val downsweepExec = downsweepPhases(upsweepInitialExec, 256, 128) + val scanParams = ScanParams(256, 2) - val startParams = Params(256, 2) - // val region = GBufferRegion - // .allocate[ScanLayout] - // .map: region => - // upsweepExec.execute(startParams, region) + // Stream compaction + case class CompactLayout(in: GBuffer[C], intIn: GBuffer[Int32], out: GBuffer[C]) extends Layout + case class FilterResult(cOut: GBuffer[C]) extends Layout + // TODO implement compaction - ??? + // TODO: connect all the layouts/executions into one + case class PredScanCompactLayout() extends Layout + case class Result(out: GBuffer[C]) extends Layout - // legacy stuff working with GFunction - extension (stream: Stream[Pure, Float]) - def gPipeFloat(fn: Float32 => Float32)(using GContext): Stream[Pure, Float] = - val gf: GFunction[Empty, Float32, Float32] = GFunction(fn) - stream - .chunkMin(256) - .flatMap: chunk => - val gmem = FloatMem(chunk.toArray) - val res = gmem.map(gf).asInstanceOf[FloatMem].toArray - Stream.emits(res) + val region = GBufferRegion // TODO fix this! + .allocate[PredLayout] + .map: layout => + predExec.execute(predParams, layout) - extension (stream: Stream[Pure, Int]) - def gPipeInt(fn: Int32 => Int32)(using GContext): Stream[Pure, Int] = - val gf: GFunction[Empty, Int32, Int32] = GFunction(fn) - stream - .chunkMin(256) - .flatMap: chunk => - val gmem = IntMem(chunk.toArray) - val res = gmem.map(gf).asInstanceOf[IntMem].toArray - Stream.emits(res) + val typeSize = typeStride(Tag.apply[C]) - extension (stream: Stream[Pure, fRGBA]) - def gPipeVec4(fn: Vec4[Float32] => Vec4[Float32])(using GContext): Stream[Pure, fRGBA] = - val gf: GFunction[Empty, Vec4[Float32], Vec4[Float32]] = GFunction(fn) - stream - .chunkMin(256) - .flatMap: chunk => - val gmem = Vec4FloatMem(chunk.toArray) - val res = gmem.map(gf).asInstanceOf[Vec4FloatMem].toArray - Stream.emits(res) + // these are allocated once, reused for many chunks + val inBuf = BufferUtils.createByteBuffer(predParams.inSize * typeSize) + val outBuf = BufferUtils.createByteBuffer(predParams.inSize * typeSize) // TODO wrong size + + // stream + // .chunkMin(predParams.inSize) + // .flatMap: chunk => + // bridge.toByteBuffer(inBuf, chunk) + // region.runUnsafe(init = PredLayout(in = GBuffer[C](inBuf), out = GBuffer[Int32](outBuf)), onDone = layout => layout.out.read(outBuf)) + // val arr = bridge.fromByteBuffer(outBuf, new Array[S](params.inSize)) + // Stream.emits(arr) + ??? diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipeLegacy.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipeLegacy.scala new file mode 100644 index 00000000..78d36209 --- /dev/null +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipeLegacy.scala @@ -0,0 +1,39 @@ +package io.computenode.cyfra.fs2interop + +import io.computenode.cyfra.core.archive.*, mem.*, GMem.fRGBA +import io.computenode.cyfra.dsl.{*, given} +import struct.GStruct, GStruct.Empty, Empty.given + +import fs2.* + +// legacy stuff working with GFunction +object GPipeLegacy: + extension (stream: Stream[Pure, Float]) + def gPipeFloat(fn: Float32 => Float32)(using GContext): Stream[Pure, Float] = + val gf: GFunction[Empty, Float32, Float32] = GFunction(fn) + stream + .chunkMin(256) + .flatMap: chunk => + val gmem = FloatMem(chunk.toArray) + val res = gmem.map(gf).asInstanceOf[FloatMem].toArray + Stream.emits(res) + + extension (stream: Stream[Pure, Int]) + def gPipeInt(fn: Int32 => Int32)(using GContext): Stream[Pure, Int] = + val gf: GFunction[Empty, Int32, Int32] = GFunction(fn) + stream + .chunkMin(256) + .flatMap: chunk => + val gmem = IntMem(chunk.toArray) + val res = gmem.map(gf).asInstanceOf[IntMem].toArray + Stream.emits(res) + + extension (stream: Stream[Pure, fRGBA]) + def gPipeVec4(fn: Vec4[Float32] => Vec4[Float32])(using GContext): Stream[Pure, fRGBA] = + val gf: GFunction[Empty, Vec4[Float32], Vec4[Float32]] = GFunction(fn) + stream + .chunkMin(256) + .flatMap: chunk => + val gmem = Vec4FloatMem(chunk.toArray) + val res = gmem.map(gf).asInstanceOf[Vec4FloatMem].toArray + Stream.emits(res) From 3094fcbddfe57271ee62e4df0db1c7d7070ad277 Mon Sep 17 00:00:00 2001 From: MarconZet <25779550+MarconZet@users.noreply.github.com> Date: Sat, 16 Aug 2025 16:06:37 +0200 Subject: [PATCH 22/59] Improved vulkan stability (#64) --- build.sbt | 1 + .../computenode/cyfra/core/Allocation.scala | 4 +- .../src/main/resources/compileAll.sh | 0 .../cyfra/samples/TestingStuff.scala | 48 ++++++++ .../cyfra/runtime/ExecutionHandler.scala | 29 ++--- .../cyfra/runtime/VkAllocation.scala | 34 +++--- .../cyfra/runtime/VkCyfraRuntime.scala | 12 +- .../computenode/cyfra/runtime/VkShader.scala | 12 +- .../cyfra/vulkan/VulkanContext.scala | 49 +++++--- .../cyfra/vulkan/VulkanThreadContext.scala | 11 ++ .../cyfra/vulkan/command/CommandPool.scala | 16 +-- .../cyfra/vulkan/command/Fence.scala | 3 +- .../cyfra/vulkan/core/Device.scala | 109 +++--------------- .../cyfra/vulkan/core/Instance.scala | 26 ++--- .../cyfra/vulkan/core/PhysicalDevice.scala | 86 ++++++++++++++ .../computenode/cyfra/vulkan/core/Queue.scala | 6 +- .../cyfra/vulkan/memory/Allocator.scala | 6 +- .../cyfra/vulkan/memory/Buffer.scala | 17 +-- .../cyfra/vulkan/memory/DescriptorPool.scala | 9 +- .../vulkan/memory/DescriptorPoolManager.scala | 19 +++ .../cyfra/vulkan/memory/DescriptorSet.scala | 77 +++++++------ .../vulkan/memory/DescriptorSetManager.scala | 32 +++++ .../cyfra/vulkan/util/VulkanObject.scala | 9 +- .../vulkan/util/VulkanObjectHandle.scala | 7 +- 24 files changed, 382 insertions(+), 240 deletions(-) mode change 100644 => 100755 cyfra-examples/src/main/resources/compileAll.sh create mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanThreadContext.scala create mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/PhysicalDevice.scala create mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPoolManager.scala create mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSetManager.scala diff --git a/build.sbt b/build.sbt index 35a46c2c..419d75a4 100644 --- a/build.sbt +++ b/build.sbt @@ -91,6 +91,7 @@ lazy val foton = (project in file("cyfra-foton")) lazy val examples = (project in file("cyfra-examples")) .settings(commonSettings, runnerSettings) + .settings(libraryDependencies += "org.scala-lang.modules" % "scala-parallel-collections_3" % "1.2.0") .dependsOn(foton) lazy val vscode = (project in file("cyfra-vscode")) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala index 783efaff..bdc1d5a7 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala @@ -11,9 +11,9 @@ import java.nio.ByteBuffer trait Allocation: extension (buffer: GBinding[?]) - def read(bb: ByteBuffer, offset: Int = 0, size: Int = -1): Unit + def read(bb: ByteBuffer, offset: Int = 0): Unit - def write(bb: ByteBuffer, offset: Int = 0, size: Int = -1): Unit + def write(bb: ByteBuffer, offset: Int = 0): Unit extension [Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding](execution: GExecution[Params, EL, RL]) def execute(params: Params, layout: EL): RL diff --git a/cyfra-examples/src/main/resources/compileAll.sh b/cyfra-examples/src/main/resources/compileAll.sh old mode 100644 new mode 100755 diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index e604bde3..8b9a5014 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -11,6 +11,10 @@ import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.runtime.VkCyfraRuntime import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil + +import java.util.concurrent.atomic.AtomicInteger +import scala.collection.parallel.CollectionConverters.given + object TestingStuff: given GContext = GContext() @@ -228,3 +232,47 @@ object TestingStuff: assert(buf.get(i) == expected(i), s"Mismatch at index $i: expected ${expected(i)}, got ${buf.get(i)}") } } + + @main + def enduranceTest = + given runtime: VkCyfraRuntime = VkCyfraRuntime() + val bufferSize = 1280 + val params = AddProgramParams(bufferSize, addA = 0, addB = 1) + val region = GBufferRegion + .allocate[AddProgramExecLayout] + .map: region => + execution.execute(params, region) + val aInt = new AtomicInteger(0) + (1 to 10000).par.foreach: i => + val inBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) + val wbbList = inBuffers.map(MemoryUtil.memByteBuffer) + val rbbList = List.fill(5)(BufferUtils.createByteBuffer(bufferSize * 4)) + + val inData = (0 until bufferSize).toArray + inBuffers.foreach(_.put(inData).flip()) + region.runUnsafe( + init = AddProgramExecLayout( + in1 = GBuffer[Int32](wbbList(0)), + in2 = GBuffer[Int32](wbbList(1)), + in3 = GBuffer[Int32](wbbList(2)), + in4 = GBuffer[Int32](wbbList(3)), + in5 = GBuffer[Int32](wbbList(4)), + out1 = GBuffer[Int32](bufferSize), + out2 = GBuffer[Int32](bufferSize), + out3 = GBuffer[Int32](bufferSize), + out4 = GBuffer[Int32](bufferSize), + out5 = GBuffer[Int32](bufferSize), + ), + onDone = layout => { + layout.out1.read(rbbList(0)) + layout.out2.read(rbbList(1)) + layout.out3.read(rbbList(2)) + layout.out4.read(rbbList(3)) + layout.out5.read(rbbList(4)) + }, + ) + val prev = aInt.getAndAdd(1) + if prev % 100 == 0 then println(s"Iteration $prev completed") + + runtime.close() + println("Endurance test completed successfully") diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index 91b445a9..782b2a85 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -20,10 +20,11 @@ import io.computenode.cyfra.runtime.ExecutionHandler.{ import io.computenode.cyfra.runtime.ExecutionHandler.DispatchType.* import io.computenode.cyfra.runtime.ExecutionHandler.ExecutionBinding.{BufferBinding, UniformBinding} import io.computenode.cyfra.utility.Utility.timed +import io.computenode.cyfra.vulkan.{VulkanContext, VulkanThreadContext} import io.computenode.cyfra.vulkan.command.{CommandPool, Fence} import io.computenode.cyfra.vulkan.compute.ComputePipeline import io.computenode.cyfra.vulkan.core.Queue -import io.computenode.cyfra.vulkan.memory.{DescriptorPool, DescriptorSet} +import io.computenode.cyfra.vulkan.memory.{DescriptorPool, DescriptorPoolManager, DescriptorSet, DescriptorSetManager} import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import izumi.reflect.Tag import org.lwjgl.vulkan.VK10.* @@ -32,25 +33,26 @@ import org.lwjgl.vulkan.{VkCommandBuffer, VkCommandBufferBeginInfo, VkDependency import scala.collection.mutable -class ExecutionHandler(runtime: VkCyfraRuntime): - private val context = runtime.context +class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadContext, context: VulkanContext): import context.given - private val queue: Queue = context.computeQueue // TODO multiple queues - multithreading support - private val descriptorPool: DescriptorPool = context.descriptorPool // TODO descriptor pool manager - descriptor allocation and reclamation support - private val commandPool: CommandPool = context.commandPool // TODO multiple command pools - different command pools for different workloads + private val dsManager: DescriptorSetManager = threadContext.descriptorSetManager + private val commandPool: CommandPool = threadContext.commandPool def handle[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding](execution: GExecution[Params, EL, RL], params: Params, layout: EL)( using VkAllocation, ): RL = val (result, shaderCalls) = interpret(execution, params, layout) - val descriptorSets = shaderCalls.map { case ShaderCall(pipeline, layout, _) => - pipeline.pipelineLayout.sets.map(descriptorPool.allocate).zip(layout).map { case (set, bindings) => - set.update(bindings.map(x => VkAllocation.getUnderlying(x.binding))) - set - } - } + val descriptorSets = shaderCalls.map: + case ShaderCall(pipeline, layout, _) => + pipeline.pipelineLayout.sets + .map(dsManager.allocate) + .zip(layout) + .map: + case (set, bindings) => + set.update(bindings.map(x => VkAllocation.getUnderlying(x.binding))) + set val dispatches: Seq[Dispatch] = shaderCalls .zip(descriptorSets) @@ -74,9 +76,10 @@ class ExecutionHandler(runtime: VkCyfraRuntime): val fence = new Fence() timed("Vulkan render command"): - check(vkQueueSubmit(queue.get, submitInfo, fence.get), "Failed to submit command buffer to queue") + check(vkQueueSubmit(commandPool.queue.get, submitInfo, fence.get), "Failed to submit command buffer to queue") fence.block().destroy() commandPool.freeCommandBuffer(commandBuffer) + descriptorSets.flatten.foreach(dsManager.free) result private def interpret[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding]( diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index 59142676..a038ac7b 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -28,27 +28,23 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) given VkAllocation = this extension (buffer: GBinding[?]) - def read(bb: ByteBuffer, offset: Int = 0, size: Int = -1): Unit = - val buf = getUnderlying(buffer) - val s = if size < 0 then buf.size - offset else size - - buf match - case buffer: Buffer.HostBuffer => Buffer.copyBuffer(buffer, bb, offset, 0, s) + def read(bb: ByteBuffer, offset: Int = 0): Unit = + val size = bb.remaining() + getUnderlying(buffer) match + case buffer: Buffer.HostBuffer => buffer.copyTo(bb, offset) case buffer: Buffer.DeviceBuffer => - val stagingBuffer = getStagingBuffer(s) - Buffer.copyBuffer(buffer, stagingBuffer, offset, 0, s, commandPool).block().destroy() - Buffer.copyBuffer(stagingBuffer, bb, 0, 0, s) - - def write(bb: ByteBuffer, offset: Int = 0, size: Int = -1): Unit = - val buf = getUnderlying(buffer) - val s = if size < 0 then bb.remaining() else size - - buf match - case buffer: Buffer.HostBuffer => Buffer.copyBuffer(bb, buffer, offset, 0, s) + val stagingBuffer = getStagingBuffer(size) + Buffer.copyBuffer(buffer, stagingBuffer, offset, 0, size, commandPool) + stagingBuffer.copyTo(bb, 0) + + def write(bb: ByteBuffer, offset: Int = 0): Unit = + val size = bb.remaining() + getUnderlying(buffer) match + case buffer: Buffer.HostBuffer => buffer.copyFrom(bb, offset) case buffer: Buffer.DeviceBuffer => - val stagingBuffer = getStagingBuffer(s) - Buffer.copyBuffer(bb, stagingBuffer, 0, 0, s) - Buffer.copyBuffer(stagingBuffer, buffer, 0, offset, s, commandPool).block().destroy() + val stagingBuffer = getStagingBuffer(size) + stagingBuffer.copyFrom(bb, offset) + Buffer.copyBuffer(stagingBuffer, buffer, 0, offset, size, commandPool) extension (buffers: GBuffer.type) def apply[T <: Value: {Tag, FromExpr}](length: Int): GBuffer[T] = diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala index f28cfd65..ccd6585f 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala @@ -8,19 +8,19 @@ import io.computenode.cyfra.vulkan.compute.ComputePipeline import scala.collection.mutable class VkCyfraRuntime extends CyfraRuntime: - val context = new VulkanContext() + private val context = new VulkanContext() import context.given - private val executionHandler = new ExecutionHandler(this) - private val shaderCache = mutable.Map.empty[String, VkShader[?]] private[cyfra] def getOrLoadProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}](program: GProgram[Params, L]): VkShader[L] = shaderCache.getOrElseUpdate(program.cacheKey, VkShader(program)).asInstanceOf[VkShader[L]] override def withAllocation(f: Allocation => Unit): Unit = - val allocation = new VkAllocation(context.commandPool, executionHandler) - f(allocation) - allocation.close() + context.withThreadContext: threadContext => + val executionHandler = new ExecutionHandler(this, threadContext, context) + val allocation = new VkAllocation(threadContext.commandPool, executionHandler) + f(allocation) + allocation.close() def close(): Unit = shaderCache.values.foreach(_.underlying.destroy()) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala index 4544553e..f0885cb9 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala @@ -23,12 +23,12 @@ object VkShader: val shaderLayout = shaderBindings(summon[LayoutStruct[L]].layoutRef) val sets = shaderLayout.map: set => - val descriptors = set.map { case Binding(binding, op) => - val kind = binding match - case buffer: GBuffer[?] => BindingType.StorageBuffer - case uniform: GUniform[?] => BindingType.Uniform - DescriptorInfo(kind) - } + val descriptors = set.map: + case Binding(binding, op) => + val kind = binding match + case buffer: GBuffer[?] => BindingType.StorageBuffer + case uniform: GUniform[?] => BindingType.Uniform + DescriptorInfo(kind) DescriptorSetInfo(descriptors) val pipeline = ComputePipeline(code, entryPoint, LayoutInfo(sets)) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala index bd806c4a..9c8c99c6 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala @@ -3,35 +3,56 @@ package io.computenode.cyfra.vulkan import io.computenode.cyfra.utility.Logger.logger import io.computenode.cyfra.vulkan.VulkanContext.ValidationLayers import io.computenode.cyfra.vulkan.command.CommandPool -import io.computenode.cyfra.vulkan.core.{DebugCallback, Device, Instance, Queue} -import io.computenode.cyfra.vulkan.memory.{Allocator, DescriptorPool} +import io.computenode.cyfra.vulkan.core.{DebugCallback, Device, Instance, PhysicalDevice, Queue} +import io.computenode.cyfra.vulkan.memory.{Allocator, DescriptorPool, DescriptorPoolManager, DescriptorSetManager} import org.lwjgl.system.Configuration +import java.util.concurrent.{ArrayBlockingQueue, BlockingQueue} +import scala.util.chaining.* +import scala.jdk.CollectionConverters.* + /** @author * MarconZet Created 13.04.2020 */ private[cyfra] object VulkanContext: val ValidationLayer: String = "VK_LAYER_KHRONOS_validation" - val SyncLayer: String = "VK_LAYER_KHRONOS_synchronization2" private val ValidationLayers: Boolean = System.getProperty("io.computenode.cyfra.vulkan.validation", "false").toBoolean if Configuration.STACK_SIZE.get() < 100 then logger.warn(s"Small stack size. Increase with org.lwjgl.system.stackSize") private[cyfra] class VulkanContext: - val instance: Instance = new Instance(ValidationLayers) - val debugCallback: Option[DebugCallback] = if ValidationLayers then Some(new DebugCallback(instance)) else None - given device: Device = new Device(instance) - given allocator: Allocator = new Allocator(instance, device) - val computeQueue: Queue = new Queue(device.computeQueueFamily, 0, device) - val descriptorPool: DescriptorPool = new DescriptorPool() - val commandPool: CommandPool = new CommandPool.Standard(computeQueue) + private val instance: Instance = new Instance(ValidationLayers) + private val debugCallback: Option[DebugCallback] = if ValidationLayers then Some(new DebugCallback(instance)) else None + private val physicalDevice = new PhysicalDevice(instance) + physicalDevice.assertRequirements() + + given device: Device = new Device(instance, physicalDevice) + given allocator: Allocator = new Allocator(instance, physicalDevice, device) + + private val descriptorPoolManager = new DescriptorPoolManager() + private val commandPools = device.getQueues.map(new CommandPool.Transient(_)) logger.debug("Vulkan context created") - logger.debug("Running on device: " + device.physicalDeviceName) + logger.debug("Running on device: " + physicalDevice.name) + + private val blockingQueue: BlockingQueue[CommandPool] = new ArrayBlockingQueue[CommandPool](commandPools.length).tap(_.addAll(commandPools.asJava)) + def withThreadContext[T](f: VulkanThreadContext => T): T = + assert( + VulkanThreadContext.guard.get() == 0, + "VulkanThreadContext is not thread-safe. Each thread can have only one VulkanThreadContext at a time. You cannot stack VulkanThreadContext.", + ) + val commandPool = blockingQueue.take() + val descriptorSetManager = new DescriptorSetManager(descriptorPoolManager) + val threadContext = new VulkanThreadContext(commandPool, descriptorSetManager) + VulkanThreadContext.guard.set(threadContext.hashCode()) + try f(threadContext) + finally + blockingQueue.put(commandPool) + descriptorSetManager.destroy() + VulkanThreadContext.guard.set(0) def destroy(): Unit = - commandPool.destroy() - descriptorPool.destroy() - computeQueue.destroy() + commandPools.foreach(_.destroy()) + descriptorPoolManager.destroy() allocator.destroy() device.destroy() debugCallback.foreach(_.destroy()) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanThreadContext.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanThreadContext.scala new file mode 100644 index 00000000..cf59ed81 --- /dev/null +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanThreadContext.scala @@ -0,0 +1,11 @@ +package io.computenode.cyfra.vulkan + +import io.computenode.cyfra.vulkan.command.CommandPool +import io.computenode.cyfra.vulkan.core.Device +import io.computenode.cyfra.vulkan.memory.{DescriptorPoolManager, DescriptorSetManager} + +case class VulkanThreadContext(commandPool: CommandPool, descriptorSetManager: DescriptorSetManager) + +object VulkanThreadContext: + val guard: ThreadLocal[Int] = new ThreadLocal[Int]: + override def initialValue(): Int = 0 diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala index a1117a02..3db65668 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala @@ -9,7 +9,7 @@ import org.lwjgl.vulkan.VK10.* /** @author * MarconZet Created 13.04.2020 Copied from Wrap */ -private[cyfra] abstract class CommandPool private (flags: Int, queue: Queue)(using device: Device) extends VulkanObjectHandle: +private[cyfra] abstract class CommandPool private (flags: Int, val queue: Queue)(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => val createInfo = VkCommandPoolCreateInfo .calloc(stack) @@ -39,11 +39,11 @@ private[cyfra] abstract class CommandPool private (flags: Int, queue: Queue)(usi check(vkAllocateCommandBuffers(device.get, allocateInfo, pointerBuffer), "Failed to allocate command buffers") 0 until n map (i => pointerBuffer.get(i)) map (new VkCommandBuffer(_, device.get)) - def executeCommand(block: VkCommandBuffer => Unit): Fence = - pushStack: stack => - val commandBuffer = beginSingleTimeCommands() - block(commandBuffer) - endSingleTimeCommands(commandBuffer) + def executeCommand(block: VkCommandBuffer => Unit): Unit = + val commandBuffer = beginSingleTimeCommands() + block(commandBuffer) + endSingleTimeCommands(commandBuffer).block().destroy() + freeCommandBuffer(commandBuffer) private def beginSingleTimeCommands(): VkCommandBuffer = pushStack: stack => @@ -65,7 +65,7 @@ private[cyfra] abstract class CommandPool private (flags: Int, queue: Queue)(usi .calloc(stack) .sType$Default() .pCommandBuffers(pointerBuffer) - val fence = new Fence(0, () => freeCommandBuffer(commandBuffer)) + val fence = Fence() check(vkQueueSubmit(queue.get, submitInfo, fence.get), "Failed to submit single time command buffer") fence @@ -80,7 +80,7 @@ private[cyfra] abstract class CommandPool private (flags: Int, queue: Queue)(usi vkDestroyCommandPool(device.get, commandPool, null) object CommandPool: - private[cyfra] class OneTime(queue: Queue)(using device: Device) + private[cyfra] class Transient(queue: Queue)(using device: Device) extends CommandPool(VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queue)(using device: Device) // TODO check if flags should be used differently private[cyfra] class Standard(queue: Queue)(using device: Device) extends CommandPool(0, queue)(using device: Device) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala index 50c350ca..630fa924 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala @@ -9,7 +9,7 @@ import org.lwjgl.vulkan.VkFenceCreateInfo /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] class Fence(flags: Int = 0, onDestroy: () => Unit = () => ())(using device: Device) extends VulkanObjectHandle: +private[cyfra] class Fence(flags: Int = 0)(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack(stack => val fenceInfo = VkFenceCreateInfo .calloc(stack) @@ -23,7 +23,6 @@ private[cyfra] class Fence(flags: Int = 0, onDestroy: () => Unit = () => ())(usi ) override def close(): Unit = - onDestroy.apply() vkDestroyFence(device.get, handle, null) def isSignaled: Boolean = diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala index e23ea52e..6908fcfa 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala @@ -1,9 +1,9 @@ package io.computenode.cyfra.vulkan.core import io.computenode.cyfra.vulkan.VulkanContext.ValidationLayer -import Device.{MacOsExtension, SyncExtension} +import Device.MacOsExtension import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} -import io.computenode.cyfra.vulkan.util.VulkanObject +import io.computenode.cyfra.vulkan.util.{VulkanObject, VulkanObjectHandle} import org.lwjgl.vulkan.* import org.lwjgl.vulkan.KHRPortabilitySubset.VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME import org.lwjgl.vulkan.KHRSynchronization2.VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME @@ -19,94 +19,20 @@ import scala.jdk.CollectionConverters.given object Device: final val MacOsExtension = VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME - final val SyncExtension = VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME - -private[cyfra] class Device(instance: Instance) extends VulkanObject: - - val physicalDevice: VkPhysicalDevice = pushStack: stack => - val pPhysicalDeviceCount = stack.callocInt(1) - check(vkEnumeratePhysicalDevices(instance.get, pPhysicalDeviceCount, null), "Failed to get number of physical devices") - val deviceCount = pPhysicalDeviceCount.get(0) - if deviceCount == 0 then throw new AssertionError("Failed to find GPUs with Vulkan support") - val pPhysicalDevices = stack.callocPointer(deviceCount) - check(vkEnumeratePhysicalDevices(instance.get, pPhysicalDeviceCount, pPhysicalDevices), "Failed to get physical devices") - new VkPhysicalDevice(pPhysicalDevices.get(), instance.get) - - val physicalDeviceName: String = pushStack: stack => - val pProperties = VkPhysicalDeviceProperties.calloc(stack) - vkGetPhysicalDeviceProperties(physicalDevice, pProperties) - pProperties.deviceNameString() - - val computeQueueFamily: Int = pushStack: stack => - val pQueueFamilyCount = stack.callocInt(1) - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyCount, null) - val queueFamilyCount = pQueueFamilyCount.get(0) - - val pQueueFamilies = VkQueueFamilyProperties.calloc(queueFamilyCount, stack) - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyCount, pQueueFamilies) - - val queues = 0 until queueFamilyCount - queues - .find { i => - val queueFamily = pQueueFamilies.get(i) - val maskedFlags = ~(VK_QUEUE_TRANSFER_BIT | VK_QUEUE_SPARSE_BINDING_BIT) & queueFamily.queueFlags() - ~(VK_QUEUE_GRAPHICS_BIT & maskedFlags) > 0 && (VK_QUEUE_COMPUTE_BIT & maskedFlags) > 0 - } - .orElse(queues.find { i => - val queueFamily = pQueueFamilies.get(i) - val maskedFlags = ~(VK_QUEUE_TRANSFER_BIT | VK_QUEUE_SPARSE_BINDING_BIT) & queueFamily.queueFlags() - (VK_QUEUE_COMPUTE_BIT & maskedFlags) > 0 - }) - .getOrElse(throw new AssertionError("No suitable queue family found for computing")) - - private val device: VkDevice = pushStack: stack => - val pPropertiesCount = stack.callocInt(1) - check( - vkEnumerateDeviceExtensionProperties(physicalDevice, null.asInstanceOf[ByteBuffer], pPropertiesCount, null), - "Failed to get number of properties extension", - ) - val propertiesCount = pPropertiesCount.get(0) - - val pProperties = VkExtensionProperties.calloc(propertiesCount, stack) - check( - vkEnumerateDeviceExtensionProperties(physicalDevice, null.asInstanceOf[ByteBuffer], pPropertiesCount, pProperties), - "Failed to get extension properties", - ) - - val deviceExtensions = pProperties.iterator().asScala.map(_.extensionNameString()) - val deviceExtensionsSet = deviceExtensions.toSet - - val vulkan12Features = VkPhysicalDeviceVulkan12Features - .calloc(stack) - .sType$Default() - - val vulkan13Features = VkPhysicalDeviceVulkan13Features - .calloc(stack) - .sType$Default() - - val physicalDeviceFeatures = VkPhysicalDeviceFeatures2 - .calloc(stack) - .sType$Default() - .pNext(vulkan12Features) - .pNext(vulkan13Features) - - vkGetPhysicalDeviceFeatures2(physicalDevice, physicalDeviceFeatures) - - val additionalExtension = pProperties.stream().anyMatch(x => x.extensionNameString().equals(MacOsExtension)) - - val pQueuePriorities = stack.callocFloat(1).put(1.0f) - pQueuePriorities.flip() +private[cyfra] class Device(instance: Instance, physicalDevice: PhysicalDevice) extends VulkanObject[VkDevice]: + protected val handle: VkDevice = pushStack: stack => + val (queueFamily, queueCount) = physicalDevice.selectComputeQueueFamily val pQueueCreateInfo = VkDeviceQueueCreateInfo.calloc(1, stack) pQueueCreateInfo .get(0) .sType$Default() .pNext(0) .flags(0) - .queueFamilyIndex(computeQueueFamily) - .pQueuePriorities(pQueuePriorities) + .queueFamilyIndex(queueFamily) + .pQueuePriorities(stack.callocFloat(queueCount)) - val extensions = Seq(MacOsExtension, SyncExtension).filter(deviceExtensionsSet) + val extensions = Seq(MacOsExtension).filter(physicalDevice.deviceExtensionsSet) val ppExtensionNames = stack.callocPointer(extensions.length) extensions.foreach(extension => ppExtensionNames.put(stack.ASCII(extension))) ppExtensionNames.flip() @@ -123,17 +49,20 @@ private[cyfra] class Device(instance: Instance) extends VulkanObject: .pQueueCreateInfos(pQueueCreateInfo) .ppEnabledExtensionNames(ppExtensionNames) - if instance.enabledLayers.contains(ValidationLayer) then - val ppValidationLayers = stack.callocPointer(1).put(stack.ASCII(ValidationLayer)) + if instance.enabledLayers.nonEmpty then + val ppValidationLayers = stack.callocPointer(instance.enabledLayers.length) + instance.enabledLayers.foreach: layer => + ppValidationLayers.put(stack.ASCII(layer)) pCreateInfo.ppEnabledLayerNames(ppValidationLayers.flip()) - assert(vulkan13Features.synchronization2() || extensions.contains(SyncExtension)) - val pDevice = stack.callocPointer(1) - check(vkCreateDevice(physicalDevice, pCreateInfo, null, pDevice), "Failed to create device") - new VkDevice(pDevice.get(0), physicalDevice, pCreateInfo) + check(vkCreateDevice(physicalDevice.get, pCreateInfo, null, pDevice), "Failed to create device") + val device = new VkDevice(pDevice.get(0), physicalDevice.get, pCreateInfo) + device - def get: VkDevice = device + def getQueues: Seq[Queue] = + val (queueFamily, queueCount) = physicalDevice.selectComputeQueueFamily + (0 until queueCount).map(new Queue(queueFamily, _, this)) override protected def close(): Unit = - vkDestroyDevice(device, null) + vkDestroyDevice(handle, null) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala index 7452ec0a..43072840 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala @@ -40,9 +40,9 @@ object Instance: lazy val version: Int = VK.getInstanceVersionSupported -private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObject: +private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObject[VkInstance]: - private val instance: VkInstance = pushStack: stack => + protected val handle: VkInstance = pushStack: stack => val appInfo = VkApplicationInfo .calloc(stack) .sType$Default() @@ -55,9 +55,8 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj val ppEnabledExtensionNames = getInstanceExtensions(stack) val ppEnabledLayerNames = - val layers = enabledLayers - val pointer = stack.callocPointer(layers.length) - layers.foreach(x => pointer.put(stack.ASCII(x))) + val pointer = stack.callocPointer(enabledLayers.length) + enabledLayers.foreach(x => pointer.put(stack.ASCII(x))) pointer.flip() val pCreateInfo = VkInstanceCreateInfo @@ -87,18 +86,15 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj lazy val enabledLayers: Seq[String] = List .empty[String] - .pipe { x => + .pipe: x => if Instance.layers.contains(ValidationLayer) && enableValidationLayers then ValidationLayer +: x else if enableValidationLayers then logger.error("Validation layers requested but not available") x else x - } - - def get: VkInstance = instance override protected def close(): Unit = - vkDestroyInstance(instance, null) + vkDestroyInstance(handle, null) private def getInstanceExtensions(stack: MemoryStack) = val n = stack.callocInt(1) @@ -108,18 +104,18 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj val availableExtensions = val buf = mutable.Buffer[String]() - buffer.forEach { ext => + buffer.forEach: ext => buf.addOne(ext.extensionNameString()) - } buf.toSet val extensions = mutable.Buffer.from(Instance.MoltenVkExtensions) if enableValidationLayers then extensions.addAll(Instance.ValidationLayersExtensions) val filteredExtensions = extensions.filter(ext => - availableExtensions.contains(ext).tap { x => // TODO detect when this extension is needed - if !x then logger.warn(s"Requested Vulkan instance extension '$ext' is not available") - }, + availableExtensions + .contains(ext) + .tap: x => // TODO detect when this extension is needed + if !x then logger.warn(s"Requested Vulkan instance extension '$ext' is not available"), ) val ppEnabledExtensionNames = stack.callocPointer(extensions.size) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/PhysicalDevice.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/PhysicalDevice.scala new file mode 100644 index 00000000..d06d62c8 --- /dev/null +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/PhysicalDevice.scala @@ -0,0 +1,86 @@ +package io.computenode.cyfra.vulkan.core + +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObject +import org.lwjgl.vulkan.VK10.* +import org.lwjgl.vulkan.VK11.vkGetPhysicalDeviceFeatures2 +import org.lwjgl.vulkan.* + +import java.nio.ByteBuffer +import scala.jdk.CollectionConverters.given + +class PhysicalDevice(instance: Instance) extends VulkanObject[VkPhysicalDevice] { + protected val handle: VkPhysicalDevice = pushStack: stack => + val pPhysicalDeviceCount = stack.callocInt(1) + check(vkEnumeratePhysicalDevices(instance.get, pPhysicalDeviceCount, null), "Failed to get number of physical devices") + val deviceCount = pPhysicalDeviceCount.get(0) + if deviceCount == 0 then throw new AssertionError("Failed to find GPUs with Vulkan support") + val pPhysicalDevices = stack.callocPointer(deviceCount) + check(vkEnumeratePhysicalDevices(instance.get, pPhysicalDeviceCount, pPhysicalDevices), "Failed to get physical devices") + new VkPhysicalDevice(pPhysicalDevices.get(), instance.get) + + override protected def close(): Unit = () + + private val pdp: VkPhysicalDeviceProperties = + val pProperties = VkPhysicalDeviceProperties.create() + vkGetPhysicalDeviceProperties(handle, pProperties) + pProperties + + private val (pdf, v11f, v12f, v13f) + : (VkPhysicalDeviceFeatures, VkPhysicalDeviceVulkan11Features, VkPhysicalDeviceVulkan12Features, VkPhysicalDeviceVulkan13Features) = + val vulkan11Features = VkPhysicalDeviceVulkan11Features.create().sType$Default() + val vulkan12Features = VkPhysicalDeviceVulkan12Features.create().sType$Default() + val vulkan13Features = VkPhysicalDeviceVulkan13Features.create().sType$Default() + + val physicalDeviceFeatures = VkPhysicalDeviceFeatures2 + .create() + .sType$Default() + .pNext(vulkan11Features) + .pNext(vulkan12Features) + .pNext(vulkan13Features) + + vkGetPhysicalDeviceFeatures2(handle, physicalDeviceFeatures) + val features = VkPhysicalDeviceFeatures.create().set(physicalDeviceFeatures.features()) + (features, vulkan11Features, vulkan12Features, vulkan13Features) + + private val extensionProperties = pushStack: stack => + val pPropertiesCount = stack.callocInt(1) + check( + vkEnumerateDeviceExtensionProperties(handle, null.asInstanceOf[ByteBuffer], pPropertiesCount, null), + "Failed to get number of properties extension", + ) + val propertiesCount = pPropertiesCount.get(0) + + val pProperties = VkExtensionProperties.create(propertiesCount) + check( + vkEnumerateDeviceExtensionProperties(handle, null.asInstanceOf[ByteBuffer], pPropertiesCount, pProperties), + "Failed to get extension properties", + ) + pProperties + + def assertRequirements(): Unit = + assert(v13f.synchronization2(), "Vulkan 1.3 synchronization2 feature is required") + + def name: String = pdp.deviceNameString() + def deviceExtensionsSet: Set[String] = extensionProperties.iterator().asScala.map(_.extensionNameString()).toSet + + def selectComputeQueueFamily: (Int, Int) = pushStack: stack => + val pQueueFamilyCount = stack.callocInt(1) + vkGetPhysicalDeviceQueueFamilyProperties(handle, pQueueFamilyCount, null) + val queueFamilyCount = pQueueFamilyCount.get(0) + + val pQueueFamilies = VkQueueFamilyProperties.calloc(queueFamilyCount, stack) + vkGetPhysicalDeviceQueueFamilyProperties(handle, pQueueFamilyCount, pQueueFamilies) + + val queues = pQueueFamilies.iterator().asScala.map(_.queueFlags()).zipWithIndex.toSeq + val onlyCompute = queues.find: (flags, _) => + ~(VK_QUEUE_GRAPHICS_BIT & flags) > 0 && (VK_QUEUE_COMPUTE_BIT & flags) > 0 + val hasCompute = queues.find: (flags, _) => + (VK_QUEUE_COMPUTE_BIT & flags) > 0 + + val (_, index) = onlyCompute + .orElse(hasCompute) + .getOrElse(throw new AssertionError("No suitable queue family found for computing")) + + (index, pQueueFamilies.get(index).queueCount()) +} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Queue.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Queue.scala index 7d894ba8..5f584492 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Queue.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Queue.scala @@ -10,12 +10,10 @@ import org.lwjgl.vulkan.{VkQueue, VkSubmitInfo} /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] class Queue(val familyIndex: Int, queueIndex: Int, device: Device) extends VulkanObject: - private val queue: VkQueue = pushStack: stack => +private[cyfra] class Queue(val familyIndex: Int, queueIndex: Int, device: Device) extends VulkanObject[VkQueue]: + protected val handle: VkQueue = pushStack: stack => val pQueue = stack.callocPointer(1) vkGetDeviceQueue(device.get, familyIndex, queueIndex, pQueue) new VkQueue(pQueue.get(0), device.get) - def get: VkQueue = queue - protected def close(): Unit = () diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Allocator.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Allocator.scala index 147e1eda..54c0cb83 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Allocator.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Allocator.scala @@ -1,6 +1,6 @@ package io.computenode.cyfra.vulkan.memory -import io.computenode.cyfra.vulkan.core.{Device, Instance} +import io.computenode.cyfra.vulkan.core.{Device, Instance, PhysicalDevice} import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.util.vma.Vma.{vmaCreateAllocator, vmaDestroyAllocator} @@ -9,7 +9,7 @@ import org.lwjgl.util.vma.{VmaAllocatorCreateInfo, VmaVulkanFunctions} /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] class Allocator(instance: Instance, device: Device) extends VulkanObjectHandle: +private[cyfra] class Allocator(instance: Instance, physicalDevice: PhysicalDevice, device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => val functions = VmaVulkanFunctions.calloc(stack) @@ -17,7 +17,7 @@ private[cyfra] class Allocator(instance: Instance, device: Device) extends Vulka val allocatorInfo = VmaAllocatorCreateInfo .calloc(stack) .device(device.get) - .physicalDevice(device.physicalDevice) + .physicalDevice(physicalDevice.get) .instance(instance.get) .pVulkanFunctions(functions) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala index f8926e3d..963aa1cd 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala @@ -45,10 +45,7 @@ object Buffer: private[cyfra] class HostBuffer(size: Int, usage: Int)(using allocator: Allocator) extends Buffer(size, usage, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)(using allocator): - def mapped(f: ByteBuffer => Unit): Unit = mappedImpl(f, flush = true) - def mappedNoFlush(f: ByteBuffer => Unit): Unit = mappedImpl(f, flush = false) - - private def mappedImpl(f: ByteBuffer => Unit, flush: Boolean): Unit = pushStack: stack => + def mapped(flush: Boolean)(f: ByteBuffer => Unit): Unit = pushStack: stack => val pData = stack.callocPointer(1) check(vmaMapMemory(this.allocator.get, this.allocation, pData), "Failed to map buffer to memory") val data = pData.get() @@ -58,15 +55,13 @@ object Buffer: if flush then vmaFlushAllocation(this.allocator.get, this.allocation, 0, size) vmaUnmapMemory(this.allocator.get, this.allocation) - def copyBuffer(src: ByteBuffer, dst: HostBuffer, srcOffset: Int, dstOffset: Int, bytes: Int): Unit = - dst.mapped: destination => - memCopy(memAddress(src) + srcOffset, memAddress(destination) + dstOffset, bytes) + def copyTo(dst: ByteBuffer, srcOffset: Int): Unit = pushStack: stack => + vmaCopyAllocationToMemory(allocator.get, allocation, srcOffset, dst) - def copyBuffer(src: HostBuffer, dst: ByteBuffer, srcOffset: Int, dstOffset: Int, bytes: Int): Unit = - src.mappedNoFlush: source => - memCopy(memAddress(source) + srcOffset, memAddress(dst) + dstOffset, bytes) + def copyFrom(src: ByteBuffer, dstOffset: Int): Unit = pushStack: stack => + vmaCopyMemoryToAllocation(allocator.get, src, allocation, dstOffset) - def copyBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool): Fence = + def copyBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool): Unit = commandPool.executeCommand: commandBuffer => pushStack: stack => val copyRegion = VkBufferCopy diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala index 093fb350..afd2f793 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPool.scala @@ -12,14 +12,14 @@ import org.lwjgl.vulkan.{VkDescriptorPoolCreateInfo, VkDescriptorPoolSize} * MarconZet Created 14.04.2019 */ object DescriptorPool: - val MAX_SETS = 100 + val MAX_SETS = 1000 private[cyfra] class DescriptorPool(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => val descriptorPoolSize = VkDescriptorPoolSize.calloc(2, stack) descriptorPoolSize .get() .`type`(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) - .descriptorCount(2 * MAX_SETS) + .descriptorCount(10 * MAX_SETS) descriptorPoolSize .get() @@ -31,14 +31,15 @@ private[cyfra] class DescriptorPool(using device: Device) extends VulkanObjectHa .calloc(stack) .sType$Default() .maxSets(MAX_SETS) - .flags(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT) .pPoolSizes(descriptorPoolSize) val pDescriptorPool = stack.callocLong(1) check(vkCreateDescriptorPool(device.get, descriptorPoolCreateInfo, null, pDescriptorPool), "Failed to create descriptor pool") pDescriptorPool.get() - def allocate(descriptorSetLayout: DescriptorSetLayout): DescriptorSet = DescriptorSet(descriptorSetLayout, this) + def allocate(layout: DescriptorSetLayout): Option[DescriptorSet] = DescriptorSet(layout, this) + + def reset(): Unit = check(vkResetDescriptorPool(device.get, handle, 0), "Failed to reset descriptor pool") override protected def close(): Unit = vkDestroyDescriptorPool(device.get, handle, null) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPoolManager.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPoolManager.scala new file mode 100644 index 00000000..293bde45 --- /dev/null +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorPoolManager.scala @@ -0,0 +1,19 @@ +package io.computenode.cyfra.vulkan.memory + +import io.computenode.cyfra.vulkan.core.Device + +class DescriptorPoolManager(using Device): + private val freePools: collection.mutable.Queue[DescriptorPool] = collection.mutable.Queue.empty + + def allocate(): DescriptorPool = synchronized: + freePools.removeHeadOption() match + case Some(value) => value + case None => new DescriptorPool() + + def free(pools: DescriptorPool*): Unit = synchronized: + pools.foreach(_.reset()) + freePools.enqueueAll(pools) + + def destroy(): Unit = synchronized: + freePools.foreach(_.destroy()) + freePools.clear() diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala index bd33df63..65296a77 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSet.scala @@ -5,50 +5,57 @@ import io.computenode.cyfra.vulkan.core.Device import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.vulkan.VK10.* -import org.lwjgl.vulkan.{VkDescriptorBufferInfo, VkDescriptorSetAllocateInfo, VkWriteDescriptorSet} +import org.lwjgl.vulkan.{VK10, VK11, VkDescriptorBufferInfo, VkDescriptorSetAllocateInfo, VkWriteDescriptorSet} /** @author * MarconZet Created 15.04.2020 */ -private[cyfra] class DescriptorSet(descriptorSetLayout: DescriptorSetLayout, descriptorPool: DescriptorPool)(using device: Device) +private[cyfra] class DescriptorSet private (protected val handle: Long, val layout: DescriptorSetLayout)(using device: Device) extends VulkanObjectHandle: - protected val handle: Long = pushStack: stack => - val pSetLayout = stack.callocLong(1).put(0, descriptorSetLayout.id) - val descriptorSetAllocateInfo = VkDescriptorSetAllocateInfo - .calloc(stack) - .sType$Default() - .descriptorPool(descriptorPool.get) - .pSetLayouts(pSetLayout) - - val pDescriptorSet = stack.callocLong(1) - check(vkAllocateDescriptorSets(device.get, descriptorSetAllocateInfo, pDescriptorSet), "Failed to allocate descriptor set") - pDescriptorSet.get() - def update(buffers: Seq[Buffer]): Unit = pushStack: stack => - val bindings = descriptorSetLayout.set.descriptors + val bindings = layout.set.descriptors assert(buffers.length == bindings.length, s"Number of buffers (${buffers.length}) does not match number of bindings (${bindings.length})") val writeDescriptorSet = VkWriteDescriptorSet.calloc(buffers.length, stack) - buffers.zip(bindings).zipWithIndex.foreach { case ((buffer, binding), idx) => - val descriptorBufferInfo = VkDescriptorBufferInfo - .calloc(1, stack) - .buffer(buffer.get) - .offset(0) - .range(VK_WHOLE_SIZE) - val descriptorType = binding.kind match - case BindingType.StorageBuffer => VK_DESCRIPTOR_TYPE_STORAGE_BUFFER - case BindingType.Uniform => VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER - writeDescriptorSet - .get() - .sType$Default() - .dstSet(handle) - .dstBinding(idx) - .descriptorCount(1) - .descriptorType(descriptorType) - .pBufferInfo(descriptorBufferInfo) - } + buffers + .zip(bindings) + .zipWithIndex + .foreach: + case ((buffer, binding), idx) => + val descriptorBufferInfo = VkDescriptorBufferInfo + .calloc(1, stack) + .buffer(buffer.get) + .offset(0) + .range(VK_WHOLE_SIZE) + val descriptorType = binding.kind match + case BindingType.StorageBuffer => VK_DESCRIPTOR_TYPE_STORAGE_BUFFER + case BindingType.Uniform => VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER + writeDescriptorSet + .get() + .sType$Default() + .dstSet(handle) + .dstBinding(idx) + .descriptorCount(1) + .descriptorType(descriptorType) + .pBufferInfo(descriptorBufferInfo) writeDescriptorSet.rewind() vkUpdateDescriptorSets(device.get, writeDescriptorSet, null) - override protected def close(): Unit = - vkFreeDescriptorSets(device.get, descriptorPool.get, handle) + override protected def close(): Unit = () + +object DescriptorSet: + def apply(layout: DescriptorSetLayout, descriptorPool: DescriptorPool)(using device: Device): Option[DescriptorSet] = + pushStack: stack => + val pSetLayout = stack.callocLong(1).put(0, layout.id) + val descriptorSetAllocateInfo = VkDescriptorSetAllocateInfo + .calloc(stack) + .sType$Default() + .descriptorPool(descriptorPool.get) + .pSetLayouts(pSetLayout) + + val pDescriptorSet = stack.callocLong(1) + val err = vkAllocateDescriptorSets(device.get, descriptorSetAllocateInfo, pDescriptorSet) + if err == VK11.VK_ERROR_OUT_OF_POOL_MEMORY || err == VK10.VK_ERROR_FRAGMENTED_POOL then None + else + check(err, "Failed to allocate descriptor set") + Some(new DescriptorSet(pDescriptorSet.get(), layout)) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSetManager.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSetManager.scala new file mode 100644 index 00000000..249ecf54 --- /dev/null +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/DescriptorSetManager.scala @@ -0,0 +1,32 @@ +package io.computenode.cyfra.vulkan.memory + +import io.computenode.cyfra.vulkan.compute.ComputePipeline.DescriptorSetLayout + +import scala.annotation.tailrec +import scala.collection.mutable + +class DescriptorSetManager(poolManager: DescriptorPoolManager): + private var currentPool: Option[DescriptorPool] = None + private val exhaustedPools = mutable.Buffer.empty[DescriptorPool] + private val freeSets = mutable.HashMap.empty[Long, mutable.Queue[DescriptorSet]] + + def allocate(layout: DescriptorSetLayout): DescriptorSet = + freeSets.get(layout.id).flatMap(_.removeHeadOption(true)).getOrElse(allocateNew(layout)) + + def free(descriptorSet: DescriptorSet): Unit = + freeSets.getOrElseUpdate(descriptorSet.layout.id, mutable.Queue.empty) += descriptorSet + + def destroy(): Unit = + currentPool.foreach(poolManager.free(_)) + poolManager.free(exhaustedPools.toSeq*) + currentPool = None + exhaustedPools.clear() + + @tailrec + private def allocateNew(layout: DescriptorSetLayout): DescriptorSet = + currentPool.flatMap(_.allocate(layout)) match + case Some(value) => value + case None => + currentPool.foreach(exhaustedPools += _) + currentPool = Some(poolManager.allocate()) + this.allocateNew(layout) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala index b896706b..3ec34726 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala @@ -3,8 +3,13 @@ package io.computenode.cyfra.vulkan.util /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] abstract class VulkanObject: - protected var alive: Boolean = true +private[cyfra] abstract class VulkanObject[T]: + protected val handle: T + private var alive: Boolean = true + + def get: T = + if !alive then throw new IllegalStateException() + else handle def destroy(): Unit = if !alive then throw new IllegalStateException() diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala index acc448c7..1b7b8d67 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObjectHandle.scala @@ -3,9 +3,4 @@ package io.computenode.cyfra.vulkan.util /** @author * MarconZet Created 13.04.2020 */ -private[cyfra] abstract class VulkanObjectHandle extends VulkanObject: - protected val handle: Long - - def get: Long = - if !alive then throw new IllegalStateException() - else handle +private[cyfra] abstract class VulkanObjectHandle extends VulkanObject[Long] From 24c333a7fe436ff7efc7f15434c28d66864144d1 Mon Sep 17 00:00:00 2001 From: spamegg Date: Mon, 18 Aug 2025 18:34:04 +0300 Subject: [PATCH 23/59] outline / sketch compaction and filter, add filter test --- .../cyfra/e2e/fs2interop/Fs2Tests.scala | 21 +++-- .../computenode/cyfra/fs2interop/GPipe.scala | 83 +++++++++---------- 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala index 20c04b9d..daba84cd 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala @@ -2,7 +2,7 @@ package io.computenode.cyfra.e2e.fs2interop import io.computenode.cyfra.core.archive.*, mem.*, GMem.fRGBA import io.computenode.cyfra.dsl.{*, given}, algebra.VectorAlgebra -import io.computenode.cyfra.fs2interop.*, GPipe.*, Bridge.given +import io.computenode.cyfra.fs2interop.*, Bridge.given import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.runtime.VkCyfraRuntime @@ -18,10 +18,10 @@ extension (f: fRGBA) class Fs2Tests extends munit.FunSuite: given cr: CyfraRuntime = VkCyfraRuntime() - test("fs2 through gPipeMap, just ints"): + test("fs2 through GPipe map, just ints"): val inSeq = (0 until 256).toSeq val stream = Stream.emits(inSeq) - val pipe = gPipeMap[Pure, Int32, Int](_ + 1) + val pipe = GPipe.map[Pure, Int32, Int](_ + 1) val result = stream.through(pipe).compile.toList val expected = inSeq.map(_ + 1) result @@ -29,10 +29,10 @@ class Fs2Tests extends munit.FunSuite: .foreach: (res, exp) => assert(res == exp, s"Expected $exp, got $res") - test("fs2 through gPipeMap, floats and vectors"): + test("fs2 through GPipe map, floats and vectors"): val inSeq = (0 to 255).map(_.toFloat).toSeq val stream = Stream.emits(inSeq) - val pipe = gPipeMap[Pure, Float32, Vec4[Float32], Float, fRGBA](f => (f, f + 1f, f + 2f, f + 3f)) + val pipe = GPipe.map[Pure, Float32, Vec4[Float32], Float, fRGBA](f => (f, f + 1f, f + 2f, f + 3f)) val result = stream.through(pipe).compile.toList val expected = inSeq.map(f => (f, f + 1f, f + 2f, f + 3f)) result @@ -40,6 +40,17 @@ class Fs2Tests extends munit.FunSuite: .foreach: (res, exp) => assert(res.close(exp)(0.001f), s"Expected $exp, got $res") + test("fs2 through GPipe filter, just ints"): + val inSeq = (0 until 256).toSeq + val stream = Stream.emits(inSeq) + val pipe = GPipe.filter[Pure, Int32, Int](_.mod(2) === 0) + val result = stream.through(pipe).compile.toList + val expected = inSeq.filter(_ % 2 == 0) + result + .zip(expected) + .foreach: (res, exp) => + assert(res == exp, s"Expected $exp, got $res") + class Fs2LegacyTests extends munit.FunSuite: given gc: GContext = GContext() import GPipeLegacy.* diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 439973d6..92452737 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -1,6 +1,5 @@ package io.computenode.cyfra.fs2interop -import io.computenode.cyfra.core.archive.*, mem.*, GMem.fRGBA import io.computenode.cyfra.core.{Allocation, layout}, layout.Layout import io.computenode.cyfra.core.{CyfraRuntime, GBufferRegion, GExecution, GProgram} import io.computenode.cyfra.dsl.{*, given}, gio.GIO, binding.{GBuffer, GUniform, GBinding} @@ -15,13 +14,12 @@ import izumi.reflect.Tag import scala.reflect.ClassTag object GPipe: - def gPipeMap[F[_], C1 <: Value: FromExpr: Tag, C2 <: Value: FromExpr: Tag, S1: ClassTag, S2: ClassTag]( + def map[F[_], C1 <: Value: FromExpr: Tag, C2 <: Value: FromExpr: Tag, S1: ClassTag, S2: ClassTag]( f: C1 => C2, )(using cr: CyfraRuntime, bridge1: Bridge[C1, S1], bridge2: Bridge[C2, S2]): Pipe[F, S1, S2] = (stream: Stream[F, S1]) => case class Params(inSize: Int) case class PLayout(in: GBuffer[C1], out: GBuffer[C2]) extends Layout - case class PResult(out: GBuffer[C2]) extends Layout val params = Params(inSize = 256) val inTypeSize = typeStride(Tag.apply[C1]) @@ -54,24 +52,12 @@ object GPipe: region.runUnsafe(init = PLayout(in = GBuffer[C1](inBuf), out = GBuffer[C2](outBuf)), onDone = layout => layout.out.read(outBuf)) Stream.emits(bridge2.fromByteBuffer(outBuf, new Array[S2](params.inSize))) - // Syntax sugar for convenient single type version - def gPipeMap[F[_], C <: Value: FromExpr: Tag, S: ClassTag](f: C => C)(using CyfraRuntime, Bridge[C, S]): Pipe[F, S, S] = - gPipeMap[F, C, C, S, S](f) - - // https://developer.nvidia.com/gpugems/gpugems3/part-vi-gpu-computing/chapter-39-parallel-prefix-sum-scan-cuda - // Prefix Sum and Stream Compaction - // 11 - // 012345678901 index - // [abcdefghijkl] starting collection - // [tfftfftttftf] convert to booleans - // [100100111010] integer equivalent - // [111222345566] prefixsum, last number tells us the size of filtered collection - // [x..x..xxx.x.] take the ones that are 1 bigger than previous. - // [adhijl] compact the collection - // 012345 (prefixsum result - 1) are the new indices in compacted collection - def gPipeFilter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: Bridge[C, S]): Pipe[F, S, S] = - (stream: Stream[F, S]) => + // Overload for convenient single type version + def map[F[_], C <: Value: FromExpr: Tag, S: ClassTag](f: C => C)(using CyfraRuntime, Bridge[C, S]): Pipe[F, S, S] = + map[F, C, C, S, S](f) + def filter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: Bridge[C, S]): Pipe[F, S, S] = + (stream: Stream[F, S]) => // Predicate mapping case class PredParams(inSize: Int) case class PredLayout(in: GBuffer[C], out: GBuffer[Int32]) extends Layout @@ -85,9 +71,9 @@ object GPipe: val result = when(pred(element))(1: Int32).otherwise(0) GIO.write[Int32](layout.out, invocId, result) + val predParams = PredParams(256) val predExec = GExecution[PredParams, PredLayout]() .addProgram(predicateProgram)(params => params, layout => layout) - val predParams = PredParams(256) // Prefix sum (inclusive), upsweep/downsweep case class ScanParams(inSize: Int, intervalSize: Int) @@ -114,10 +100,10 @@ object GPipe: ): layout => val ScanArgs(size) = layout.intervalSize.read val invocId = GIO.invocationId - val root = invocId * size - 1 // if invocId = 0, this is -1 (out of bounds) - val mid = root + (size / 2) + val end = invocId * size - 1 // if invocId = 0, this is -1 (out of bounds) + val mid = end + (size / 2) val oldValue = GIO.read[Int32](layout.ints, mid) - val addValue = when(root > 0)(GIO.read[Int32](layout.ints, root)).otherwise(0) + val addValue = when(end > 0)(GIO.read[Int32](layout.ints, end)).otherwise(0) val newValue = oldValue + addValue GIO.write[Int32](layout.ints, mid, newValue) @@ -141,31 +127,42 @@ object GPipe: val downsweepExec = downsweepPhases(upsweepInitialExec, 256, 128) val scanParams = ScanParams(256, 2) - // Stream compaction - case class CompactLayout(in: GBuffer[C], intIn: GBuffer[Int32], out: GBuffer[C]) extends Layout - case class FilterResult(cOut: GBuffer[C]) extends Layout // TODO implement compaction + case class CompactParams() + case class CompactLayout(in: GBuffer[C], intIn: GBuffer[Int32], out: GBuffer[C]) extends Layout + val compactedStreamSize: Int = ??? // TODO how to get this out of prefix sum results + + val compactProgram = GProgram[CompactParams, CompactLayout](layout = params => ???, dispatch = (layout, params) => ???): compactLayout => + ??? + val compactExec = GExecution[CompactParams, CompactLayout]() // TODO: connect all the layouts/executions into one - case class PredScanCompactLayout() extends Layout - case class Result(out: GBuffer[C]) extends Layout + case class PredScanCompactParams(inSize: Int) + case class PredScanCompactLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C]) extends Layout + + val predScanCompactExec = GExecution[PredScanCompactParams, PredScanCompactLayout]() // TODO + val predScanCompactParams = PredScanCompactParams(256) // TODO - val region = GBufferRegion // TODO fix this! - .allocate[PredLayout] + val region = GBufferRegion + .allocate[PredScanCompactLayout] .map: layout => - predExec.execute(predParams, layout) + predScanCompactExec.execute(predScanCompactParams, layout) val typeSize = typeStride(Tag.apply[C]) + val intSize = typeStride(Tag.apply[Int32]) // these are allocated once, reused for many chunks - val inBuf = BufferUtils.createByteBuffer(predParams.inSize * typeSize) - val outBuf = BufferUtils.createByteBuffer(predParams.inSize * typeSize) // TODO wrong size - - // stream - // .chunkMin(predParams.inSize) - // .flatMap: chunk => - // bridge.toByteBuffer(inBuf, chunk) - // region.runUnsafe(init = PredLayout(in = GBuffer[C](inBuf), out = GBuffer[Int32](outBuf)), onDone = layout => layout.out.read(outBuf)) - // val arr = bridge.fromByteBuffer(outBuf, new Array[S](params.inSize)) - // Stream.emits(arr) - ??? + val predBuf = BufferUtils.createByteBuffer(predParams.inSize * typeSize) + val scanBuf = BufferUtils.createByteBuffer(predParams.inSize * intSize) + val compactBuf = BufferUtils.createByteBuffer(compactedStreamSize * typeSize) + + stream + .chunkMin(predScanCompactParams.inSize) + .flatMap: chunk => + bridge.toByteBuffer(predBuf, chunk) + region.runUnsafe( + init = PredScanCompactLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf)), + onDone = layout => layout.out.read(compactBuf), + ) + val arr = bridge.fromByteBuffer(compactBuf, new Array[S](compactedStreamSize)) + Stream.emits(arr) From 278bbb0c00f548952c2b2819da1548dd66f62a9c Mon Sep 17 00:00:00 2001 From: spamegg Date: Wed, 20 Aug 2025 11:17:05 +0300 Subject: [PATCH 24/59] some comments --- .../main/scala/io/computenode/cyfra/fs2interop/GPipe.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 92452737..8bfbcfa9 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -140,7 +140,11 @@ object GPipe: case class PredScanCompactParams(inSize: Int) case class PredScanCompactLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C]) extends Layout - val predScanCompactExec = GExecution[PredScanCompactParams, PredScanCompactLayout]() // TODO + // How to "connect" many GExecutions? with flatMap? + val predScanCompactExec = GExecution[PredScanCompactParams, PredScanCompactLayout]() + // predExec + // .flatMap(predLayout => ???) // add downsweepExec + // .flatMap(layout => ???) // add compactExec val predScanCompactParams = PredScanCompactParams(256) // TODO val region = GBufferRegion From c72e45cd56c2a6c56021ea39223538ed5bad91cf Mon Sep 17 00:00:00 2001 From: Szymon Date: Thu, 21 Aug 2025 00:52:56 +0200 Subject: [PATCH 25/59] GIO and Layouts WIP --- .../io/computenode/cyfra/spirv/Context.scala | 6 +- .../cyfra/spirv/compilers/DSLCompiler.scala | 12 +- .../spirv/compilers/ExpressionCompiler.scala | 19 +-- .../compilers/SpirvProgramCompiler.scala | 111 +++++++------ .../computenode/cyfra/core/GExecution.scala | 1 - .../cyfra/core/archive/GContext.scala | 1 - .../io/computenode/cyfra/dsl/Expression.scala | 3 +- .../cyfra/dsl/collections/GArray.scala | 14 -- .../cyfra/dsl/collections/GArray2D.scala | 12 -- .../cyfra/samples/TestingStuff.scala | 154 ------------------ .../cyfra/runtime/ExecutionHandler.scala | 2 +- 11 files changed, 77 insertions(+), 258 deletions(-) delete mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala delete mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala index 974f045f..20ffd53a 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala @@ -16,11 +16,11 @@ private[cyfra] case class Context( voidTypeRef: Int = -1, voidFuncTypeRef: Int = -1, workerIndexRef: Int = -1, - uniformVarRef: Int = -1, + uniformVarRefs: Map[Int, Int] = Map.empty, + bindingToStructType: Map[Int, Int] = Map.empty, constRefs: Map[(Tag[?], Any), Int] = Map(), exprRefs: Map[Int, Int] = Map(), - inBufferBlocks: List[ArrayBufferBlock] = List(), - outBufferBlocks: List[ArrayBufferBlock] = List(), + bufferBlocks: List[ArrayBufferBlock] = List(), nextResultId: Int = HEADER_REFS_TOP, nextBinding: Int = 0, exprNames: Map[Int, String] = Map(), diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala index 07ae9aab..fc2b30bd 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala @@ -47,23 +47,23 @@ private[cyfra] object DSLCompiler: allScopesCache(root.treeid) = result result - def compile(tree: Value, inTypes: List[Tag[?]], outTypes: List[Tag[?]], uniformSchema: GStructSchema[?]): ByteBuffer = + def compile(tree: Value, buffers: List[Tag[?]], uniformSchemaIns: List[GStructSchema[?]]): ByteBuffer = val treeExpr = tree.tree val allExprs = getAllExprsFlattened(treeExpr, visitDetached = true) val typesInCode = allExprs.map(_.tag).distinct - val allTypes = (typesInCode ::: inTypes ::: outTypes).distinct + val allTypes = (typesInCode ::: buffers).distinct def scalarTypes = allTypes.filter(_.tag <:< summon[Tag[Scalar]].tag) val (typeDefs, typedContext) = defineScalarTypes(scalarTypes, Context.initialContext) val structsInCode = (allExprs.collect { case cs: ComposeStruct[?] => cs.resultSchema case gf: GetField[?, ?] => gf.resultSchema - } :+ uniformSchema).distinct + } ::: uniformSchemaIns).distinct val (structDefs, structCtx) = defineStructTypes(structsInCode, typedContext) val structNames = getStructNames(structsInCode, structCtx) - val (decorations, uniformDefs, uniformContext) = initAndDecorateUniforms(inTypes, outTypes, structCtx) - val (uniformStructDecorations, uniformStructInsns, uniformStructContext) = createAndInitUniformBlock(uniformSchema, uniformContext) - val blockNames = getBlockNames(uniformContext, uniformSchema) + val (decorations, uniformDefs, uniformContext) = initAndDecorateBuffers(buffers, structCtx) + val (uniformStructDecorations, uniformStructInsns, uniformStructContext) = createAndInitUniformBlocks(uniformSchemaIns, uniformContext) + val blockNames = getBlockNames(uniformContext, uniformSchemaIns) val (inputDefs, inputContext) = createInvocationId(uniformStructContext) val (constDefs, constCtx) = defineConstants(allExprs, inputContext) val (varDefs, varCtx) = defineVarNames(constCtx) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala index 1a8cd62b..5d99da3a 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala @@ -22,10 +22,6 @@ private[cyfra] object ExpressionCompiler: val WorkerIndexTag = "worker_index" - val WorkerIndex: Int32 = Int32(Dynamic(WorkerIndexTag)) - val UniformStructRefTag = "uniform_struct" - def UniformStructRef[G <: Value: Tag] = Dynamic(UniformStructRefTag) - private def binaryOpOpcode(expr: BinaryOpExpression[?]) = expr match case _: Sum[?] => (Op.OpIAdd, Op.OpFAdd) case _: Diff[?] => (Op.OpISub, Op.OpFSub) @@ -110,11 +106,11 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (c.treeid -> constRef)) (List(), updatedContext) - case d @ Dynamic(WorkerIndexTag) => - (Nil, ctx.copy(exprRefs = ctx.exprRefs + (d.treeid -> ctx.workerIndexRef))) + case w @ WorkerIndex => + (Nil, ctx.copy(exprRefs = ctx.exprRefs + (w.treeid -> ctx.workerIndexRef))) - case d @ Dynamic(UniformStructRefTag) => - (Nil, ctx.copy(exprRefs = ctx.exprRefs + (d.treeid -> ctx.uniformVarRef))) + case d @ Binding(id) => + (Nil, ctx.copy(exprRefs = ctx.exprRefs + (d.treeid -> ctx.uniformVarRefs(id)))) case c: ConvertExpression[?, ?] => compileConvertExpression(c, ctx) @@ -293,7 +289,7 @@ private[cyfra] object ExpressionCompiler: case fc: FunctionCall[?] => compileFunctionCall(fc, ctx) - case ga @ GArrayElem(index, i) => + case ReadBuffer(index, i) => val instructions = List( Instruction( Op.OpAccessChain, @@ -330,14 +326,15 @@ private[cyfra] object ExpressionCompiler: ) val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (cs.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (insns, updatedContext) - case gf @ GetField(dynamic @ Dynamic(UniformStructRefTag), fieldIndex) => + + case gf @ GetField(binding @ Binding(bindingId), fieldIndex) => val insns: List[Instruction] = List( Instruction( Op.OpAccessChain, List( ResultRef(ctx.uniformPointerMap(ctx.valueTypeMap(gf.tag.tag))), ResultRef(ctx.nextResultId), - ResultRef(ctx.uniformVarRef), + ResultRef(ctx.uniformVarRefs(bindingId)), ResultRef(ctx.constRefs((Int32Tag, gf.fieldIndex))), ), ), diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index 8d16743c..1aea6fdb 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -101,13 +101,7 @@ private[cyfra] object SpirvProgramCompiler: ) val ctxWithVoid = context.copy(voidTypeRef = TYPE_VOID_REF, voidFuncTypeRef = VOID_FUNC_TYPE_REF) (voidDef, ctxWithVoid) - - def initAndDecorateUniforms(ins: List[Tag[?]], outs: List[Tag[?]], context: Context): (List[Words], List[Words], Context) = - val (inDecor, inDef, inCtx) = createAndInitBlocks(ins, in = true, context) - val (outDecor, outDef, outCtx) = createAndInitBlocks(outs, in = false, inCtx) - val (voidsDef, voidCtx) = defineVoids(outCtx) - (inDecor ::: outDecor, voidsDef ::: inDef ::: outDef, voidCtx) - + def createInvocationId(context: Context): (List[Words], Context) = val definitionInstructions = List( Instruction(Op.OpConstant, List(ResultRef(context.valueTypeMap(UInt32Tag.tag)), ResultRef(context.nextResultId + 0), IntWord(localSizeX))), @@ -125,8 +119,14 @@ private[cyfra] object SpirvProgramCompiler: ), ) (definitionInstructions, context.copy(nextResultId = context.nextResultId + 3)) + def initAndDecorateBuffers(buffers: List[Tag[?]], context: Context): (List[Words], List[Words], Context) = + val (blockDecor, blockDef, inCtx) = createAndInitBlocks(buffers, context) + val (voidsDef, voidCtx) = defineVoids(inCtx) + (blockDecor, voidsDef ::: blockDef, voidCtx) + - def createAndInitBlocks(blocks: List[Tag[?]], in: Boolean, context: Context): (List[Words], List[Words], Context) = + + def createAndInitBlocks(blocks: List[Tag[?]], context: Context): (List[Words], List[Words], Context) = val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { case ((decAcc, insnAcc, ctx), tpe) => val block = ArrayBufferBlock(ctx.nextResultId, ctx.nextResultId + 1, ctx.nextResultId + 2, ctx.nextResultId + 3, ctx.nextBinding) @@ -146,7 +146,7 @@ private[cyfra] object SpirvProgramCompiler: ) val contextWithBlock = - if in then ctx.copy(inBufferBlocks = block :: ctx.inBufferBlocks) else ctx.copy(outBufferBlocks = block :: ctx.outBufferBlocks) + ctx.copy(bufferBlocks = block :: ctx.bufferBlocks) ( decAcc ::: decorationInstructions, insnAcc ::: definitionInstructions, @@ -155,58 +155,61 @@ private[cyfra] object SpirvProgramCompiler: } (decoration, definition, newContext) - def getBlockNames(context: Context, uniformSchema: GStructSchema[?]): List[Words] = + def getBlockNames(context: Context, uniformSchemas: List[GStructSchema[?]]): List[Words] = def namesForBlock(block: ArrayBufferBlock, tpe: String): List[Words] = Instruction(Op.OpName, List(ResultRef(block.structTypeRef), Text(s"Buffer$tpe"))) :: Instruction(Op.OpName, List(ResultRef(block.blockVarRef), Text(s"data$tpe"))) :: Nil // todo name uniform context.inBufferBlocks.flatMap(namesForBlock(_, "In")) ::: context.outBufferBlocks.flatMap(namesForBlock(_, "Out")) - def createAndInitUniformBlock(schema: GStructSchema[?], ctx: Context): (List[Words], List[Words], Context) = - def totalStride(gs: GStructSchema[?]): Int = gs.fields - .map: - case (_, fromExpr, t) if t <:< gs.gStructTag => - val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] - totalStride(constructor.schema) - case (_, _, t) => - typeStride(t) - .sum - val uniformStructTypeRef = ctx.valueTypeMap(schema.structTag.tag) - - val (offsetDecorations, _) = schema.fields.zipWithIndex.foldLeft[(List[Words], Int)](List.empty[Word], 0): - case ((acc, offset), ((name, fromExpr, tag), idx)) => - val stride = - if tag <:< schema.gStructTag then - val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] - totalStride(constructor.schema) - else typeStride(tag) - val offsetDecoration = Instruction(Op.OpMemberDecorate, List(ResultRef(uniformStructTypeRef), IntWord(idx), Decoration.Offset, IntWord(offset))) - (acc :+ offsetDecoration, offset + stride) - - val uniformBlockDecoration = Instruction(Op.OpDecorate, List(ResultRef(uniformStructTypeRef), Decoration.Block)) - - val uniformPointerUniformRef = ctx.nextResultId - val uniformPointerUniform = - Instruction(Op.OpTypePointer, List(ResultRef(uniformPointerUniformRef), StorageClass.Uniform, ResultRef(uniformStructTypeRef))) - - val uniformVarRef = ctx.nextResultId + 1 - val uniformVar = Instruction(Op.OpVariable, List(ResultRef(uniformPointerUniformRef), ResultRef(uniformVarRef), StorageClass.Uniform)) - - val uniformDecorateDescriptorSet = Instruction(Op.OpDecorate, List(ResultRef(uniformVarRef), Decoration.DescriptorSet, IntWord(0))) - - assert(ctx.nextBinding == 2, "Currently the only legal layout is (in, out, uniform)") - val uniformDecorateBinding = Instruction(Op.OpDecorate, List(ResultRef(uniformVarRef), Decoration.Binding, IntWord(ctx.nextBinding))) + def totalStride(gs: GStructSchema[?]): Int = gs.fields + .map: + case (_, fromExpr, t) if t <:< gs.gStructTag => + val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] + totalStride(constructor.schema) + case (_, _, t) => + typeStride(t) + .sum + + def createAndInitUniformBlocks(schemas: List[GStructSchema[?]], ctx: Context): (List[Words], List[Words], Context) = + schemas.foldLeft((List.empty[Words], List.empty[Words], ctx)) { case ((decorationsAcc, definitionsAcc, currentCtx), schema) => + val uniformStructTypeRef = currentCtx.valueTypeMap(schema.structTag.tag) + val currentBinding = currentCtx.nextBinding + + val (offsetDecorations, _) = schema.fields.zipWithIndex.foldLeft[(List[Words], Int)](List.empty[Words], 0): + case ((acc, offset), ((name, fromExpr, tag), idx)) => + val stride = + if tag <:< schema.gStructTag then + val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] + totalStride(constructor.schema) + else typeStride(tag) + val offsetDecoration = Instruction(Op.OpMemberDecorate, List(ResultRef(uniformStructTypeRef), IntWord(idx), Decoration.Offset, IntWord(offset))) + (acc :+ offsetDecoration, offset + stride) + + val uniformBlockDecoration = Instruction(Op.OpDecorate, List(ResultRef(uniformStructTypeRef), Decoration.Block)) + + val uniformPointerUniformRef = currentCtx.nextResultId + val uniformPointerUniform = + Instruction(Op.OpTypePointer, List(ResultRef(uniformPointerUniformRef), StorageClass.Uniform, ResultRef(uniformStructTypeRef))) + + val uniformVarRef = currentCtx.nextResultId + 1 + val uniformVar = Instruction(Op.OpVariable, List(ResultRef(uniformPointerUniformRef), ResultRef(uniformVarRef), StorageClass.Uniform)) + + val uniformDecorateDescriptorSet = Instruction(Op.OpDecorate, List(ResultRef(uniformVarRef), Decoration.DescriptorSet, IntWord(0))) + val uniformDecorateBinding = Instruction(Op.OpDecorate, List(ResultRef(uniformVarRef), Decoration.Binding, IntWord(currentBinding))) + + val newDecorations = decorationsAcc ::: offsetDecorations ::: List(uniformDecorateDescriptorSet, uniformDecorateBinding, uniformBlockDecoration) + val newDefinitions = definitionsAcc ::: List(uniformPointerUniform, uniformVar) + val newCtx = currentCtx.copy( + nextResultId = currentCtx.nextResultId + 2, + nextBinding = currentCtx.nextBinding + 1, + uniformVarRefs = currentCtx.uniformVarRefs + (currentBinding -> uniformVarRef), + uniformPointerMap = currentCtx.uniformPointerMap + (uniformStructTypeRef -> uniformPointerUniformRef), + bindingToStructType = currentCtx.bindingToStructType + (currentBinding -> uniformStructTypeRef) + ) - ( - offsetDecorations ::: List(uniformDecorateDescriptorSet, uniformDecorateBinding, uniformBlockDecoration), - List(uniformPointerUniform, uniformVar), - ctx.copy( - nextResultId = ctx.nextResultId + 2, - nextBinding = ctx.nextBinding + 1, - uniformVarRef = uniformVarRef, - uniformPointerMap = ctx.uniformPointerMap + (uniformStructTypeRef -> uniformPointerUniformRef), - ), - ) + (newDecorations, newDefinitions, newCtx) + } val predefinedConsts = List((Int32Tag, 0), (UInt32Tag, 0), (Int32Tag, 1)) def defineConstants(exprs: List[E[?]], ctx: Context): (List[Words], Context) = diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala index 22418ead..7ea8ccaf 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala @@ -6,7 +6,6 @@ import io.computenode.cyfra.core.layout.* import io.computenode.cyfra.dsl.binding.GBuffer import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} -import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.UniformStructRef import izumi.reflect.Tag import GExecution.* diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala index 9f209ea4..59a04927 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala @@ -9,7 +9,6 @@ import io.computenode.cyfra.dsl.collections.GArray import io.computenode.cyfra.dsl.struct.* import io.computenode.cyfra.spirv.SpirvTypes.typeStride import io.computenode.cyfra.spirv.compilers.DSLCompiler -import io.computenode.cyfra.spirv.compilers.ExpressionCompiler.{UniformStructRef, WorkerIndex} import io.computenode.cyfra.spirvtools.SpirvToolsRunner import izumi.reflect.Tag diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala index 18f81033..ef723217 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala @@ -111,4 +111,5 @@ object Expression: case class Pass[T <: Value: Tag](value: T) extends E[T] - case class Dynamic[T <: Value: Tag](source: String) extends E[T] + case object WorkerIndex extends E[Int32] + case class Binding[T <: Value: Tag](binding: Int) extends E[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala deleted file mode 100644 index 6e9daf13..00000000 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala +++ /dev/null @@ -1,14 +0,0 @@ -package io.computenode.cyfra.dsl.collections - -import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.collections.GArray.GArrayElem -import io.computenode.cyfra.dsl.macros.Source -import io.computenode.cyfra.dsl.{Expression, Value} -import izumi.reflect.Tag - -case class GArray[T <: Value: {Tag, FromExpr}](index: Int): - def at(i: Int32)(using Source): T = - summon[FromExpr[T]].fromExpr(GArrayElem(index, i.tree)) - -object GArray: - case class GArrayElem[T <: Value: Tag](index: Int, i: Expression[Int32]) extends Expression[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala deleted file mode 100644 index 70d6df19..00000000 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala +++ /dev/null @@ -1,12 +0,0 @@ -package io.computenode.cyfra.dsl.collections - -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Value.Int32 -import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} -import io.computenode.cyfra.dsl.macros.Source -import izumi.reflect.Tag -import io.computenode.cyfra.dsl.Value.FromExpr - -class GArray2D[T <: Value: {Tag, FromExpr}](width: Int, val arr: GArray[T]): - def at(x: Int32, y: Int32)(using Source): T = - arr.at(y * width + x) diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index 8b9a5014..cd2fc227 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -122,157 +122,3 @@ object TestingStuff: .zipWithIndex .foreach: case ((e, a), i) => assert(e == a, s"Mismatch at index $i: expected $e, got $a") - -// Test case: Use one program 10 times, copying values from five input buffers to five output buffers and adding values from two uniforms - case class AddProgramParams(bufferSize: Int, addA: Int, addB: Int) - case class AddProgramUniform(a: Int32) extends GStruct[AddProgramUniform] - case class AddProgramLayout( - in1: GBuffer[Int32], - in2: GBuffer[Int32], - in3: GBuffer[Int32], - in4: GBuffer[Int32], - in5: GBuffer[Int32], - out1: GBuffer[Int32], - out2: GBuffer[Int32], - out3: GBuffer[Int32], - out4: GBuffer[Int32], - out5: GBuffer[Int32], - u1: GUniform[AddProgramUniform] = GUniform.fromParams, - u2: GUniform[AddProgramUniform] = GUniform.fromParams, - ) extends Layout - - case class AddProgramExecLayout( - in1: GBuffer[Int32], - in2: GBuffer[Int32], - in3: GBuffer[Int32], - in4: GBuffer[Int32], - in5: GBuffer[Int32], - out1: GBuffer[Int32], - out2: GBuffer[Int32], - out3: GBuffer[Int32], - out4: GBuffer[Int32], - out5: GBuffer[Int32], - ) extends Layout - - val addProgram: GProgram[AddProgramParams, AddProgramLayout] = GProgram[AddProgramParams, AddProgramLayout]( - layout = params => - AddProgramLayout( - in1 = GBuffer[Int32](params.bufferSize), - in2 = GBuffer[Int32](params.bufferSize), - in3 = GBuffer[Int32](params.bufferSize), - in4 = GBuffer[Int32](params.bufferSize), - in5 = GBuffer[Int32](params.bufferSize), - out1 = GBuffer[Int32](params.bufferSize), - out2 = GBuffer[Int32](params.bufferSize), - out3 = GBuffer[Int32](params.bufferSize), - out4 = GBuffer[Int32](params.bufferSize), - out5 = GBuffer[Int32](params.bufferSize), - u1 = GUniform(AddProgramUniform(params.addA)), - u2 = GUniform(AddProgramUniform(params.addB)), - ), - dispatch = (layout, args) => GProgram.StaticDispatch((args.bufferSize / 128, 1, 1)), - )(_ => ???) - def swap(l: AddProgramLayout): AddProgramLayout = - val AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5, u1, u2) = l - AddProgramLayout(out1, out2, out3, out4, out5, in1, in2, in3, in4, in5, u1, u2) - - def fromExecLayout(l: AddProgramExecLayout): AddProgramLayout = - val AddProgramExecLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5) = l - AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5) - - val execution = (0 until 11).foldLeft( - GExecution[AddProgramParams, AddProgramExecLayout]().asInstanceOf[GExecution[AddProgramParams, AddProgramExecLayout, AddProgramExecLayout]], - )((x, i) => - if i % 2 == 0 then x.addProgram(addProgram)(mapParams = identity[AddProgramParams], mapLayout = fromExecLayout) - else x.addProgram(addProgram)(mapParams = identity, mapLayout = x => swap(fromExecLayout(x))), - ) - - @main - def testAddProgram10Times = - given runtime: VkCyfraRuntime = VkCyfraRuntime() - val bufferSize = 1280 - val params = AddProgramParams(bufferSize, addA = 0, addB = 1) - val region = GBufferRegion - .allocate[AddProgramExecLayout] - .map: region => - execution.execute(params, region) - - val inBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) - val wbbList = inBuffers.map(MemoryUtil.memByteBuffer) - val outBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) - val rbbList = outBuffers.map(MemoryUtil.memByteBuffer) - - val inData = (0 until bufferSize).toArray - inBuffers.foreach(_.put(inData).flip()) - region.runUnsafe( - init = AddProgramExecLayout( - in1 = GBuffer[Int32](wbbList(0)), - in2 = GBuffer[Int32](wbbList(1)), - in3 = GBuffer[Int32](wbbList(2)), - in4 = GBuffer[Int32](wbbList(3)), - in5 = GBuffer[Int32](wbbList(4)), - out1 = GBuffer[Int32](bufferSize), - out2 = GBuffer[Int32](bufferSize), - out3 = GBuffer[Int32](bufferSize), - out4 = GBuffer[Int32](bufferSize), - out5 = GBuffer[Int32](bufferSize), - ), - onDone = layout => { - layout.out1.read(rbbList(0)) - layout.out2.read(rbbList(1)) - layout.out3.read(rbbList(2)) - layout.out4.read(rbbList(3)) - layout.out5.read(rbbList(4)) - }, - ) - runtime.close() - val expected = inData.map(_ + 11 * (params.addA + params.addB)) - outBuffers.foreach { buf => - (0 until bufferSize).foreach { i => - assert(buf.get(i) == expected(i), s"Mismatch at index $i: expected ${expected(i)}, got ${buf.get(i)}") - } - } - - @main - def enduranceTest = - given runtime: VkCyfraRuntime = VkCyfraRuntime() - val bufferSize = 1280 - val params = AddProgramParams(bufferSize, addA = 0, addB = 1) - val region = GBufferRegion - .allocate[AddProgramExecLayout] - .map: region => - execution.execute(params, region) - val aInt = new AtomicInteger(0) - (1 to 10000).par.foreach: i => - val inBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) - val wbbList = inBuffers.map(MemoryUtil.memByteBuffer) - val rbbList = List.fill(5)(BufferUtils.createByteBuffer(bufferSize * 4)) - - val inData = (0 until bufferSize).toArray - inBuffers.foreach(_.put(inData).flip()) - region.runUnsafe( - init = AddProgramExecLayout( - in1 = GBuffer[Int32](wbbList(0)), - in2 = GBuffer[Int32](wbbList(1)), - in3 = GBuffer[Int32](wbbList(2)), - in4 = GBuffer[Int32](wbbList(3)), - in5 = GBuffer[Int32](wbbList(4)), - out1 = GBuffer[Int32](bufferSize), - out2 = GBuffer[Int32](bufferSize), - out3 = GBuffer[Int32](bufferSize), - out4 = GBuffer[Int32](bufferSize), - out5 = GBuffer[Int32](bufferSize), - ), - onDone = layout => { - layout.out1.read(rbbList(0)) - layout.out2.read(rbbList(1)) - layout.out3.read(rbbList(2)) - layout.out4.read(rbbList(3)) - layout.out5.read(rbbList(4)) - }, - ) - val prev = aInt.getAndAdd(1) - if prev % 100 == 0 then println(s"Iteration $prev completed") - - runtime.close() - println("Endurance test completed successfully") diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index 782b2a85..00855e4e 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -75,7 +75,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte .pCommandBuffers(pCommandBuffer) val fence = new Fence() - timed("Vulkan render command"): + timed("Vulkan execute command"): check(vkQueueSubmit(commandPool.queue.get, submitInfo, fence.get), "Failed to submit command buffer to queue") fence.block().destroy() commandPool.freeCommandBuffer(commandBuffer) From 27888dc6e97ae191c456d7c0fcaea0b94021a61e Mon Sep 17 00:00:00 2001 From: Szymon Date: Sat, 23 Aug 2025 15:50:08 +0200 Subject: [PATCH 26/59] WIP2 --- .../cyfra/spirv/compilers/GIOCompiler.scala | 4 + .../compilers/SpirvProgramCompiler.scala | 6 +- cyfra-e2e-test/src/test/resources/addOne.comp | 48 ++++ .../src/test/resources/compileAll.ps1 | 4 + .../src/test/resources/compileAll.sh | 7 + cyfra-e2e-test/src/test/resources/emit.comp | 23 ++ cyfra-e2e-test/src/test/resources/filter.comp | 20 ++ .../cyfra/e2e/RuntimeEnduranceTest.scala | 221 ++++++++++++++++++ 8 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala create mode 100644 cyfra-e2e-test/src/test/resources/addOne.comp create mode 100644 cyfra-e2e-test/src/test/resources/compileAll.ps1 create mode 100644 cyfra-e2e-test/src/test/resources/compileAll.sh create mode 100644 cyfra-e2e-test/src/test/resources/emit.comp create mode 100644 cyfra-e2e-test/src/test/resources/filter.comp create mode 100644 cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala new file mode 100644 index 00000000..b291168a --- /dev/null +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala @@ -0,0 +1,4 @@ +package io.computenode.cyfra.spirv.compilers + +object GIOCompiler: + \ No newline at end of file diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index 1aea6fdb..e7330f66 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -4,6 +4,7 @@ import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.dsl.Expression.{Const, E} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.{GStructConstructor, GStructSchema} import io.computenode.cyfra.spirv.Context import io.computenode.cyfra.spirv.SpirvConstants.* @@ -18,7 +19,7 @@ private[cyfra] object SpirvProgramCompiler: case Instruction(Op.OpVariable, _) => true case _ => false - def compileMain(tree: Value, resultType: Tag[?], ctx: Context): (List[Words], Context) = + def compileMain(body: GIO[?], resultType: Tag[?], ctx: Context): (List[Words], Context) = val init = List( Instruction(Op.OpFunction, List(ResultRef(ctx.voidTypeRef), ResultRef(MAIN_FUNC_REF), SamplerAddressingMode.None, ResultRef(VOID_FUNC_TYPE_REF))), @@ -160,7 +161,8 @@ private[cyfra] object SpirvProgramCompiler: Instruction(Op.OpName, List(ResultRef(block.structTypeRef), Text(s"Buffer$tpe"))) :: Instruction(Op.OpName, List(ResultRef(block.blockVarRef), Text(s"data$tpe"))) :: Nil // todo name uniform - context.inBufferBlocks.flatMap(namesForBlock(_, "In")) ::: context.outBufferBlocks.flatMap(namesForBlock(_, "Out")) + //context.inBufferBlocks.flatMap(namesForBlock(_, "In")) ::: context.outBufferBlocks.flatMap(namesForBlock(_, "Out")) + List() def totalStride(gs: GStructSchema[?]): Int = gs.fields .map: diff --git a/cyfra-e2e-test/src/test/resources/addOne.comp b/cyfra-e2e-test/src/test/resources/addOne.comp new file mode 100644 index 00000000..091de31f --- /dev/null +++ b/cyfra-e2e-test/src/test/resources/addOne.comp @@ -0,0 +1,48 @@ +#version 450 + +layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in; + +layout (set = 0, binding = 0) buffer In1 { + int in1[]; +}; +layout (set = 0, binding = 1) buffer In2 { + int in2[]; +}; +layout (set = 0, binding = 2) buffer In3 { + int in3[]; +}; +layout (set = 0, binding = 3) buffer In4 { + int in4[]; +}; +layout (set = 0, binding = 4) buffer In5 { + int in5[]; +}; +layout (set = 0, binding = 5) buffer Out1 { + int out1[]; +}; +layout (set = 0, binding = 6) buffer Out2 { + int out2[]; +}; +layout (set = 0, binding = 7) buffer Out3 { + int out3[]; +}; +layout (set = 0, binding = 8) buffer Out4 { + int out4[]; +}; +layout (set = 0, binding = 9) buffer Out5 { + int out5[]; +}; +layout (set = 0, binding = 10) uniform U1 { + int a; +}; +layout (set = 0, binding = 11) uniform U2 { + int b; +}; +void main(void) { + uint index = gl_GlobalInvocationID.x; + out1[index] = in1[index] + a + b; + out2[index] = in2[index] + a + b; + out3[index] = in3[index] + a + b; + out4[index] = in4[index] + a + b; + out5[index] = in5[index] + a + b; +} diff --git a/cyfra-e2e-test/src/test/resources/compileAll.ps1 b/cyfra-e2e-test/src/test/resources/compileAll.ps1 new file mode 100644 index 00000000..e1755a32 --- /dev/null +++ b/cyfra-e2e-test/src/test/resources/compileAll.ps1 @@ -0,0 +1,4 @@ +Get-ChildItem -Filter *.comp -Name | ForEach-Object -Process { + $name = $_.Replace(".comp", "") + "$Env:VULKAN_SDK\Bin\glslangValidator.exe -V $name.comp -o $name.spv" | Invoke-Expression +} diff --git a/cyfra-e2e-test/src/test/resources/compileAll.sh b/cyfra-e2e-test/src/test/resources/compileAll.sh new file mode 100644 index 00000000..e4f70140 --- /dev/null +++ b/cyfra-e2e-test/src/test/resources/compileAll.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +for f in *.comp +do + prefix=$(echo "$f" | cut -f 1 -d '.') + glslangValidator -V "$prefix.comp" -o "$prefix.spv" +done diff --git a/cyfra-e2e-test/src/test/resources/emit.comp b/cyfra-e2e-test/src/test/resources/emit.comp new file mode 100644 index 00000000..5789c424 --- /dev/null +++ b/cyfra-e2e-test/src/test/resources/emit.comp @@ -0,0 +1,23 @@ +#version 450 + +layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in; + +layout (set = 0, binding = 0) buffer InputBuffer { + int inBuffer[]; +}; +layout (set = 0, binding = 1) buffer OutputBuffer { + int outBuffer[]; +}; + +layout (set = 0, binding = 2) uniform InputUniform { + int emitN; +}; + +void main(void) { + uint index = gl_GlobalInvocationID.x; + int element = inBuffer[index]; + uint offset = index * uint(emitN); + for (int i = 0; i < emitN; i++) { + outBuffer[offset + uint(i)] = element; + } +} diff --git a/cyfra-e2e-test/src/test/resources/filter.comp b/cyfra-e2e-test/src/test/resources/filter.comp new file mode 100644 index 00000000..37beef64 --- /dev/null +++ b/cyfra-e2e-test/src/test/resources/filter.comp @@ -0,0 +1,20 @@ +#version 450 + +layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in; + +layout (set = 0, binding = 0) buffer InputBuffer { + int inBuffer[]; +}; +layout (set = 0, binding = 1) buffer OutputBuffer { + bool outBuffer[]; +}; + +layout (set = 0, binding = 2) uniform InputUniform { + int filterValue; +}; + +void main(void) { + uint index = gl_GlobalInvocationID.x; + int element = inBuffer[index]; + outBuffer[index] = (element == filterValue); +} diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala new file mode 100644 index 00000000..35ad5bb2 --- /dev/null +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala @@ -0,0 +1,221 @@ +package io.computenode.cyfra.e2e + +import io.computenode.cyfra.core.archive.GContext +import io.computenode.cyfra.core.layout.* +import io.computenode.cyfra.core.{GBufferRegion, GExecution, GProgram} +import io.computenode.cyfra.dsl.Value.{GBoolean, Int32} +import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} +import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.runtime.VkCyfraRuntime +import io.computenode.cyfra.utility.Logger.logger +import org.lwjgl.BufferUtils +import org.lwjgl.system.MemoryUtil + +import scala.concurrent.ExecutionContext.Implicits.global +import java.util.concurrent.atomic.AtomicInteger +import scala.concurrent.{Await, Future} + + +class RuntimeEnduranceTest extends munit.FunSuite: + + test("Endurance test for GExecution with multiple programs"): + runEnduranceTest(10000) + + // === Emit program === + + case class EmitProgramParams(inSize: Int, emitN: Int) + + case class EmitProgramUniform(emitN: Int32) extends GStruct[EmitProgramUniform] + + case class EmitProgramLayout( + in: GBuffer[Int32], + out: GBuffer[Int32], + args: GUniform[EmitProgramUniform] = GUniform.fromParams, // todo will be different in the future + ) extends Layout + + val emitProgram = GProgram[EmitProgramParams, EmitProgramLayout]( + layout = params => + EmitProgramLayout( + in = GBuffer[Int32](params.inSize), + out = GBuffer[Int32](params.inSize * params.emitN), + args = GUniform(EmitProgramUniform(params.emitN)), + ), + dispatch = (_, args) => GProgram.StaticDispatch((args.inSize / 128, 1, 1)), + ): layout => + val EmitProgramUniform(emitN) = layout.args.read + val invocId = GIO.invocationId + val element = GIO.read(layout.in, invocId) + val bufferOffset = invocId * emitN + GIO.repeat(emitN): i => + GIO.write(layout.out, bufferOffset + i, element) + + // === Filter program === + + case class FilterProgramParams(inSize: Int, filterValue: Int) + + case class FilterProgramUniform(filterValue: Int32) extends GStruct[FilterProgramUniform] + + case class FilterProgramLayout(in: GBuffer[Int32], out: GBuffer[GBoolean], params: GUniform[FilterProgramUniform] = GUniform.fromParams) + extends Layout + + val filterProgram = GProgram[FilterProgramParams, FilterProgramLayout]( + layout = params => + FilterProgramLayout( + in = GBuffer[Int32](params.inSize), + out = GBuffer[GBoolean](params.inSize), + params = GUniform(FilterProgramUniform(params.filterValue)), + ), + dispatch = (_, args) => GProgram.StaticDispatch((args.inSize / 128, 1, 1)), + ): layout => + val invocId = GIO.invocationId + val element = GIO.read(layout.in, invocId) + val isMatch = element === layout.params.read.filterValue + GIO.write(layout.out, invocId, isMatch) + + // === GExecution === + + case class EmitFilterParams(inSize: Int, emitN: Int, filterValue: Int) + + case class EmitFilterLayout(inBuffer: GBuffer[Int32], emitBuffer: GBuffer[Int32], filterBuffer: GBuffer[GBoolean]) extends Layout + + case class EmitFilterResult(out: GBuffer[GBoolean]) extends Layout + + val emitFilterExecution = GExecution[EmitFilterParams, EmitFilterLayout]() + .addProgram(emitProgram)( + params => EmitProgramParams(inSize = params.inSize, emitN = params.emitN), + layout => EmitProgramLayout(in = layout.inBuffer, out = layout.emitBuffer), + ) + .addProgram(filterProgram)( + params => FilterProgramParams(inSize = 2 * params.inSize, filterValue = params.filterValue), + layout => FilterProgramLayout(in = layout.emitBuffer, out = layout.filterBuffer), + ) + + // Test case: Use one program 10 times, copying values from five input buffers to five output buffers and adding values from two uniforms + case class AddProgramParams(bufferSize: Int, addA: Int, addB: Int) + + case class AddProgramUniform(a: Int32) extends GStruct[AddProgramUniform] + + case class AddProgramLayout( + in1: GBuffer[Int32], + in2: GBuffer[Int32], + in3: GBuffer[Int32], + in4: GBuffer[Int32], + in5: GBuffer[Int32], + out1: GBuffer[Int32], + out2: GBuffer[Int32], + out3: GBuffer[Int32], + out4: GBuffer[Int32], + out5: GBuffer[Int32], + u1: GUniform[AddProgramUniform] = GUniform.fromParams, + u2: GUniform[AddProgramUniform] = GUniform.fromParams, + ) extends Layout + + case class AddProgramExecLayout( + in1: GBuffer[Int32], + in2: GBuffer[Int32], + in3: GBuffer[Int32], + in4: GBuffer[Int32], + in5: GBuffer[Int32], + out1: GBuffer[Int32], + out2: GBuffer[Int32], + out3: GBuffer[Int32], + out4: GBuffer[Int32], + out5: GBuffer[Int32], + ) extends Layout + + val addProgram: GProgram[AddProgramParams, AddProgramLayout] = GProgram[AddProgramParams, AddProgramLayout]( + layout = params => + AddProgramLayout( + in1 = GBuffer[Int32](params.bufferSize), + in2 = GBuffer[Int32](params.bufferSize), + in3 = GBuffer[Int32](params.bufferSize), + in4 = GBuffer[Int32](params.bufferSize), + in5 = GBuffer[Int32](params.bufferSize), + out1 = GBuffer[Int32](params.bufferSize), + out2 = GBuffer[Int32](params.bufferSize), + out3 = GBuffer[Int32](params.bufferSize), + out4 = GBuffer[Int32](params.bufferSize), + out5 = GBuffer[Int32](params.bufferSize), + u1 = GUniform(AddProgramUniform(params.addA)), + u2 = GUniform(AddProgramUniform(params.addB)), + ), + dispatch = (layout, args) => GProgram.StaticDispatch((args.bufferSize / 128, 1, 1)), + ): + case AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5, u1, u2) => + val index = GIO.invocationId + val a = u1.read.a + val b = u2.read.a + for + _ <- GIO.write(out1, index, GIO.read(in1, index) + a + b) + _ <- GIO.write(out2, index, GIO.read(in2, index) + a + b) + _ <- GIO.write(out3, index, GIO.read(in3, index) + a + b) + _ <- GIO.write(out4, index, GIO.read(in4, index) + a + b) + _ <- GIO.write(out5, index, GIO.read(in5, index) + a + b) + yield () + + def swap(l: AddProgramLayout): AddProgramLayout = + val AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5, u1, u2) = l + AddProgramLayout(out1, out2, out3, out4, out5, in1, in2, in3, in4, in5, u1, u2) + + def fromExecLayout(l: AddProgramExecLayout): AddProgramLayout = + val AddProgramExecLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5) = l + AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5) + + val execution = (0 until 11).foldLeft( + GExecution[AddProgramParams, AddProgramExecLayout]().asInstanceOf[GExecution[AddProgramParams, AddProgramExecLayout, AddProgramExecLayout]], + )((x, i) => + if i % 2 == 0 then x.addProgram(addProgram)(mapParams = identity[AddProgramParams], mapLayout = fromExecLayout) + else x.addProgram(addProgram)(mapParams = identity, mapLayout = x => swap(fromExecLayout(x))), + ) + + def runEnduranceTest(nRuns: Int): Unit = + logger.info(s"Starting endurance test with ${nRuns} runs...") + + given runtime: VkCyfraRuntime = VkCyfraRuntime() + + val bufferSize = 1280 + val params = AddProgramParams(bufferSize, addA = 0, addB = 1) + val region = GBufferRegion + .allocate[AddProgramExecLayout] + .map: region => + execution.execute(params, region) + val aInt = new AtomicInteger(0) + val runs = (1 to nRuns).map: + i => Future: + val inBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) + val wbbList = inBuffers.map(MemoryUtil.memByteBuffer) + val rbbList = List.fill(5)(BufferUtils.createByteBuffer(bufferSize * 4)) + + val inData = (0 until bufferSize).toArray + inBuffers.foreach(_.put(inData).flip()) + region.runUnsafe( + init = AddProgramExecLayout( + in1 = GBuffer[Int32](wbbList(0)), + in2 = GBuffer[Int32](wbbList(1)), + in3 = GBuffer[Int32](wbbList(2)), + in4 = GBuffer[Int32](wbbList(3)), + in5 = GBuffer[Int32](wbbList(4)), + out1 = GBuffer[Int32](bufferSize), + out2 = GBuffer[Int32](bufferSize), + out3 = GBuffer[Int32](bufferSize), + out4 = GBuffer[Int32](bufferSize), + out5 = GBuffer[Int32](bufferSize), + ), + onDone = layout => { + layout.out1.read(rbbList(0)) + layout.out2.read(rbbList(1)) + layout.out3.read(rbbList(2)) + layout.out4.read(rbbList(3)) + layout.out5.read(rbbList(4)) + }, + ) + val prev = aInt.getAndAdd(1) + if prev % 50 == 0 then logger.info(s"Iteration $prev completed") + + val allRuns = Future.sequence(runs) + Await.result(allRuns, scala.concurrent.duration.Duration.Inf) + + runtime.close() + logger.info("Endurance test completed successfully") From 21494b8d4f9818310dcf3e7a7940f89bfc531188 Mon Sep 17 00:00:00 2001 From: Szymon Date: Sat, 23 Aug 2025 22:50:51 +0200 Subject: [PATCH 27/59] WIP3 --- .../io/computenode/cyfra/spirv/Context.scala | 3 +- .../cyfra/spirv/compilers/DSLCompiler.scala | 40 ++++++++++++--- .../spirv/compilers/ExpressionCompiler.scala | 10 ++-- .../cyfra/spirv/compilers/GIOCompiler.scala | 51 ++++++++++++++++++- .../compilers/SpirvProgramCompiler.scala | 39 +++++++------- .../io/computenode/cyfra/core/GProgram.scala | 1 - .../computenode/cyfra/core/GioProgram.scala | 7 +-- .../computenode/cyfra/core/SpirvProgram.scala | 16 +----- .../cyfra/core/archive/GContext.scala | 1 - .../cyfra/dsl/binding/GBinding.scala | 11 ++-- .../cyfra/dsl/binding/WriteBuffer.scala | 5 +- .../cyfra/dsl/binding/WriteUniform.scala | 5 +- .../cyfra/dsl/collections/GArray.scala | 13 +++++ .../cyfra/dsl/collections/GArray2D.scala | 13 +++++ .../io/computenode/cyfra/dsl/gio/GIO.scala | 28 +++++----- .../computenode/cyfra/runtime/VkShader.scala | 7 ++- 16 files changed, 170 insertions(+), 80 deletions(-) create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala create mode 100644 cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala index 20ffd53a..35b39a46 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala @@ -1,5 +1,6 @@ package io.computenode.cyfra.spirv +import io.computenode.cyfra.dsl.binding.GBuffer import io.computenode.cyfra.dsl.macros.FnCall.FnIdentifier import io.computenode.cyfra.spirv.SpirvConstants.HEADER_REFS_TOP import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction @@ -20,7 +21,7 @@ private[cyfra] case class Context( bindingToStructType: Map[Int, Int] = Map.empty, constRefs: Map[(Tag[?], Any), Int] = Map(), exprRefs: Map[Int, Int] = Map(), - bufferBlocks: List[ArrayBufferBlock] = List(), + bufferBlocks: Map[GBuffer[?], ArrayBufferBlock] = Map(), nextResultId: Int = HEADER_REFS_TOP, nextBinding: Int = 0, exprNames: Map[Int, String] = Map(), diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala index fc2b30bd..f15c9d54 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala @@ -4,6 +4,8 @@ import io.computenode.cyfra.* import io.computenode.cyfra.dsl.* import io.computenode.cyfra.dsl.Expression.E import io.computenode.cyfra.dsl.Value.Scalar +import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform, WriteBuffer, WriteUniform} +import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.GStruct.* import io.computenode.cyfra.dsl.struct.GStructSchema import io.computenode.cyfra.spirv.Context @@ -24,6 +26,25 @@ import scala.runtime.stdLibPatches.Predef.summon private[cyfra] object DSLCompiler: + @tailrec + private def getAllExprsFlattened(pending: List[GIO[?]], acc: List[E[?]], visitDetached: Boolean): List[E[?]] = + pending match + case Nil => acc + case GIO.Pure(v) :: tail => + getAllExprsFlattened(tail, getAllExprsFlattened(v.tree, visitDetached), visitDetached) + case GIO.FlatMap(v, n) :: tail => + getAllExprsFlattened(v :: n :: tail, acc, visitDetached) + case GIO.Repeat(n, gio) :: tail => + val nAllExprs = getAllExprsFlattened(n.tree, visitDetached) + getAllExprsFlattened(gio :: tail, nAllExprs ::: acc, visitDetached) + case WriteBuffer(_, index, value) :: tail => + val indexAllExprs = getAllExprsFlattened(index.tree, visitDetached) + val valueAllExprs = getAllExprsFlattened(value.tree, visitDetached) + getAllExprsFlattened(tail, indexAllExprs ::: valueAllExprs ::: acc, visitDetached) + case WriteUniform(_, value) :: tail => + val valueAllExprs = getAllExprsFlattened(value.tree, visitDetached) + getAllExprsFlattened(tail, valueAllExprs ::: acc, visitDetached) + // TODO: Not traverse same fn scopes for each fn call private def getAllExprsFlattened(root: E[?], visitDetached: Boolean): List[E[?]] = var blockI = 0 @@ -33,7 +54,7 @@ private[cyfra] object DSLCompiler: def getAllScopesExprsAcc(toVisit: List[E[?]], acc: List[E[?]] = Nil): List[E[?]] = toVisit match case Nil => acc case e :: tail if visited.contains(e.treeid) => getAllScopesExprsAcc(tail, acc) - case e :: tail => + case e :: tail => // todo i don't think this really works (tail not used???) if allScopesCache.contains(root.treeid) then return allScopesCache(root.treeid) val eScopes = e.introducedScopes val filteredScopes = if visitDetached then eScopes else eScopes.filterNot(_.isDetached) @@ -47,18 +68,22 @@ private[cyfra] object DSLCompiler: allScopesCache(root.treeid) = result result - def compile(tree: Value, buffers: List[Tag[?]], uniformSchemaIns: List[GStructSchema[?]]): ByteBuffer = - val treeExpr = tree.tree - val allExprs = getAllExprsFlattened(treeExpr, visitDetached = true) + def compile(bodyIo: GIO[?], bindings: List[GBinding[?]]): ByteBuffer = + val allExprs = getAllExprsFlattened(List(bodyIo), Nil, visitDetached = true) val typesInCode = allExprs.map(_.tag).distinct - val allTypes = (typesInCode ::: buffers).distinct + val allTypes = (typesInCode ::: bindings.map(_.tag)).distinct def scalarTypes = allTypes.filter(_.tag <:< summon[Tag[Scalar]].tag) val (typeDefs, typedContext) = defineScalarTypes(scalarTypes, Context.initialContext) + val (buffers, uniforms) = bindings.partition: + case _: GBuffer[?] => true + case _: GUniform[?] => false + .asInstanceOf[(List[GBinding[?]], List[GUniform[?]])] + val uniformSchemas = uniforms.map(_.schema) val structsInCode = (allExprs.collect { case cs: ComposeStruct[?] => cs.resultSchema case gf: GetField[?, ?] => gf.resultSchema - } ::: uniformSchemaIns).distinct + } ::: uniformSchemas).distinct val (structDefs, structCtx) = defineStructTypes(structsInCode, typedContext) val structNames = getStructNames(structsInCode, structCtx) val (decorations, uniformDefs, uniformContext) = initAndDecorateBuffers(buffers, structCtx) @@ -67,8 +92,7 @@ private[cyfra] object DSLCompiler: val (inputDefs, inputContext) = createInvocationId(uniformStructContext) val (constDefs, constCtx) = defineConstants(allExprs, inputContext) val (varDefs, varCtx) = defineVarNames(constCtx) - val resultType = tree.tree.tag - val (main, ctxAfterMain) = compileMain(tree, resultType, varCtx) + val (main, ctxAfterMain) = compileMain(bodyIo, varCtx) val (fnTypeDefs, fnDefs, ctxWithFnDefs) = compileFunctions(ctxAfterMain) val nameDecorations = getNameDecorations(ctxWithFnDefs) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala index 5d99da3a..7e7cb849 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala @@ -3,7 +3,7 @@ package io.computenode.cyfra.spirv.compilers import io.computenode.cyfra.dsl.* import io.computenode.cyfra.dsl.Expression.* import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.collections.GArray.GArrayElem +import io.computenode.cyfra.dsl.binding.* import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.macros.Source import io.computenode.cyfra.dsl.struct.GStruct.{ComposeStruct, GetField} @@ -289,19 +289,19 @@ private[cyfra] object ExpressionCompiler: case fc: FunctionCall[?] => compileFunctionCall(fc, ctx) - case ReadBuffer(index, i) => + case ReadBuffer(buffer, i) => val instructions = List( Instruction( Op.OpAccessChain, List( - ResultRef(ctx.uniformPointerMap(ctx.valueTypeMap(ga.tag.tag))), + ResultRef(ctx.uniformPointerMap(ctx.valueTypeMap(buffer.tag.tag))), ResultRef(ctx.nextResultId), - ResultRef(ctx.inBufferBlocks(index).blockVarRef), + ResultRef(ctx.bufferBlocks(buffer).blockVarRef), ResultRef(ctx.constRefs((Int32Tag, 0))), ResultRef(ctx.exprRefs(i.treeid)), ), ), - Instruction(Op.OpLoad, List(IntWord(ctx.valueTypeMap(ga.tag.tag)), ResultRef(ctx.nextResultId + 1), ResultRef(ctx.nextResultId))), + Instruction(Op.OpLoad, List(IntWord(ctx.valueTypeMap(buffer.tag.tag)), ResultRef(ctx.nextResultId + 1), ResultRef(ctx.nextResultId))), ) val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> (ctx.nextResultId + 1)), nextResultId = ctx.nextResultId + 2) (instructions, updatedContext) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala index b291168a..c64b9cae 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala @@ -1,4 +1,53 @@ package io.computenode.cyfra.spirv.compilers +import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.spirv.Context +import io.computenode.cyfra.spirv.Opcodes.* +import io.computenode.cyfra.dsl.binding.* +import io.computenode.cyfra.dsl.gio.GIO.CurrentRepeatIndex +import io.computenode.cyfra.spirv.SpirvTypes.{Int32Tag, LInt32Tag} + object GIOCompiler: - \ No newline at end of file + + def compileGio(gio: GIO[?], ctx: Context, acc: List[Words] = Nil): (List[Words], Context) = + gio match + + case GIO.Pure(v) => + val (insts, updatedCtx) = ExpressionCompiler.compileBlock(v.tree, ctx) + (acc ::: insts, updatedCtx) + + case WriteBuffer(buffer, index, value) => + val insns = List(Instruction( + Op.OpAccessChain, + List( + ResultRef(ctx.uniformPointerMap(ctx.valueTypeMap(buffer.tag.tag))), + ResultRef(ctx.nextResultId), + ResultRef(ctx.bufferBlocks(buffer).blockVarRef), + ResultRef(ctx.constRefs((Int32Tag, 0))), + ResultRef(ctx.workerIndexRef), + ), + ), + Instruction(Op.OpStore, List(ResultRef(ctx.nextResultId), ResultRef(ctx.exprRefs(value.tree.treeid)))) + ) + val updatedCtx = ctx.copy(nextResultId = ctx.nextResultId + 1) + (acc ::: insns, updatedCtx) + + case GIO.Repeat(n, f) => + val (nInsts, ctxWithN) = ExpressionCompiler.compileBlock(n.tree, ctx) + val loopHeaderId = ctxWithN.nextResultId + val loopMergeId = ctxWithN.nextResultId + 1 + val loopContinueId = ctxWithN.nextResultId + 2 + val counterVarId = ctxWithN.nextResultId + 3 + val ctxWithCounter = ctxWithN.copy(exprRefs = ctxWithN.exprRefs + (CurrentRepeatIndex.treeid -> counterVarId), nextResultId = ctxWithN.nextResultId + 4) + val counterInit = Instruction(Op.OpVariable, List(ResultRef(ctxWithCounter.constRefs((Int32Tag, 0))), ResultRef(counterVarId), StorageClass.Function)) + val counterStore = Instruction(Op.OpStore, List(ResultRef(counterVarId), ResultRef(ctxWithCounter.constRefs((Int32Tag, 0))))) + val (body, afterBodyCtx) = compileGio(f, ctxWithCounter) + // todo + ??? + + + + + + + \ No newline at end of file diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index e7330f66..73ebf1bf 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -4,6 +4,7 @@ import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.dsl.Expression.{Const, E} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.binding.GBuffer import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.{GStructConstructor, GStructSchema} import io.computenode.cyfra.spirv.Context @@ -19,7 +20,7 @@ private[cyfra] object SpirvProgramCompiler: case Instruction(Op.OpVariable, _) => true case _ => false - def compileMain(body: GIO[?], resultType: Tag[?], ctx: Context): (List[Words], Context) = + def compileMain(bodyIo: GIO[?], ctx: Context): (List[Words], Context) = val init = List( Instruction(Op.OpFunction, List(ResultRef(ctx.voidTypeRef), ResultRef(MAIN_FUNC_REF), SamplerAddressingMode.None, ResultRef(VOID_FUNC_TYPE_REF))), @@ -39,22 +40,23 @@ private[cyfra] object SpirvProgramCompiler: Instruction(Op.OpLoad, List(ResultRef(ctx.valueTypeMap(Int32Tag.tag)), ResultRef(ctx.nextResultId + 2), ResultRef(ctx.nextResultId + 1))), ) - val (body, codeCtx) = compileBlock(tree.tree, ctx.copy(nextResultId = ctx.nextResultId + 3, workerIndexRef = ctx.nextResultId + 2)) + val (body, codeCtx) = GIOCompiler.compileGio(bodyIo, ctx.copy(nextResultId = ctx.nextResultId + 3, workerIndexRef = ctx.nextResultId + 2)) val (vars, nonVarsBody) = bubbleUpVars(body) val end = List( - Instruction( - Op.OpAccessChain, - List( - ResultRef(codeCtx.uniformPointerMap(codeCtx.valueTypeMap(resultType.tag))), - ResultRef(codeCtx.nextResultId), - ResultRef(codeCtx.outBufferBlocks.head.blockVarRef), - ResultRef(codeCtx.constRefs((Int32Tag, 0))), - ResultRef(codeCtx.workerIndexRef), - ), - ), - Instruction(Op.OpStore, List(ResultRef(codeCtx.nextResultId), ResultRef(codeCtx.exprRefs(tree.tree.treeid)))), +// TODO Remove - Write is a part of GIO now +// Instruction( +// Op.OpAccessChain, +// List( +// ResultRef(codeCtx.uniformPointerMap(codeCtx.valueTypeMap(resultType.tag))), +// ResultRef(codeCtx.nextResultId), +// ResultRef(codeCtx.outBufferBlocks.head.blockVarRef), +// ResultRef(codeCtx.constRefs((Int32Tag, 0))), +// ResultRef(codeCtx.workerIndexRef), +// ), +// ), +// Instruction(Op.OpStore, List(ResultRef(codeCtx.nextResultId), ResultRef(codeCtx.exprRefs(tree.tree.treeid)))), Instruction(Op.OpReturn, List()), Instruction(Op.OpFunctionEnd, List()), ) @@ -120,15 +122,14 @@ private[cyfra] object SpirvProgramCompiler: ), ) (definitionInstructions, context.copy(nextResultId = context.nextResultId + 3)) - def initAndDecorateBuffers(buffers: List[Tag[?]], context: Context): (List[Words], List[Words], Context) = + def initAndDecorateBuffers(buffers: List[GBuffer[?]], context: Context): (List[Words], List[Words], Context) = val (blockDecor, blockDef, inCtx) = createAndInitBlocks(buffers, context) val (voidsDef, voidCtx) = defineVoids(inCtx) (blockDecor, voidsDef ::: blockDef, voidCtx) - - - def createAndInitBlocks(blocks: List[Tag[?]], context: Context): (List[Words], List[Words], Context) = - val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { case ((decAcc, insnAcc, ctx), tpe) => + def createAndInitBlocks(blocks: List[GBuffer[?]], context: Context): (List[Words], List[Words], Context) = + val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { case ((decAcc, insnAcc, ctx), buff) => + val tpe = buff.tag val block = ArrayBufferBlock(ctx.nextResultId, ctx.nextResultId + 1, ctx.nextResultId + 2, ctx.nextResultId + 3, ctx.nextBinding) val decorationInstructions = List[Words]( @@ -147,7 +148,7 @@ private[cyfra] object SpirvProgramCompiler: ) val contextWithBlock = - ctx.copy(bufferBlocks = block :: ctx.bufferBlocks) + ctx.copy(bufferBlocks = ctx.bufferBlocks + (buff -> block)) ( decAcc ::: decorationInstructions, insnAcc ::: definitionInstructions, diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala index da5407df..d1a43226 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala @@ -16,7 +16,6 @@ trait GProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}] extends GExec val layout: InitProgramLayout => Params => L val dispatch: (L, Params) => ProgramDispatch val workgroupSize: WorkDimensions - private[cyfra] def cacheKey: String // TODO better type def layoutStruct = summon[LayoutStruct[L]] object GProgram: diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GioProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GioProgram.scala index d97f97b2..03158fea 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GioProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GioProgram.scala @@ -11,9 +11,4 @@ case class GioProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}]( layout: InitProgramLayout => Params => L, dispatch: (L, Params) => ProgramDispatch, workgroupSize: WorkDimensions, -) extends GProgram[Params, L]: - private[cyfra] def cacheKey: String = summon[LayoutStruct[L]].elementTypes match - case x if x.size == 12 => "addOne" - case x if x.contains(summon[Tag[GBoolean]]) && x.size == 3 => "filter" - case x if x.size == 3 => "emit" - case _ => ??? +) extends GProgram[Params, L] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala index c7b9f29a..b4bcbd85 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala @@ -26,7 +26,6 @@ case class SpirvProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}] priv code: ByteBuffer, entryPoint: String, shaderBindings: L => ShaderLayout, - cacheKey: String, ) extends GProgram[Params, L] object SpirvProgram: @@ -38,24 +37,13 @@ object SpirvProgram: case ReadWrite def apply[Params, L <: Layout: {LayoutBinding, LayoutStruct}]( - path: String, layout: InitProgramLayout ?=> Params => L, dispatch: (L, Params) => ProgramDispatch, + code: ByteBuffer ): SpirvProgram[Params, L] = - val code = loadShader(path).get val workgroupSize = (128, 1, 1) // TODO Extract form shader val main = "main" val f: L => ShaderLayout = { case layout: Product => layout.productIterator.zipWithIndex.map { case (binding: GBinding[?], i) => Binding(binding, ReadWrite) }.toSeq.pipe(Seq(_)) } - val cacheKey = - val x = new File(path).getName - x.substring(0, x.lastIndexOf('.')) - new SpirvProgram[Params, L]((il: InitProgramLayout) => layout(using il), dispatch, workgroupSize, code, main, f, cacheKey) - - def loadShader(path: String, classLoader: ClassLoader = getClass.getClassLoader): Try[ByteBuffer] = - Using.Manager: use => - val file = new File(Objects.requireNonNull(classLoader.getResource(path)).getFile) - val fis = use(new FileInputStream(file)) - val fc = use(fis.getChannel) - fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()) + new SpirvProgram[Params, L]((il: InitProgramLayout) => layout(using il), dispatch, workgroupSize, code, main, f) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala index 59a04927..7b141690 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala @@ -5,7 +5,6 @@ import io.computenode.cyfra.core.archive.mem.{FloatMem, GMem, IntMem, Vec4FloatM import io.computenode.cyfra.core.archive.{GFunction, UniformContext} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.{Float32, FromExpr, Int32, Vec4} -import io.computenode.cyfra.dsl.collections.GArray import io.computenode.cyfra.dsl.struct.* import io.computenode.cyfra.spirv.SpirvTypes.typeStride import io.computenode.cyfra.spirv.compilers.DSLCompiler diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala index 60c53cac..8bad4bb8 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala @@ -4,7 +4,8 @@ import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr.fromExpr as fromExprEval import io.computenode.cyfra.dsl.Value.{FromExpr, Int32} import io.computenode.cyfra.dsl.gio.GIO -import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} +import io.computenode.cyfra.dsl.struct.GStruct.Empty import izumi.reflect.Tag sealed trait GBinding[T <: Value: {Tag, FromExpr}]: @@ -14,14 +15,16 @@ sealed trait GBinding[T <: Value: {Tag, FromExpr}]: trait GBuffer[T <: Value: {FromExpr, Tag}] extends GBinding[T]: def read(index: Int32): T = FromExpr.fromExpr(ReadBuffer(this, index)) - def write(index: Int32, value: T): GIO[Unit] = GIO.write(this, index, value) + def write(index: Int32, value: T): GIO[Empty] = GIO.write(this, index, value) object GBuffer -trait GUniform[T <: Value: {Tag, FromExpr}] extends GBinding[T]: +trait GUniform[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}] extends GBinding[T]: def read: T = fromExprEval(ReadUniform(this)) - def write(value: T): GIO[Unit] = WriteUniform(this, value) + def write(value: T): GIO[Empty] = WriteUniform(this, value) + + def schema = summon[GStructSchema[T]] object GUniform: diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteBuffer.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteBuffer.scala index 53b0abf9..1856079a 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteBuffer.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteBuffer.scala @@ -3,6 +3,7 @@ package io.computenode.cyfra.dsl.binding import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.Int32 import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.dsl.struct.GStruct.Empty -case class WriteBuffer[T <: Value](buffer: GBuffer[T], index: Int32, value: T) extends GIO[Unit]: - override def underlying: Unit = () +case class WriteBuffer[T <: Value](buffer: GBuffer[T], index: Int32, value: T) extends GIO[Empty]: + override def underlying: Empty = Empty() diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala index 240aa643..a450a5e7 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala @@ -3,7 +3,8 @@ package io.computenode.cyfra.dsl.binding import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.GStruct.Empty import izumi.reflect.Tag -case class WriteUniform[T <: Value: Tag](uniform: GUniform[T], value: T) extends GIO[Unit]: - override def underlying: Unit = () +case class WriteUniform[T <: Value: Tag](uniform: GUniform[T], value: T) extends GIO[Empty]: + override def underlying: Empty = Empty() diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala new file mode 100644 index 00000000..4ffc51c3 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala @@ -0,0 +1,13 @@ +package io.computenode.cyfra.dsl.collections + +import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.binding.{GBuffer, ReadBuffer} +import io.computenode.cyfra.dsl.macros.Source +import io.computenode.cyfra.dsl.{Expression, Value} +import izumi.reflect.Tag + +// todo temporary +case class GArray[T <: Value: {Tag, FromExpr}](underlying: GBuffer[T]): + def at(i: Int32)(using Source): T = + summon[FromExpr[T]].fromExpr(ReadBuffer(underlying, i)) + diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala new file mode 100644 index 00000000..e532eea2 --- /dev/null +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala @@ -0,0 +1,13 @@ +package io.computenode.cyfra.dsl.collections + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.Int32 +import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} +import io.computenode.cyfra.dsl.macros.Source +import izumi.reflect.Tag +import io.computenode.cyfra.dsl.Value.FromExpr + +// todo temporary +class GArray2D[T <: Value: {Tag, FromExpr}](width: Int, val arr: GArray[T]): + def at(x: Int32, y: Int32)(using Source): T = + arr.at(y * width + x) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala index 02a018f8..7c1fa7f4 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala @@ -6,36 +6,40 @@ import io.computenode.cyfra.dsl.Value.FromExpr.fromExpr import io.computenode.cyfra.dsl.binding.{GBuffer, ReadBuffer, WriteBuffer} import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.gio.GIO.* +import io.computenode.cyfra.dsl.struct.GStruct.Empty import izumi.reflect.Tag -trait GIO[T]: +trait GIO[T <: Value]: - def flatMap[U](f: T => GIO[U]): GIO[U] = FlatMap(this, f(this.underlying)) + def flatMap[U <: Value](f: T => GIO[U]): GIO[U] = FlatMap(this, f(this.underlying)) - def map[U](f: T => U): GIO[U] = flatMap(t => GIO.pure(f(t))) + def map[U <: Value](f: T => U): GIO[U] = flatMap(t => GIO.pure(f(t))) private[cyfra] def underlying: T object GIO: - case class Pure[T](value: T) extends GIO[T]: + case class Pure[T <: Value](value: T) extends GIO[T]: override def underlying: T = value - case class FlatMap[T, U](gio: GIO[T], next: GIO[U]) extends GIO[U]: + case class FlatMap[T <: Value, U <: Value](gio: GIO[T], next: GIO[U]) extends GIO[U]: override def underlying: U = next.underlying // TODO repeat that collects results - case class Repeat(n: Int32, f: Int32 => GIO[?]) extends GIO[Unit]: - override def underlying: Unit = () + case class Repeat(n: Int32, f: GIO[?]) extends GIO[Empty]: + override def underlying: Empty = Empty() - def pure[T](value: T): GIO[T] = Pure(value) + def pure[T <: Value](value: T): GIO[T] = Pure(value) - def value[T](value: T): GIO[T] = Pure(value) + def value[T <: Value](value: T): GIO[T] = Pure(value) - def repeat(n: Int32)(f: Int32 => GIO[?]): GIO[Unit] = - Repeat(n, f) + case object CurrentRepeatIndex extends PhantomExpression[Int32] with CustomTreeId: + override val treeid: Int = treeidState.getAndIncrement() + + def repeat(n: Int32)(f: Int32 => GIO[?]): GIO[Empty] = + Repeat(n, f(fromExpr(CurrentRepeatIndex))) - def write[T <: Value](buffer: GBuffer[T], index: Int32, value: T): GIO[Unit] = + def write[T <: Value](buffer: GBuffer[T], index: Int32, value: T): GIO[Empty] = WriteBuffer(buffer, index, value) def read[T <: Value: {FromExpr, Tag}](buffer: GBuffer[T], index: Int32): T = diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala index f0885cb9..3086b15c 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala @@ -5,6 +5,7 @@ import io.computenode.cyfra.core.SpirvProgram.* import io.computenode.cyfra.core.GProgram.InitProgramLayout import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} +import io.computenode.cyfra.spirv.compilers.DSLCompiler import io.computenode.cyfra.vulkan.compute.ComputePipeline import io.computenode.cyfra.vulkan.compute.ComputePipeline.* import io.computenode.cyfra.vulkan.core.Device @@ -36,7 +37,5 @@ object VkShader: def compile[Params, L <: Layout: {LayoutBinding, LayoutStruct}](program: GioProgram[Params, L]): SpirvProgram[Params, L] = val GioProgram(_, layout, dispatch, _) = program - val name = program.cacheKey + ".spv" - loadShader(name) match - case Failure(_) => ??? - case Success(_) => SpirvProgram(name, (il: InitProgramLayout) ?=> layout(il), dispatch) + val compiled = DSLCompiler.compile(program.body(summon[LayoutStruct[L]].layoutRef), ???) + SpirvProgram((il: InitProgramLayout) ?=> layout(il), dispatch, compiled) From 03fa272b6b18c540b66e0b37bf8198a1b480f01b Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Sun, 24 Aug 2025 12:16:34 +0200 Subject: [PATCH 28/59] executing, not workin^g --- .../computenode/cyfra/spirv/SpirvTypes.scala | 1 + .../cyfra/runtime/ExecutionHandler.scala | 26 +++--- .../cyfra/runtime/PendingExecution.scala | 89 +++++++++++++++++++ .../cyfra/runtime/VkAllocation.scala | 50 ++++++----- .../computenode/cyfra/runtime/VkBinding.scala | 69 ++++++++++++++ .../computenode/cyfra/runtime/VkBuffer.scala | 23 ----- .../computenode/cyfra/runtime/VkUniform.scala | 21 ----- .../cyfra/vulkan/command/CommandPool.scala | 37 +++----- .../cyfra/vulkan/command/Semaphore.scala | 2 +- .../cyfra/vulkan/memory/Buffer.scala | 21 ++++- .../cyfra/vulkan/util/VulkanObject.scala | 1 + 11 files changed, 226 insertions(+), 114 deletions(-) create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala delete mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala delete mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala index 9fe1b386..7adeb972 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala @@ -54,6 +54,7 @@ private[cyfra] object SpirvTypes: case LGBooleanTag => 4 case v if v <:< LVecTag => vecSize(v) * typeStride(v.typeArgs.head) + case _ => 4 def typeStride(tag: Tag[?]): Int = typeStride(tag.tag) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index 782b2a85..a20efbbb 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -51,7 +51,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte .zip(layout) .map: case (set, bindings) => - set.update(bindings.map(x => VkAllocation.getUnderlying(x.binding))) + set.update(bindings.map(x => VkAllocation.getUnderlying(x.binding).buffer)) set val dispatches: Seq[Dispatch] = shaderCalls @@ -67,19 +67,15 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte else (steps.appended(step), dirty ++ bindings) val commandBuffer = recordCommandBuffer(executeSteps) - pushStack: stack => - val pCommandBuffer = stack.callocPointer(1).put(0, commandBuffer) - val submitInfo = VkSubmitInfo - .calloc(stack) - .sType$Default() - .pCommandBuffers(pCommandBuffer) - - val fence = new Fence() - timed("Vulkan render command"): - check(vkQueueSubmit(commandPool.queue.get, submitInfo, fence.get), "Failed to submit command buffer to queue") - fence.block().destroy() - commandPool.freeCommandBuffer(commandBuffer) - descriptorSets.flatten.foreach(dsManager.free) + val cleanup = () => + descriptorSets.flatten.foreach(dsManager.free) + commandPool.freeCommandBuffer(commandBuffer) + + val externalBindings = (summon[LayoutBinding[EL]].toBindings(layout) ++ summon[LayoutBinding[RL]].toBindings(result)) + .map(VkAllocation.getUnderlying) + val deps = externalBindings.flatMap(_.execution.fold(Seq(_), _.toSeq)) + val pe = new PendingExecution(commandBuffer, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, deps, cleanup) + externalBindings.foreach(_.execution = Left(pe)) result private def interpret[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding]( @@ -228,7 +224,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte dispatch match case Direct(x, y, z) => vkCmdDispatch(commandBuffer, x, y, z) - case Indirect(buffer, offset) => vkCmdDispatchIndirect(commandBuffer, VkAllocation.getUnderlying(buffer).get, offset) + case Indirect(buffer, offset) => vkCmdDispatchIndirect(commandBuffer, VkAllocation.getUnderlying(buffer).buffer.get, offset) check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") commandBuffer diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala new file mode 100644 index 00000000..b213c0c9 --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala @@ -0,0 +1,89 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.vulkan.command.{CommandPool, Fence, Semaphore} +import io.computenode.cyfra.vulkan.core.{Device, Queue} +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObject +import org.lwjgl.vulkan.VK13.{VK_PIPELINE_STAGE_2_COPY_BIT, vkQueueSubmit2} +import org.lwjgl.vulkan.{VkCommandBuffer, VkCommandBufferSubmitInfo, VkSemaphoreSubmitInfo, VkSubmitInfo2} + +import scala.collection.mutable + +class PendingExecution(protected val handle: VkCommandBuffer, val waitStage: Long, val dependencies: Seq[PendingExecution], cleanup: () => Unit)( + using Device, +) extends VulkanObject[VkCommandBuffer]: + private val semaphore: Semaphore = Semaphore(waitStage) + private var fence: Option[Fence] = None + + override protected def close(): Unit = cleanup() + + private def setFence(otherFence: Fence): Unit = + if fence.isDefined then return + fence = Some(otherFence) + dependencies.foreach(_.setFence(otherFence)) + + private def gatherForSubmission: Seq[((VkCommandBuffer, Semaphore), Set[Semaphore])] = { + if fence.isDefined then return Seq.empty + val mySubmission = ((handle, semaphore), dependencies.map(_.semaphore).toSet) + dependencies.flatMap(_.gatherForSubmission).appended(mySubmission) + } + + def block(): Unit = + fence match + case Some(f) => f.block() + case None => throw new IllegalStateException("No fence set for this execution") + +object PendingExecution: + def executeAll(executions: Seq[PendingExecution], queue: Queue)(using Device): Fence = pushStack: stack => + val gathered = executions.flatMap(_.gatherForSubmission).toSet.groupMap(_._2)(_._1).toSeq + + val submitInfos = VkSubmitInfo2.calloc(gathered.size, stack) + gathered.foreach: (semaphores, executions) => + val pCommandBuffersSI = VkCommandBufferSubmitInfo.calloc(executions.size, stack) + val signalSemaphoreSI = VkSemaphoreSubmitInfo.calloc(executions.size, stack) + executions.foreach: (cb, s) => + pCommandBuffersSI + .get() + .sType$Default() + .commandBuffer(cb) + .deviceMask(0) + signalSemaphoreSI + .get() + .sType$Default() + .semaphore(s.get) + .stageMask(s.stage) + + pCommandBuffersSI.flip() + signalSemaphoreSI.flip() + + val waitSemaphoreSI = VkSemaphoreSubmitInfo.calloc(semaphores.size, stack) + semaphores.foreach: s => + waitSemaphoreSI + .get() + .sType$Default() + .semaphore(s.get) + .stageMask(s.stage) + + waitSemaphoreSI.flip() + + submitInfos + .get() + .sType$Default() + .flags(0) + .pCommandBufferInfos(pCommandBuffersSI) + .pSignalSemaphoreInfos(signalSemaphoreSI) + .pWaitSemaphoreInfos(waitSemaphoreSI) + + submitInfos.flip() + + val fence = Fence() + executions.foreach(_.setFence(fence)) + check(vkQueueSubmit2(queue.get, submitInfos, fence.get), "Failed to submit command buffer to queue") + fence + + def cleanupAll(executions: Seq[PendingExecution]): Unit = + def cleanupRec(ex: PendingExecution): Unit = + if !ex.isAlive then return + ex.destroy() + ex.dependencies.foreach(cleanupRec) + executions.foreach(cleanupRec) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index a038ac7b..a851389e 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -14,37 +14,48 @@ import io.computenode.cyfra.vulkan.command.CommandPool import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} import io.computenode.cyfra.vulkan.util.Util.pushStack import io.computenode.cyfra.dsl.Value.Int32 +import io.computenode.cyfra.vulkan.core.Device import izumi.reflect.Tag import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil import org.lwjgl.vulkan.VK10 +import org.lwjgl.vulkan.VK13.VK_PIPELINE_STAGE_2_COPY_BIT import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT} import java.nio.ByteBuffer import scala.collection.mutable import scala.util.chaining.* -class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler)(using Allocator) extends Allocation: +class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler)(using Allocator, Device) extends Allocation: given VkAllocation = this extension (buffer: GBinding[?]) def read(bb: ByteBuffer, offset: Int = 0): Unit = val size = bb.remaining() - getUnderlying(buffer) match - case buffer: Buffer.HostBuffer => buffer.copyTo(bb, offset) - case buffer: Buffer.DeviceBuffer => + buffer match + case VkBinding(buffer: Buffer.HostBuffer) => buffer.copyTo(bb, offset) + case binding: VkBinding[?] => + binding.materialise(commandPool.queue) val stagingBuffer = getStagingBuffer(size) - Buffer.copyBuffer(buffer, stagingBuffer, offset, 0, size, commandPool) + Buffer.copyBuffer(binding.buffer, stagingBuffer, offset, 0, size, commandPool) stagingBuffer.copyTo(bb, 0) + case _ => throw new IllegalArgumentException(s"Tried to read from non-VkBinding $buffer") def write(bb: ByteBuffer, offset: Int = 0): Unit = val size = bb.remaining() - getUnderlying(buffer) match - case buffer: Buffer.HostBuffer => buffer.copyFrom(bb, offset) - case buffer: Buffer.DeviceBuffer => + buffer match + case VkBinding(buffer: Buffer.HostBuffer) => buffer.copyFrom(bb, offset) + case binding: VkBinding[?] => + binding.materialise(commandPool.queue) val stagingBuffer = getStagingBuffer(size) - stagingBuffer.copyFrom(bb, offset) - Buffer.copyBuffer(stagingBuffer, buffer, 0, offset, size, commandPool) + stagingBuffer.copyFrom(bb, 0) + val cb = Buffer.copyBufferCommandBuffer(stagingBuffer, binding.buffer, 0, offset, size, commandPool) + val cleanup = () => + commandPool.freeCommandBuffer(cb) + stagingBuffer.destroy() + val pe = new PendingExecution(cb, VK_PIPELINE_STAGE_2_COPY_BIT, binding.execution.fold(Seq(_), _.toSeq), cleanup) + binding.execution = Left(pe) + case _ => throw new IllegalArgumentException(s"Tried to write to non-VkBinding $buffer") extension (buffers: GBuffer.type) def apply[T <: Value: {Tag, FromExpr}](length: Int): GBuffer[T] = @@ -80,22 +91,13 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) private val bindings = mutable.Buffer[VkUniform[?] | VkBuffer[?]]() private[cyfra] def close(): Unit = - bindings.map(getUnderlying).foreach(_.destroy()) - stagingBuffer.foreach(_.destroy()) + bindings.map(getUnderlying).foreach(_.buffer.destroy()) - private var stagingBuffer: Option[Buffer.HostBuffer] = None private def getStagingBuffer(size: Int): Buffer.HostBuffer = - stagingBuffer match - case Some(buffer) if buffer.size >= size => buffer - case _ => - stagingBuffer.foreach(_.destroy()) - val newBuffer = Buffer.HostBuffer(size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT) - stagingBuffer = Some(newBuffer) - newBuffer + Buffer.HostBuffer(size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT) object VkAllocation: - private[runtime] def getUnderlying(buffer: GBinding[?]): Buffer = + private[runtime] def getUnderlying(buffer: GBinding[?]): VkBinding[?] = buffer match - case buffer: VkBuffer[?] => buffer.underlying - case uniform: VkUniform[?] => uniform.underlying - case _ => throw new IllegalArgumentException(s"Tried to get underlying of non-VkBinding $buffer") + case buffer: VkBinding[?] => buffer + case _ => throw new IllegalArgumentException(s"Tried to get underlying of non-VkBinding $buffer") diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala new file mode 100644 index 00000000..f83f39fb --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala @@ -0,0 +1,69 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.spirv.SpirvTypes.typeStride +import izumi.reflect.Tag +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer} +import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} +import io.computenode.cyfra.vulkan.core.Queue +import io.computenode.cyfra.vulkan.core.Device +import izumi.reflect.Tag +import io.computenode.cyfra.spirv.SpirvTypes.typeStride +import org.lwjgl.vulkan.VK10 +import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT} +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.GUniform +import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} +import izumi.reflect.Tag +import org.lwjgl.vulkan.VK10 +import org.lwjgl.vulkan.VK10.* + +import scala.collection.mutable + +sealed abstract class VkBinding[T <: Value: {Tag, FromExpr}](val buffer: Buffer): + val sizeOfT: Int = typeStride(summon[Tag[T]]) + + /** Holds either: + * 1. a single execution that writes to this buffer + * 1. multiple executions that read from this buffer + */ + var execution: Either[PendingExecution, mutable.Buffer[PendingExecution]] = Right(mutable.Buffer.empty) + + def materialise(queue: Queue)(using Device): Unit = execution match + case Left(exec) if exec.isAlive => + PendingExecution.executeAll(Seq(exec), queue) + exec.block() + PendingExecution.cleanupAll(Seq(exec)) + case _ => () + +object VkBinding: + def unapply(binding: GBinding[?]): Option[Buffer] = binding match + case b: VkBinding[?] => Some(b.buffer) + case _ => None + +class VkBuffer[T <: Value: {Tag, FromExpr}] private (val length: Int, underlying: Buffer) extends VkBinding(underlying) with GBuffer[T] + +object VkBuffer: + private final val Padding = 64 + private final val UsageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT + + def apply[T <: Value: {Tag, FromExpr}](length: Int)(using Allocator): VkBuffer[T] = + val sizeOfT = typeStride(summon[Tag[T]]) + val size = (length * sizeOfT + Padding - 1) / Padding * Padding + val buffer = new Buffer.DeviceBuffer(size, UsageFlags) + new VkBuffer[T](length, buffer) + +class VkUniform[T <: Value: {Tag, FromExpr}] private (underlying: Buffer) extends VkBinding[T](underlying) with GUniform[T] + +object VkUniform: + private final val UsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT + + def apply[T <: Value: {Tag, FromExpr}]()(using Allocator): VkUniform[T] = + val sizeOfT = typeStride(summon[Tag[T]]) + val buffer = new Buffer.DeviceBuffer(sizeOfT, UsageFlags) + new VkUniform[T](buffer) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala deleted file mode 100644 index cda73868..00000000 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala +++ /dev/null @@ -1,23 +0,0 @@ -package io.computenode.cyfra.runtime - -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Value.FromExpr -import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer} -import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} -import izumi.reflect.Tag -import io.computenode.cyfra.spirv.SpirvTypes.typeStride -import org.lwjgl.vulkan.VK10 -import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT} - -class VkBuffer[T <: Value: {Tag, FromExpr}] private (var length: Int, val underlying: Buffer) extends GBuffer[T]: - val sizeOfT: Int = typeStride(summon[Tag[T]]) - -object VkBuffer: - private final val Padding = 64 - private final val UsageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT - - def apply[T <: Value: {Tag, FromExpr}](length: Int)(using Allocator): VkBuffer[T] = - val sizeOfT = typeStride(summon[Tag[T]]) - val size = (length * sizeOfT + Padding - 1) / Padding * Padding - val buffer = new Buffer.DeviceBuffer(size, UsageFlags) - new VkBuffer[T](length, buffer) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala deleted file mode 100644 index f8c75da7..00000000 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala +++ /dev/null @@ -1,21 +0,0 @@ -package io.computenode.cyfra.runtime - -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Value.FromExpr -import io.computenode.cyfra.dsl.binding.GUniform -import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} -import izumi.reflect.Tag -import org.lwjgl.vulkan.VK10 -import org.lwjgl.vulkan.VK10.* - -class VkUniform[T <: Value: {Tag, FromExpr}] private (val underlying: Buffer) extends GUniform[T]: - val sizeOfT: Int = 4 - -object VkUniform: - private final val UsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | - VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT - - def apply[T <: Value: {Tag, FromExpr}]()(using Allocator): VkUniform[T] = - val sizeOfT = 4 // typeStride(summon[Tag[T]]) - val buffer = new Buffer.DeviceBuffer(sizeOfT, UsageFlags) - new VkUniform[T](buffer) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala index 3db65668..11d21e1a 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala @@ -39,35 +39,18 @@ private[cyfra] abstract class CommandPool private (flags: Int, val queue: Queue) check(vkAllocateCommandBuffers(device.get, allocateInfo, pointerBuffer), "Failed to allocate command buffers") 0 until n map (i => pointerBuffer.get(i)) map (new VkCommandBuffer(_, device.get)) - def executeCommand(block: VkCommandBuffer => Unit): Unit = - val commandBuffer = beginSingleTimeCommands() - block(commandBuffer) - endSingleTimeCommands(commandBuffer).block().destroy() - freeCommandBuffer(commandBuffer) - - private def beginSingleTimeCommands(): VkCommandBuffer = - pushStack: stack => - val commandBuffer = this.createCommandBuffer() - - val beginInfo = VkCommandBufferBeginInfo - .calloc(stack) - .sType$Default() - .flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) + def recordSingleTimeCommand(block: VkCommandBuffer => Unit): VkCommandBuffer = pushStack: stack => + val commandBuffer = createCommandBuffer() - check(vkBeginCommandBuffer(commandBuffer, beginInfo), "Failed to begin single time command buffer") - commandBuffer + val beginInfo = VkCommandBufferBeginInfo + .calloc(stack) + .sType$Default() + .flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) - private def endSingleTimeCommands(commandBuffer: VkCommandBuffer): Fence = - pushStack: stack => - vkEndCommandBuffer(commandBuffer) - val pointerBuffer = stack.callocPointer(1).put(0, commandBuffer) - val submitInfo = VkSubmitInfo - .calloc(stack) - .sType$Default() - .pCommandBuffers(pointerBuffer) - val fence = Fence() - check(vkQueueSubmit(queue.get, submitInfo, fence.get), "Failed to submit single time command buffer") - fence + check(vkBeginCommandBuffer(commandBuffer, beginInfo), "Failed to begin single time command buffer") + block(commandBuffer) + check(vkEndCommandBuffer(commandBuffer), "Failed to end single time command buffer") + commandBuffer def freeCommandBuffer(commandBuffer: VkCommandBuffer*): Unit = pushStack: stack => diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala index 04034b1c..88386710 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala @@ -9,7 +9,7 @@ import org.lwjgl.vulkan.VkSemaphoreCreateInfo /** @author * MarconZet Created 30.10.2019 */ -private[cyfra] class Semaphore(using device: Device) extends VulkanObjectHandle: +private[cyfra] class Semaphore(val stage: Long)(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => val semaphoreCreateInfo = VkSemaphoreCreateInfo .calloc(stack) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala index 963aa1cd..1f677f04 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala @@ -1,13 +1,14 @@ package io.computenode.cyfra.vulkan.memory import io.computenode.cyfra.vulkan.command.{CommandPool, Fence} +import io.computenode.cyfra.vulkan.core.Device import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.system.MemoryUtil.* import org.lwjgl.util.vma.Vma.* import org.lwjgl.util.vma.VmaAllocationCreateInfo import org.lwjgl.vulkan.VK10.* -import org.lwjgl.vulkan.{VkBufferCopy, VkBufferCreateInfo} +import org.lwjgl.vulkan.{VkBufferCopy, VkBufferCreateInfo, VkCommandBuffer, VkSubmitInfo} import java.nio.ByteBuffer @@ -61,8 +62,22 @@ object Buffer: def copyFrom(src: ByteBuffer, dstOffset: Int): Unit = pushStack: stack => vmaCopyMemoryToAllocation(allocator.get, src, allocation, dstOffset) - def copyBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool): Unit = - commandPool.executeCommand: commandBuffer => + def copyBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool)(using Device): Unit = pushStack: + stack => + val cb = copyBufferCommandBuffer(src, dst, srcOffset, dstOffset, bytes, commandPool) + + val pCB = stack.callocPointer(1).put(0, cb) + val submitInfo = VkSubmitInfo + .calloc(stack) + .sType$Default() + .pCommandBuffers(pCB) + + val fence = Fence() + check(vkQueueSubmit(commandPool.queue.get, submitInfo, fence.get), "Failed to submit single time command buffer") + fence.block() + + def copyBufferCommandBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool): VkCommandBuffer = + commandPool.recordSingleTimeCommand: commandBuffer => pushStack: stack => val copyRegion = VkBufferCopy .calloc(1, stack) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala index 3ec34726..50d3baf7 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala @@ -6,6 +6,7 @@ package io.computenode.cyfra.vulkan.util private[cyfra] abstract class VulkanObject[T]: protected val handle: T private var alive: Boolean = true + def isAlive: Boolean = alive def get: T = if !alive then throw new IllegalStateException() From 046a823c03cf1768bc45d29014c6ed41f72d61b2 Mon Sep 17 00:00:00 2001 From: spamegg Date: Sun, 24 Aug 2025 17:27:08 +0300 Subject: [PATCH 29/59] add idle profiling --- .../e2e/interpreter/InterpreterTests.scala | 12 ++++++------ .../cyfra/interpreter/ReadWrite.scala | 3 ++- .../computenode/cyfra/interpreter/Record.scala | 18 ++++++++++-------- .../cyfra/interpreter/Simulate.scala | 11 ++++++++--- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala index ee3e08a9..0cef1d25 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/interpreter/InterpreterTests.scala @@ -7,7 +7,7 @@ import FromExpr.fromExpr, control.Scope import izumi.reflect.Tag class InterpreterE2eTest extends munit.FunSuite: - test("interpret should not stack overflow"): + test("interpret should not stack overflow".ignore): val fakeContext = SimContext(Map(), Map(), SimData()) val n: Int32 = 0 val pure = Pure(n) @@ -19,26 +19,26 @@ class InterpreterE2eTest extends munit.FunSuite: test("interpret mixed arithmetic, buffer reads/writes, uniform reads/writes, and when"): case class SimGBuffer[T <: Value: Tag: FromExpr]() extends GBuffer[T] val buffer = SimGBuffer[Int32]() - val array = (0 until 3).toArray[Result] + val array = Array[Result](0, 1, 2) case class SimGUniform[T <: Value: Tag: FromExpr]() extends GUniform[T] val uniform = SimGUniform[Int32]() val uniValue = 4 val data = SimData().addBuffer(buffer, array).addUniform(uniform, uniValue) - val startingRecords = Map(0 -> Record(), 1 -> Record(), 2 -> Record()) // running 3 invocations + val startingRecords = Records(0 until 3) // running 3 invocations val startingSc = SimContext(records = startingRecords, data = data) val a = ReadUniform(uniform) // 4 - val invocId = InvocationId + val invocId = InvocationId // 0,1,2 val readExpr = ReadBuffer(buffer, fromExpr(invocId)) // 0,1,2 val expr1 = Mul(fromExpr(a), fromExpr(readExpr)) // 4*0 = 0, 4*1 = 4, 4*2 = 8 val expr2 = Sum(fromExpr(a), fromExpr(expr1)) // 4+0 = 4, 4+4 = 8, 4+8 = 12 val expr3 = Mod(fromExpr(expr2), 5) // 4%5 = 4, 8%5 = 3, 12%5 = 2 - val cond1 = fromExpr(expr1) <= fromExpr(expr3) - val cond2 = Equal(fromExpr(expr3), fromExpr(readExpr)) + val cond1 = fromExpr(expr1) <= fromExpr(expr3) // 0 <= 4, 4 <= 3, 8 <= 2 + val cond2 = Equal(fromExpr(expr3), fromExpr(readExpr)) // 4 == 0, 3 == 1, 2 == 2 // invoc 0 enters when, invoc2 enters elseWhen, invoc1 enters otherwise val expr = WhenExpr( diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala index aacf6551..568873f1 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/ReadWrite.scala @@ -28,7 +28,8 @@ object CoalesceProfile: def apply(addresses: Seq[Int], profile: Profile): CoalesceProfile = val length = addresses.length val distinct = addresses.distinct.length == length - if !distinct then RaceCondition(profile) + if length == 0 then NotCoalesced(profile) + else if !distinct then RaceCondition(profile) else val (start, end) = (addresses.min, addresses.max) val coalesced = end - start + 1 == length diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala index 50f9e9b8..eb88e226 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Record.scala @@ -4,14 +4,11 @@ import io.computenode.cyfra.dsl.{*, given} import binding.{GBuffer, GUniform} type TreeId = Int +type IdleDuration = Int type Cache = Map[TreeId, Result] +type Idles = Map[TreeId, IdleDuration] -type InvocId = Int -type Records = Map[InvocId, Record] - -case class Idle(treeid: TreeId, length: Int) - -case class Record(cache: Cache = Map(), writes: List[Write] = Nil, reads: List[Read] = Nil, idles: List[Idle] = Nil): +case class Record(cache: Cache = Map(), writes: List[Write] = Nil, reads: List[Read] = Nil, idles: Idles = Map()): def addRead(read: Read): Record = read match case ReadBuf(_, _, _, _) => copy(reads = read :: reads) case ReadUni(_, _, _) => copy(reads = read :: reads) @@ -21,12 +18,15 @@ case class Record(cache: Cache = Map(), writes: List[Write] = Nil, reads: List[R case WriteUni(_, _) => copy(writes = write :: writes) def addResult(treeid: TreeId, res: Result) = copy(cache = cache.updated(treeid, res)) + def updateIdles(treeid: TreeId) = copy(idles = idles.updated(treeid, idles.getOrElse(treeid, 0) + 1)) - def addIdle(treeid: TreeId, length: Int) = copy(idles = Idle(treeid, length) :: idles) +type InvocId = Int +type Records = Map[InvocId, Record] -extension (records: Records) +object Records: def apply(invocIds: Seq[InvocId]): Records = invocIds.map(invocId => invocId -> Record()).toMap +extension (records: Records) def updateResults(treeid: TreeId, results: Results): Records = records.map: (invocId, record) => results.get(invocId) match @@ -38,3 +38,5 @@ extension (records: Records) writes.get(invocId) match case Some(write) => invocId -> record.addWrite(write) case None => invocId -> record + + def updateIdles(rootTreeId: TreeId) = records.view.mapValues(_.updateIdles(rootTreeId)).toMap diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala index 2ee72399..baf60707 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala @@ -144,7 +144,7 @@ object Simulate: finishedRecords: Records, pendingRecords: Records, sc: SimContext, - ): SimContext = + )(using rootTreeId: TreeId): SimContext = if pendingRecords.isEmpty then sc else // scopes are not included in caches, they have to be simulated from scratch. @@ -154,7 +154,11 @@ object Simulate: val SimContext(boolResults, boolRecords, boolData, boolProfs) = sim(when, pendingSc) // Split invocations that enter this branch. - val (enterRecords, newPendingRecords) = boolRecords.partition((invocId, _) => boolResults(invocId).asInstanceOf[Boolean]) + val (enterRecords, pendingRecords1) = boolRecords.partition((invocId, _) => boolResults(invocId).asInstanceOf[Boolean]) + + // Finished records and still pending records will idle. + val newFinishedRecords = finishedRecords.updateIdles(rootTreeId) + val newPendingRecords = pendingRecords1.updateIdles(rootTreeId) // Only those invocs that enter the branch will have their records updated with thenCode result. val enterSc = SimContext(Map(), enterRecords, boolData, boolProfs) @@ -181,13 +185,14 @@ object Simulate: private def simWhen(e: WhenExpr[?], sc: SimContext): SimContext = e match case WhenExpr(when, thenCode, otherConds, otherCaseCodes, otherwise) => - whenHelper(when.tree, thenCode, otherConds, otherCaseCodes, otherwise, Map(), Map(), sc.records, sc) + whenHelper(when.tree, thenCode, otherConds, otherCaseCodes, otherwise, Map(), Map(), sc.records, sc)(using e.treeid) private def simReadBuffer(e: ReadBuffer[?], sc: SimContext): SimContext = val SimContext(_, records, data, profs) = sc e match case ReadBuffer(buffer, index) => val indices = records.view.mapValues(_.cache(index.tree.treeid).asInstanceOf[Int]).toMap + // println(s"$e: $indices") val readValues = indices.view.mapValues(i => data.lookup(buffer, i)).toMap val newRecords = records.map: (invocId, record) => invocId -> record.addRead(ReadBuf(e.treeid, buffer, indices(invocId), readValues(invocId))) From 74d8d8b29fce13cb1a39aa0629c1a8de63df4154 Mon Sep 17 00:00:00 2001 From: Szymon Date: Sun, 24 Aug 2025 23:23:36 +0200 Subject: [PATCH 30/59] Works! --- .../io/computenode/cyfra/spirv/Context.scala | 4 +- .../cyfra/spirv/compilers/DSLCompiler.scala | 16 ++- .../spirv/compilers/ExpressionCompiler.scala | 12 +- .../cyfra/spirv/compilers/GIOCompiler.scala | 124 ++++++++++++++---- .../compilers/SpirvProgramCompiler.scala | 27 ++-- .../computenode/cyfra/core/Allocation.scala | 6 +- .../io/computenode/cyfra/core/GProgram.scala | 8 +- .../cyfra/core/binding/UniformRef.scala | 4 +- .../cyfra/core/layout/LayoutStruct.scala | 24 ++-- .../cyfra/dsl/binding/GBinding.scala | 6 +- .../cyfra/dsl/binding/ReadUniform.scala | 3 +- .../cyfra/dsl/binding/WriteUniform.scala | 4 +- .../cyfra/dsl/struct/GStruct.scala | 4 +- .../cyfra/dsl/struct/GStructSchema.scala | 4 +- .../cyfra/samples/TestingStuff.scala | 50 ++++++- .../cyfra/runtime/ExecutionHandler.scala | 22 ++-- .../cyfra/runtime/VkAllocation.scala | 10 +- .../cyfra/runtime/VkCyfraRuntime.scala | 25 +++- .../computenode/cyfra/runtime/VkShader.scala | 11 +- .../computenode/cyfra/runtime/VkUniform.scala | 5 +- .../cyfra/spirvtools/SpirvCross.scala | 2 +- .../cyfra/spirvtools/SpirvDisassembler.scala | 2 +- .../cyfra/spirvtools/SpirvOptimizer.scala | 2 +- .../cyfra/spirvtools/SpirvTool.scala | 19 ++- .../cyfra/spirvtools/SpirvToolsRunner.scala | 2 +- 25 files changed, 270 insertions(+), 126 deletions(-) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala index 35b39a46..8e8f5f96 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala @@ -1,6 +1,6 @@ package io.computenode.cyfra.spirv -import io.computenode.cyfra.dsl.binding.GBuffer +import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} import io.computenode.cyfra.dsl.macros.FnCall.FnIdentifier import io.computenode.cyfra.spirv.SpirvConstants.HEADER_REFS_TOP import io.computenode.cyfra.spirv.compilers.FunctionCompiler.SprivFunction @@ -17,7 +17,7 @@ private[cyfra] case class Context( voidTypeRef: Int = -1, voidFuncTypeRef: Int = -1, workerIndexRef: Int = -1, - uniformVarRefs: Map[Int, Int] = Map.empty, + uniformVarRefs: Map[GUniform[?], Int] = Map.empty, bindingToStructType: Map[Int, Int] = Map.empty, constRefs: Map[(Tag[?], Any), Int] = Map(), exprRefs: Map[Int, Int] = Map(), diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala index f15c9d54..09dd9999 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala @@ -74,10 +74,12 @@ private[cyfra] object DSLCompiler: val allTypes = (typesInCode ::: bindings.map(_.tag)).distinct def scalarTypes = allTypes.filter(_.tag <:< summon[Tag[Scalar]].tag) val (typeDefs, typedContext) = defineScalarTypes(scalarTypes, Context.initialContext) - val (buffers, uniforms) = bindings.partition: - case _: GBuffer[?] => true - case _: GUniform[?] => false - .asInstanceOf[(List[GBinding[?]], List[GUniform[?]])] + val (buffersWithIndices, uniformsWithIndices) = bindings.zipWithIndex.partition: + case (_: GBuffer[?], _) => true + case (_: GUniform[?], _) => false + .asInstanceOf[(List[(GBuffer[?], Int)], List[(GUniform[?], Int)])] + val uniforms = uniformsWithIndices.map(_._1) + val buffers = buffersWithIndices.map(_._1) val uniformSchemas = uniforms.map(_.schema) val structsInCode = (allExprs.collect { @@ -86,9 +88,9 @@ private[cyfra] object DSLCompiler: } ::: uniformSchemas).distinct val (structDefs, structCtx) = defineStructTypes(structsInCode, typedContext) val structNames = getStructNames(structsInCode, structCtx) - val (decorations, uniformDefs, uniformContext) = initAndDecorateBuffers(buffers, structCtx) - val (uniformStructDecorations, uniformStructInsns, uniformStructContext) = createAndInitUniformBlocks(uniformSchemaIns, uniformContext) - val blockNames = getBlockNames(uniformContext, uniformSchemaIns) + val (decorations, uniformDefs, uniformContext) = initAndDecorateBuffers(buffersWithIndices, structCtx) + val (uniformStructDecorations, uniformStructInsns, uniformStructContext) = createAndInitUniformBlocks(uniformsWithIndices, uniformContext) + val blockNames = getBlockNames(uniformContext, uniforms) val (inputDefs, inputContext) = createInvocationId(uniformStructContext) val (constDefs, constCtx) = defineConstants(allExprs, inputContext) val (varDefs, varCtx) = defineVarNames(constCtx) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala index 7e7cb849..c1459fcf 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala @@ -106,11 +106,11 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (c.treeid -> constRef)) (List(), updatedContext) - case w @ WorkerIndex => + case w @ InvocationId => (Nil, ctx.copy(exprRefs = ctx.exprRefs + (w.treeid -> ctx.workerIndexRef))) - case d @ Binding(id) => - (Nil, ctx.copy(exprRefs = ctx.exprRefs + (d.treeid -> ctx.uniformVarRefs(id)))) + case d @ ReadUniform(u) => + (Nil, ctx.copy(exprRefs = ctx.exprRefs + (d.treeid -> ctx.uniformVarRefs(u)))) case c: ConvertExpression[?, ?] => compileConvertExpression(c, ctx) @@ -306,6 +306,7 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> (ctx.nextResultId + 1)), nextResultId = ctx.nextResultId + 2) (instructions, updatedContext) + case when: WhenExpr[?] => compileWhen(when, ctx) @@ -327,14 +328,14 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (cs.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (insns, updatedContext) - case gf @ GetField(binding @ Binding(bindingId), fieldIndex) => + case gf @ GetField(binding @ ReadUniform(uf), fieldIndex) => val insns: List[Instruction] = List( Instruction( Op.OpAccessChain, List( ResultRef(ctx.uniformPointerMap(ctx.valueTypeMap(gf.tag.tag))), ResultRef(ctx.nextResultId), - ResultRef(ctx.uniformVarRefs(bindingId)), + ResultRef(ctx.uniformVarRefs(uf)), ResultRef(ctx.constRefs((Int32Tag, gf.fieldIndex))), ), ), @@ -342,6 +343,7 @@ private[cyfra] object ExpressionCompiler: ) val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> (ctx.nextResultId + 1)), nextResultId = ctx.nextResultId + 2) (insns, updatedContext) + case gf: GetField[?, ?] => val insns: List[Instruction] = List( Instruction( diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala index c64b9cae..a4a55212 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala @@ -5,7 +5,7 @@ import io.computenode.cyfra.spirv.Context import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.dsl.binding.* import io.computenode.cyfra.dsl.gio.GIO.CurrentRepeatIndex -import io.computenode.cyfra.spirv.SpirvTypes.{Int32Tag, LInt32Tag} +import io.computenode.cyfra.spirv.SpirvTypes.{GBooleanTag, Int32Tag, LInt32Tag} object GIOCompiler: @@ -17,37 +17,113 @@ object GIOCompiler: (acc ::: insts, updatedCtx) case WriteBuffer(buffer, index, value) => + val (valueInsts, ctxWithValue) = ExpressionCompiler.compileBlock(value.tree, ctx) + val (indexInsts, ctxWithIndex) = ExpressionCompiler.compileBlock(index.tree, ctxWithValue) + val insns = List(Instruction( Op.OpAccessChain, List( - ResultRef(ctx.uniformPointerMap(ctx.valueTypeMap(buffer.tag.tag))), - ResultRef(ctx.nextResultId), - ResultRef(ctx.bufferBlocks(buffer).blockVarRef), - ResultRef(ctx.constRefs((Int32Tag, 0))), - ResultRef(ctx.workerIndexRef), + ResultRef(ctxWithIndex.uniformPointerMap(ctxWithIndex.valueTypeMap(buffer.tag.tag))), + ResultRef(ctxWithIndex.nextResultId), + ResultRef(ctxWithIndex.bufferBlocks(buffer).blockVarRef), + ResultRef(ctxWithIndex.constRefs((Int32Tag, 0))), + ResultRef(ctxWithIndex.exprRefs(index.tree.treeid)), ), ), - Instruction(Op.OpStore, List(ResultRef(ctx.nextResultId), ResultRef(ctx.exprRefs(value.tree.treeid)))) + Instruction(Op.OpStore, List(ResultRef(ctxWithIndex.nextResultId), ResultRef(ctxWithIndex.exprRefs(value.tree.treeid)))) ) - val updatedCtx = ctx.copy(nextResultId = ctx.nextResultId + 1) - (acc ::: insns, updatedCtx) - + val updatedCtx = ctxWithIndex.copy(nextResultId = ctxWithIndex.nextResultId + 1) + (acc ::: indexInsts ::: valueInsts ::: insns, updatedCtx) + case GIO.Repeat(n, f) => + + // Compile 'n' first (so we can use its id in the comparison) val (nInsts, ctxWithN) = ExpressionCompiler.compileBlock(n.tree, ctx) - val loopHeaderId = ctxWithN.nextResultId - val loopMergeId = ctxWithN.nextResultId + 1 - val loopContinueId = ctxWithN.nextResultId + 2 - val counterVarId = ctxWithN.nextResultId + 3 - val ctxWithCounter = ctxWithN.copy(exprRefs = ctxWithN.exprRefs + (CurrentRepeatIndex.treeid -> counterVarId), nextResultId = ctxWithN.nextResultId + 4) - val counterInit = Instruction(Op.OpVariable, List(ResultRef(ctxWithCounter.constRefs((Int32Tag, 0))), ResultRef(counterVarId), StorageClass.Function)) - val counterStore = Instruction(Op.OpStore, List(ResultRef(counterVarId), ResultRef(ctxWithCounter.constRefs((Int32Tag, 0))))) - val (body, afterBodyCtx) = compileGio(f, ctxWithCounter) - // todo - ??? - - - - + + // Types and constants + val intTy = ctxWithN.valueTypeMap(Int32Tag.tag) + val boolTy = ctxWithN.valueTypeMap(GBooleanTag.tag) + val zeroId = ctxWithN.constRefs((Int32Tag, 0)) + val oneId = ctxWithN.constRefs((Int32Tag, 1)) + val nId = ctxWithN.exprRefs(n.tree.treeid) + + // Reserve ids for blocks and results + val baseId = ctxWithN.nextResultId + val preHeaderId = baseId + val headerId = baseId + 1 + val bodyId = baseId + 2 + val continueId = baseId + 3 + val mergeId = baseId + 4 + val phiId = baseId + 5 + val cmpId = baseId + 6 + val addId = baseId + 7 + + // Bind CurrentRepeatIndex to the phi result for body compilation + val bodyCtx = ctxWithN.copy( + nextResultId = baseId + 8, + exprRefs = ctxWithN.exprRefs + (CurrentRepeatIndex.treeid -> phiId) + ) + val (bodyInsts, ctxAfterBody) = compileGio(f, bodyCtx) + + // Preheader: close current block and jump to header through a dedicated block + val preheader = List( + Instruction(Op.OpBranch, List(ResultRef(preHeaderId))), + Instruction(Op.OpLabel, List(ResultRef(preHeaderId))), + Instruction(Op.OpBranch, List(ResultRef(headerId))) + ) + + // Header: OpPhi first, then compute condition, then OpLoopMerge and the terminating branch + val header = List( + Instruction(Op.OpLabel, List(ResultRef(headerId))), + // OpPhi must be first in the block + Instruction( + Op.OpPhi, + List( + ResultRef(intTy), ResultRef(phiId), + ResultRef(zeroId), ResultRef(preHeaderId), + ResultRef(addId), ResultRef(continueId) + ) + ), + // cmp = (counter < n) + Instruction( + Op.OpSLessThan, + List(ResultRef(boolTy), ResultRef(cmpId), ResultRef(phiId), ResultRef(nId)) + ), + // OpLoopMerge must be the second-to-last instruction, before the terminating branch + Instruction(Op.OpLoopMerge, List(ResultRef(mergeId), ResultRef(continueId), LoopControlMask.MaskNone)), + Instruction(Op.OpBranchConditional, List(ResultRef(cmpId), ResultRef(bodyId), ResultRef(mergeId))) + ) + + val bodyBlk = List( + Instruction(Op.OpLabel, List(ResultRef(bodyId))) + ) ::: bodyInsts ::: List( + Instruction(Op.OpBranch, List(ResultRef(continueId))) + ) + + val contBlk = List( + Instruction(Op.OpLabel, List(ResultRef(continueId))), + Instruction( + Op.OpIAdd, + List(ResultRef(intTy), ResultRef(addId), ResultRef(phiId), ResultRef(oneId)) + ), + Instruction(Op.OpBranch, List(ResultRef(headerId))) + ) + + val mergeBlk = List( + Instruction(Op.OpLabel, List(ResultRef(mergeId))) + ) + + val finalNextId = math.max(ctxAfterBody.nextResultId, addId + 1) + val finalCtx = ctxAfterBody.copy( + nextResultId = finalNextId, + exprRefs = ctxAfterBody.exprRefs - CurrentRepeatIndex.treeid + ) + + (acc ::: nInsts ::: preheader ::: header ::: bodyBlk ::: contBlk ::: mergeBlk, finalCtx) + + + + \ No newline at end of file diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index 73ebf1bf..997c93b2 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -4,7 +4,7 @@ import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.dsl.Expression.{Const, E} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.* -import io.computenode.cyfra.dsl.binding.GBuffer +import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.{GStructConstructor, GStructSchema} import io.computenode.cyfra.spirv.Context @@ -122,15 +122,15 @@ private[cyfra] object SpirvProgramCompiler: ), ) (definitionInstructions, context.copy(nextResultId = context.nextResultId + 3)) - def initAndDecorateBuffers(buffers: List[GBuffer[?]], context: Context): (List[Words], List[Words], Context) = + def initAndDecorateBuffers(buffers: List[(GBuffer[?], Int)], context: Context): (List[Words], List[Words], Context) = val (blockDecor, blockDef, inCtx) = createAndInitBlocks(buffers, context) val (voidsDef, voidCtx) = defineVoids(inCtx) (blockDecor, voidsDef ::: blockDef, voidCtx) - def createAndInitBlocks(blocks: List[GBuffer[?]], context: Context): (List[Words], List[Words], Context) = - val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { case ((decAcc, insnAcc, ctx), buff) => + def createAndInitBlocks(blocks: List[(GBuffer[?], Int)], context: Context): (List[Words], List[Words], Context) = + val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { case ((decAcc, insnAcc, ctx), (buff, binding)) => val tpe = buff.tag - val block = ArrayBufferBlock(ctx.nextResultId, ctx.nextResultId + 1, ctx.nextResultId + 2, ctx.nextResultId + 3, ctx.nextBinding) + val block = ArrayBufferBlock(ctx.nextResultId, ctx.nextResultId + 1, ctx.nextResultId + 2, ctx.nextResultId + 3, binding) val decorationInstructions = List[Words]( Instruction(Op.OpDecorate, List(ResultRef(block.memberArrayTypeRef), Decoration.ArrayStride, IntWord(typeStride(tpe)))), // OpDecorate %_runtimearr_X ArrayStride [typeStride(type)] @@ -152,12 +152,12 @@ private[cyfra] object SpirvProgramCompiler: ( decAcc ::: decorationInstructions, insnAcc ::: definitionInstructions, - contextWithBlock.copy(nextResultId = contextWithBlock.nextResultId + 5, nextBinding = contextWithBlock.nextBinding + 1), + contextWithBlock.copy(nextResultId = contextWithBlock.nextResultId + 5), ) } (decoration, definition, newContext) - def getBlockNames(context: Context, uniformSchemas: List[GStructSchema[?]]): List[Words] = + def getBlockNames(context: Context, uniformSchemas: List[GUniform[?]]): List[Words] = def namesForBlock(block: ArrayBufferBlock, tpe: String): List[Words] = Instruction(Op.OpName, List(ResultRef(block.structTypeRef), Text(s"Buffer$tpe"))) :: Instruction(Op.OpName, List(ResultRef(block.blockVarRef), Text(s"data$tpe"))) :: Nil @@ -174,10 +174,10 @@ private[cyfra] object SpirvProgramCompiler: typeStride(t) .sum - def createAndInitUniformBlocks(schemas: List[GStructSchema[?]], ctx: Context): (List[Words], List[Words], Context) = - schemas.foldLeft((List.empty[Words], List.empty[Words], ctx)) { case ((decorationsAcc, definitionsAcc, currentCtx), schema) => + def createAndInitUniformBlocks(schemas: List[(GUniform[?], Int)], ctx: Context): (List[Words], List[Words], Context) = + schemas.foldLeft((List.empty[Words], List.empty[Words], ctx)) { case ((decorationsAcc, definitionsAcc, currentCtx), (uniform, binding)) => + val schema = uniform.schema val uniformStructTypeRef = currentCtx.valueTypeMap(schema.structTag.tag) - val currentBinding = currentCtx.nextBinding val (offsetDecorations, _) = schema.fields.zipWithIndex.foldLeft[(List[Words], Int)](List.empty[Words], 0): case ((acc, offset), ((name, fromExpr, tag), idx)) => @@ -199,16 +199,15 @@ private[cyfra] object SpirvProgramCompiler: val uniformVar = Instruction(Op.OpVariable, List(ResultRef(uniformPointerUniformRef), ResultRef(uniformVarRef), StorageClass.Uniform)) val uniformDecorateDescriptorSet = Instruction(Op.OpDecorate, List(ResultRef(uniformVarRef), Decoration.DescriptorSet, IntWord(0))) - val uniformDecorateBinding = Instruction(Op.OpDecorate, List(ResultRef(uniformVarRef), Decoration.Binding, IntWord(currentBinding))) + val uniformDecorateBinding = Instruction(Op.OpDecorate, List(ResultRef(uniformVarRef), Decoration.Binding, IntWord(binding))) val newDecorations = decorationsAcc ::: offsetDecorations ::: List(uniformDecorateDescriptorSet, uniformDecorateBinding, uniformBlockDecoration) val newDefinitions = definitionsAcc ::: List(uniformPointerUniform, uniformVar) val newCtx = currentCtx.copy( nextResultId = currentCtx.nextResultId + 2, - nextBinding = currentCtx.nextBinding + 1, - uniformVarRefs = currentCtx.uniformVarRefs + (currentBinding -> uniformVarRef), + uniformVarRefs = currentCtx.uniformVarRefs + (uniform -> uniformVarRef), uniformPointerMap = currentCtx.uniformPointerMap + (uniformStructTypeRef -> uniformPointerUniformRef), - bindingToStructType = currentCtx.bindingToStructType + (currentBinding -> uniformStructTypeRef) + bindingToStructType = currentCtx.bindingToStructType + (binding -> uniformStructTypeRef) ) (newDecorations, newDefinitions, newCtx) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala index bdc1d5a7..65b5e367 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala @@ -4,7 +4,7 @@ import io.computenode.cyfra.core.layout.{Layout, LayoutBinding} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} -import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import izumi.reflect.Tag import java.nio.ByteBuffer @@ -24,6 +24,6 @@ trait Allocation: def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] extension (buffers: GUniform.type) - def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GUniform[T] + def apply[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}](buff: ByteBuffer): GUniform[T] - def apply[T <: Value: {Tag, FromExpr}](): GUniform[T] + def apply[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}](): GUniform[T] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala index d1a43226..f1cef442 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala @@ -8,7 +8,7 @@ import GProgram.* import io.computenode.cyfra.dsl.{Expression, Value} import io.computenode.cyfra.dsl.Value.{FromExpr, GBoolean, Int32} import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} -import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import io.computenode.cyfra.dsl.struct.GStruct.Empty import izumi.reflect.Tag @@ -34,7 +34,7 @@ object GProgram: private[cyfra] class BufferLengthSpec[T <: Value: {Tag, FromExpr}](val length: Int) extends GBuffer[T]: private[cyfra] def materialise()(using Allocation): GBuffer[T] = GBuffer.apply[T](length) - private[cyfra] class DynamicUniform[T <: GStruct[T]: {Tag, FromExpr}]() extends GUniform[T] + private[cyfra] class DynamicUniform[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}]() extends GUniform[T] trait InitProgramLayout: extension (_buffers: GBuffer.type) @@ -42,6 +42,6 @@ object GProgram: BufferLengthSpec[T](length) extension (_uniforms: GUniform.type) - def apply[T <: GStruct[T]: {Tag, FromExpr}](): GUniform[T] = + def apply[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}](): GUniform[T] = DynamicUniform[T]() - def apply[T <: GStruct[T]: {Tag, FromExpr}](value: T): GUniform[T] + def apply[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}](value: T): GUniform[T] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/UniformRef.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/UniformRef.scala index d7c3b308..8fc86c2f 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/UniformRef.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/binding/UniformRef.scala @@ -3,8 +3,8 @@ package io.computenode.cyfra.core.binding import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} -import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import izumi.reflect.Tag import izumi.reflect.macrortti.LightTypeTag -case class UniformRef[T <: Value: {Tag, FromExpr}](layoutOffset: Int, valueTag: Tag[T]) extends GUniform[T] +case class UniformRef[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}](layoutOffset: Int, valueTag: Tag[T]) extends GUniform[T] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala index 3d79b409..0703bbbb 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala @@ -4,6 +4,7 @@ import io.computenode.cyfra.core.binding.{BufferRef, UniformRef} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import izumi.reflect.Tag import izumi.reflect.macrortti.LightTypeTag @@ -55,17 +56,18 @@ object LayoutStruct: val buffers = typeGivens.zipWithIndex.map: case ((ftype, tpe, tag, fromExpr), i) => - tpe match - case '[type t <: Value; t] => - ftype match - case '[type tg <: GBuffer[?]; tg] => - '{ - BufferRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }) - } - case '[type tg <: GUniform[?]; tg] => - '{ - UniformRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }) - } + (tpe, ftype) match + case ('[type t <: Value; t], '[type tg <: GBuffer[?]; tg]) => + '{ + BufferRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }) + } + case ('[type t <: GStruct[?]; t], '[type tg <: GUniform[?]; tg]) => + val structSchema = Expr.summon[GStructSchema[t]] match + case Some(s) => s + case None => report.errorAndAbort(s"Cannot summon GStructSchema for type") + '{ + UniformRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }, ${ structSchema }) + } val constructor = sym.primaryConstructor diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala index 8bad4bb8..ce003c87 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala @@ -19,7 +19,7 @@ trait GBuffer[T <: Value: {FromExpr, Tag}] extends GBinding[T]: object GBuffer -trait GUniform[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}] extends GBinding[T]: +trait GUniform[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}] extends GBinding[T]: def read: T = fromExprEval(ReadUniform(this)) def write(value: T): GIO[Empty] = WriteUniform(this, value) @@ -28,6 +28,6 @@ trait GUniform[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}] extends GBinding object GUniform: - class ParamUniform[T <: GStruct[T]: {Tag, FromExpr}]() extends GUniform[T] + class ParamUniform[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}]() extends GUniform[T] - def fromParams[T <: GStruct[T]: {Tag, FromExpr}] = ParamUniform[T]() + def fromParams[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}] = ParamUniform[T]() diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadUniform.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadUniform.scala index 9f75a278..85b2b53e 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadUniform.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/ReadUniform.scala @@ -1,6 +1,7 @@ package io.computenode.cyfra.dsl.binding +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import io.computenode.cyfra.dsl.{Expression, Value} import izumi.reflect.Tag -case class ReadUniform[T <: Value: Tag](uniform: GUniform[T]) extends Expression[T] +case class ReadUniform[T <: GStruct[?]: {Tag, GStructSchema}](uniform: GUniform[T]) extends Expression[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala index a450a5e7..f176014a 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/WriteUniform.scala @@ -2,9 +2,9 @@ package io.computenode.cyfra.dsl.binding import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.gio.GIO -import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import io.computenode.cyfra.dsl.struct.GStruct.Empty import izumi.reflect.Tag -case class WriteUniform[T <: Value: Tag](uniform: GUniform[T], value: T) extends GIO[Empty]: +case class WriteUniform[T <: GStruct[?]: {Tag, GStructSchema}](uniform: GUniform[T], value: T) extends GIO[Empty]: override def underlying: Empty = Empty() diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala index 9ec4199b..f9f6b383 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala @@ -26,9 +26,9 @@ object GStruct: object Empty: given GStructSchema[Empty] = GStructSchema.derived - case class ComposeStruct[T <: GStruct[T]: Tag](fields: List[Value], resultSchema: GStructSchema[T]) extends Expression[T] + case class ComposeStruct[T <: GStruct[?]: Tag](fields: List[Value], resultSchema: GStructSchema[T]) extends Expression[T] - case class GetField[S <: GStruct[S]: GStructSchema, T <: Value: Tag](struct: E[S], fieldIndex: Int) extends Expression[T]: + case class GetField[S <: GStruct[?]: GStructSchema, T <: Value: Tag](struct: E[S], fieldIndex: Int) extends Expression[T]: val resultSchema: GStructSchema[S] = summon[GStructSchema[S]] given [T <: GStruct[T]: GStructSchema]: GStructConstructor[T] with diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala index e0cd5d8f..8c26aa4f 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStructSchema.scala @@ -10,7 +10,7 @@ import izumi.reflect.Tag import scala.compiletime.{constValue, erasedValue, error, summonAll} import scala.deriving.Mirror -case class GStructSchema[T <: GStruct[T]: Tag](fields: List[(String, FromExpr[?], Tag[?])], dependsOn: Option[E[T]], fromTuple: (Tuple, Source) => T): +case class GStructSchema[T <: GStruct[?]: Tag](fields: List[(String, FromExpr[?], Tag[?])], dependsOn: Option[E[T]], fromTuple: (Tuple, Source) => T): given GStructSchema[T] = this val structTag = summon[Tag[T]] @@ -23,7 +23,7 @@ case class GStructSchema[T <: GStruct[T]: Tag](fields: List[(String, FromExpr[?] def create(values: List[Value], schema: GStructSchema[T])(using name: Source): T = val valuesTuple = Tuple.fromArray(values.toArray) val newStruct = fromTuple(valuesTuple, name) - newStruct._schema = schema + newStruct._schema = schema.asInstanceOf newStruct.tree.of = Some(newStruct) newStruct diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index cd2fc227..e431b719 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -9,9 +9,12 @@ import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.runtime.VkCyfraRuntime +import io.computenode.cyfra.spirvtools.SpirvTool.ToFile +import io.computenode.cyfra.spirvtools.{SpirvCross, SpirvToolsRunner, SpirvValidator} import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil +import java.nio.file.Paths import java.util.concurrent.atomic.AtomicInteger import scala.collection.parallel.CollectionConverters.given @@ -88,9 +91,52 @@ object TestingStuff: layout => FilterProgramLayout(in = layout.emitBuffer, out = layout.filterBuffer), ) + @main + def testEmit = + given runtime: VkCyfraRuntime = VkCyfraRuntime( + spirvToolsRunner = SpirvToolsRunner( + crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))) + ) + ) + + val emitParams = EmitProgramParams(inSize = 1024, emitN = 2) + + val region = GBufferRegion + .allocate[EmitProgramLayout] + .map: region => + emitProgram.execute(emitParams, region) + + val data = (0 until 1024).toArray + val buffer = BufferUtils.createByteBuffer(data.length * 4) + buffer.asIntBuffer().put(data).flip() + + val result = BufferUtils.createIntBuffer(data.length * 2) + val rbb = MemoryUtil.memByteBuffer(result) + region.runUnsafe( + init = EmitProgramLayout( + in = GBuffer[Int32](buffer), + out = GBuffer[Int32](data.length * 2), + ), + onDone = layout => layout.out.read(rbb), + ) + runtime.close() + + val actual = (0 until 2 * 1024).map(i => result.get(i * 1)) + val expected = (0 until 1024).flatMap(x => Seq.fill(emitParams.emitN)(x)) + expected + .zip(actual) + .zipWithIndex + .foreach: + case ((e, a), i) => assert(e == a, s"Mismatch at index $i: expected $e, got $a") + @main def test = - given runtime: VkCyfraRuntime = VkCyfraRuntime() + given runtime: VkCyfraRuntime = VkCyfraRuntime( + spirvToolsRunner = SpirvToolsRunner( + crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))), + validator = SpirvValidator.Disable + ) + ) val emitFilterParams = EmitFilterParams(inSize = 1024, emitN = 2, filterValue = 42) @@ -115,7 +161,7 @@ object TestingStuff: ) runtime.close() - val actual = (0 until 2 * 1024).map(i => result.get(i * 1) != 0) + val actual = (0 until 2 * 1024).map(i => result.get(i) != 0) val expected = (0 until 1024).flatMap(x => Seq.fill(emitFilterParams.emitN)(x)).map(_ == emitFilterParams.filterValue) expected .zip(actual) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index 00855e4e..d0ad3a5a 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -8,15 +8,8 @@ import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} -import io.computenode.cyfra.runtime.ExecutionHandler.{ - BindingLogicError, - Dispatch, - DispatchType, - ExecutionBinding, - ExecutionStep, - PipelineBarrier, - ShaderCall, -} +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} +import io.computenode.cyfra.runtime.ExecutionHandler.{BindingLogicError, Dispatch, DispatchType, ExecutionBinding, ExecutionStep, PipelineBarrier, ShaderCall} import io.computenode.cyfra.runtime.ExecutionHandler.DispatchType.* import io.computenode.cyfra.runtime.ExecutionHandler.ExecutionBinding.{BufferBinding, UniformBinding} import io.computenode.cyfra.utility.Utility.timed @@ -248,11 +241,16 @@ object ExecutionHandler: sealed trait ExecutionBinding[T <: Value: {FromExpr, Tag}] object ExecutionBinding: - class UniformBinding[T <: Value: {FromExpr, Tag}] extends ExecutionBinding[T] with GUniform[T] + class UniformBinding[T <: GStruct[?]: {FromExpr, Tag, GStructSchema}] extends ExecutionBinding[T] with GUniform[T] class BufferBinding[T <: Value: {FromExpr, Tag}] extends ExecutionBinding[T] with GBuffer[T] - def apply[T <: Value: {FromExpr, Tag}](binding: GBinding[T]): ExecutionBinding[T] & GBinding[T] = binding match - case _: GUniform[T] => new UniformBinding() + def apply[T <: Value: {FromExpr as fe, Tag as t}](binding: GBinding[T]): ExecutionBinding[T] & GBinding[T] = binding match + // todo types are a mess here + case u: GUniform[GStruct[?]] => new UniformBinding[GStruct[?]](using + fe.asInstanceOf[FromExpr[GStruct[?]]], + t.asInstanceOf[Tag[GStruct[?]]], + u.schema.asInstanceOf + ).asInstanceOf[UniformBinding[T]] case _: GBuffer[T] => new BufferBinding() case class BindingLogicError(bindings: Seq[GBinding[?]], message: String) extends RuntimeException(s"Error in binding logic for $bindings: $message") diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index a038ac7b..350f0369 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -7,7 +7,7 @@ import io.computenode.cyfra.dsl.Expression.ConstInt32 import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} -import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import io.computenode.cyfra.runtime.VkAllocation.getUnderlying import io.computenode.cyfra.spirv.SpirvTypes.typeStride import io.computenode.cyfra.vulkan.command.CommandPool @@ -57,22 +57,22 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) GBuffer[T](length).tap(_.write(buff)) extension (buffers: GUniform.type) - def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GUniform[T] = + def apply[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}](buff: ByteBuffer): GUniform[T] = GUniform[T]().tap(_.write(buff)) - def apply[T <: Value: {Tag, FromExpr}](): GUniform[T] = + def apply[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}](): GUniform[T] = VkUniform[T]().tap(bindings += _) extension [Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding](execution: GExecution[Params, EL, RL]) def execute(params: Params, layout: EL): RL = executionHandler.handle(execution, params, layout) - private def direct[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GUniform[T] = + private def direct[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}](buff: ByteBuffer): GUniform[T] = GUniform[T](buff) def getInitProgramLayout: GProgram.InitProgramLayout = new GProgram.InitProgramLayout: extension (uniforms: GUniform.type) - def apply[T <: GStruct[T]: {Tag, FromExpr}](value: T): GUniform[T] = pushStack: stack => + def apply[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}](value: T): GUniform[T] = pushStack: stack => val bb = value.productElement(0) match case Int32(tree: ConstInt32) => MemoryUtil.memByteBuffer(stack.ints(tree.value)) case _ => ??? diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala index ccd6585f..c6383665 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala @@ -1,19 +1,34 @@ package io.computenode.cyfra.runtime +import io.computenode.cyfra.core.GProgram.InitProgramLayout import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} -import io.computenode.cyfra.core.{Allocation, CyfraRuntime, GExecution, GProgram, SpirvProgram} +import io.computenode.cyfra.core.{Allocation, CyfraRuntime, GExecution, GProgram, GioProgram, SpirvProgram} +import io.computenode.cyfra.spirv.compilers.DSLCompiler +import io.computenode.cyfra.spirvtools.SpirvToolsRunner import io.computenode.cyfra.vulkan.VulkanContext import io.computenode.cyfra.vulkan.compute.ComputePipeline import scala.collection.mutable -class VkCyfraRuntime extends CyfraRuntime: +class VkCyfraRuntime(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()) extends CyfraRuntime: private val context = new VulkanContext() import context.given - private val shaderCache = mutable.Map.empty[String, VkShader[?]] - private[cyfra] def getOrLoadProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}](program: GProgram[Params, L]): VkShader[L] = - shaderCache.getOrElseUpdate(program.cacheKey, VkShader(program)).asInstanceOf[VkShader[L]] + private val shaderCache = mutable.Map[GProgram[?, ?], VkShader[?]]() + private[cyfra] def getOrLoadProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}](program: GProgram[Params, L]): VkShader[L] = synchronized: + val spirvProgram = program match + case p: GioProgram[?, ?] => compile(p) + case p: SpirvProgram[?, ?] => p + case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") + + shaderCache.getOrElseUpdate(program, VkShader(spirvProgram)).asInstanceOf[VkShader[L]] + + private def compile[Params, L <: Layout: {LayoutBinding as lbinding, LayoutStruct as lstruct}](program: GioProgram[Params, L]): SpirvProgram[Params, L] = + val GioProgram(_, layout, dispatch, _) = program + val bindings = lbinding.toBindings(lstruct.layoutRef).toList + val compiled = DSLCompiler.compile(program.body(summon[LayoutStruct[L]].layoutRef), bindings) + val optimizedShaderCode = spirvToolsRunner.processShaderCodeWithSpirvTools(compiled) + SpirvProgram((il: InitProgramLayout) ?=> layout(il), dispatch, optimizedShaderCode) override def withAllocation(f: Allocation => Unit): Unit = context.withThreadContext: threadContext => diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala index 3086b15c..d2209fe1 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala @@ -16,11 +16,8 @@ import scala.util.{Failure, Success} case class VkShader[L](underlying: ComputePipeline, shaderBindings: L => ShaderLayout) object VkShader: - def apply[P, L <: Layout: {LayoutBinding, LayoutStruct}](program: GProgram[P, L])(using Device): VkShader[L] = - val SpirvProgram(layout, dispatch, _workgroupSize, code, entryPoint, shaderBindings, _) = program match - case p: GioProgram[?, ?] => compile(p) - case p: SpirvProgram[?, ?] => p - case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") + def apply[P, L <: Layout: {LayoutBinding, LayoutStruct}](program: SpirvProgram[P, L])(using Device): VkShader[L] = + val SpirvProgram(layout, dispatch, _workgroupSize, code, entryPoint, shaderBindings) = program val shaderLayout = shaderBindings(summon[LayoutStruct[L]].layoutRef) val sets = shaderLayout.map: set => @@ -35,7 +32,3 @@ object VkShader: val pipeline = ComputePipeline(code, entryPoint, LayoutInfo(sets)) VkShader(pipeline, shaderBindings) - def compile[Params, L <: Layout: {LayoutBinding, LayoutStruct}](program: GioProgram[Params, L]): SpirvProgram[Params, L] = - val GioProgram(_, layout, dispatch, _) = program - val compiled = DSLCompiler.compile(program.body(summon[LayoutStruct[L]].layoutRef), ???) - SpirvProgram((il: InitProgramLayout) ?=> layout(il), dispatch, compiled) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala index f8c75da7..86ed671e 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala @@ -3,19 +3,20 @@ package io.computenode.cyfra.runtime import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.GUniform +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} import izumi.reflect.Tag import org.lwjgl.vulkan.VK10 import org.lwjgl.vulkan.VK10.* -class VkUniform[T <: Value: {Tag, FromExpr}] private (val underlying: Buffer) extends GUniform[T]: +class VkUniform[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}] private (val underlying: Buffer) extends GUniform[T]: val sizeOfT: Int = 4 object VkUniform: private final val UsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT - def apply[T <: Value: {Tag, FromExpr}]()(using Allocator): VkUniform[T] = + def apply[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}]()(using Allocator): VkUniform[T] = val sizeOfT = 4 // typeStride(summon[Tag[T]]) val buffer = new Buffer.DeviceBuffer(sizeOfT, UsageFlags) new VkUniform[T](buffer) diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala index 73304350..991fda38 100644 --- a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala @@ -20,7 +20,7 @@ object SpirvCross extends SpirvTool("spirv-cross"): case Right(crossCompiledCode) => toolOutput match case Ignore => - case toFile @ SpirvTool.ToFile(_) => + case toFile @ SpirvTool.ToFile(_, _) => toFile.write(crossCompiledCode) logger.debug(s"Saved cross compiled shader code in ${toFile.filePath}.") case ToLogger => logger.debug(s"SPIR-V Cross Compilation result:\n$crossCompiledCode") diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala index f0c7c38f..67730961 100644 --- a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala @@ -19,7 +19,7 @@ object SpirvDisassembler extends SpirvTool("spirv-dis"): case Right(disassembledShader) => toolOutput match case Ignore => - case toFile @ SpirvTool.ToFile(_) => + case toFile @ SpirvTool.ToFile(_, _) => toFile.write(disassembledShader) logger.debug(s"Saved disassembled shader code in ${toFile.filePath}.") case ToLogger => logger.debug(s"SPIR-V Assembly:\n$disassembledShader") diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala index b42c0651..509e763c 100644 --- a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala @@ -20,7 +20,7 @@ object SpirvOptimizer extends SpirvTool("spirv-opt"): case Right(optimizedShaderCode) => toolOutput match case SpirvTool.Ignore => - case toFile @ SpirvTool.ToFile(_) => + case toFile @ SpirvTool.ToFile(_, _) => toFile.write(optimizedShaderCode) logger.debug(s"Saved optimized shader code in ${toFile.filePath}.") Some(optimizedShaderCode) diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvTool.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvTool.scala index 729c0efd..58501a42 100644 --- a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvTool.scala +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvTool.scala @@ -95,18 +95,27 @@ object SpirvTool: case class Param(value: String): def asStringParam: String = value - case class ToFile(filePath: Path) extends ToolOutput: + case class ToFile(filePath: Path, hashSuffix: Boolean = true) extends ToolOutput: require(filePath != null, "filePath must not be null") - def write(outputToSave: String | ByteBuffer): Unit = - Option(filePath.getParent).foreach { dir => + def write(outputToSave: String | ByteBuffer): Unit = { + val suffix = if hashSuffix then s"_${outputToSave.hashCode() & 0xffff}" else "" + // prefix before last dot + val suffixedPath = filePath.getFileName.toString.lastIndexOf('.') match + case -1 => filePath.getFileName.toString + suffix + case index => filePath.getFileName.toString.substring(0, index) + suffix + filePath.getFileName.toString.substring(index) + val updatedPath = filePath.getParent match + case null => Path.of(suffixedPath) + case dir => dir.resolve(suffixedPath) + Option(updatedPath.getParent).foreach { dir => if !Files.exists(dir) then Files.createDirectories(dir) logger.debug(s"Created output directory: $dir") outputToSave match - case stringOutput: String => Files.write(filePath, stringOutput.getBytes(StandardCharsets.UTF_8)) - case byteBuffer: ByteBuffer => dumpByteBufferToFile(byteBuffer, filePath) + case stringOutput: String => Files.write(updatedPath, stringOutput.getBytes(StandardCharsets.UTF_8)) + case byteBuffer: ByteBuffer => dumpByteBufferToFile(byteBuffer, updatedPath) } + } private def dumpByteBufferToFile(code: ByteBuffer, path: Path): Unit = Using.resource(new FileOutputStream(path.toAbsolutePath.toString).getChannel) { fc => diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvToolsRunner.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvToolsRunner.scala index 234fca7b..1467350e 100644 --- a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvToolsRunner.scala +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvToolsRunner.scala @@ -20,7 +20,7 @@ class SpirvToolsRunner( SpirvValidator.validateSpirv(code, validator) originalSpirvOutput match - case toFile @ SpirvTool.ToFile(_) => + case toFile @ SpirvTool.ToFile(_, _) => toFile.write(shaderCode) logger.debug(s"Saved original shader code in ${toFile.filePath}.") case Ignore => From dbf17349127767c9368f85d7595bab07dd1f5f16 Mon Sep 17 00:00:00 2001 From: Szymon Date: Sun, 24 Aug 2025 23:29:17 +0200 Subject: [PATCH 31/59] FlatMap --- .../io/computenode/cyfra/spirv/compilers/GIOCompiler.scala | 6 +++++- .../io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala index a4a55212..dd1d853c 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala @@ -11,7 +11,7 @@ object GIOCompiler: def compileGio(gio: GIO[?], ctx: Context, acc: List[Words] = Nil): (List[Words], Context) = gio match - + case GIO.Pure(v) => val (insts, updatedCtx) = ExpressionCompiler.compileBlock(v.tree, ctx) (acc ::: insts, updatedCtx) @@ -35,6 +35,10 @@ object GIOCompiler: val updatedCtx = ctxWithIndex.copy(nextResultId = ctxWithIndex.nextResultId + 1) (acc ::: indexInsts ::: valueInsts ::: insns, updatedCtx) + case GIO.FlatMap(v, n) => + val (vInsts, ctxAfterV) = compileGio(v, ctx, acc) + compileGio(n, ctxAfterV, vInsts) + case GIO.Repeat(n, f) => // Compile 'n' first (so we can use its id in the comparison) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala index 35ad5bb2..4d002c19 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala @@ -7,6 +7,7 @@ import io.computenode.cyfra.dsl.Value.{GBoolean, Int32} import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.GStruct.Empty import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.runtime.VkCyfraRuntime import io.computenode.cyfra.utility.Logger.logger @@ -153,7 +154,7 @@ class RuntimeEnduranceTest extends munit.FunSuite: _ <- GIO.write(out3, index, GIO.read(in3, index) + a + b) _ <- GIO.write(out4, index, GIO.read(in4, index) + a + b) _ <- GIO.write(out5, index, GIO.read(in5, index) + a + b) - yield () + yield Empty() def swap(l: AddProgramLayout): AddProgramLayout = val AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5, u1, u2) = l From b2d53f87c8d19ba2b0eba7111fd414386787ea49 Mon Sep 17 00:00:00 2001 From: spamegg Date: Tue, 26 Aug 2025 15:48:56 +0300 Subject: [PATCH 32/59] added stream compaction program --- .../computenode/cyfra/fs2interop/GPipe.scala | 108 +++++++++++------- 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 8bfbcfa9..85346448 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -58,11 +58,12 @@ object GPipe: def filter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: Bridge[C, S]): Pipe[F, S, S] = (stream: Stream[F, S]) => + case class Params(inSize: Int) // used commonly by many program layouts + // Predicate mapping - case class PredParams(inSize: Int) case class PredLayout(in: GBuffer[C], out: GBuffer[Int32]) extends Layout - val predicateProgram = GProgram[PredParams, PredLayout]( + val predicateProgram = GProgram[Params, PredLayout]( layout = params => PredLayout(in = GBuffer[C](params.inSize), out = GBuffer[Int32](params.inSize)), dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), ): layout => @@ -71,10 +72,6 @@ object GPipe: val result = when(pred(element))(1: Int32).otherwise(0) GIO.write[Int32](layout.out, invocId, result) - val predParams = PredParams(256) - val predExec = GExecution[PredParams, PredLayout]() - .addProgram(predicateProgram)(params => params, layout => layout) - // Prefix sum (inclusive), upsweep/downsweep case class ScanParams(inSize: Int, intervalSize: Int) case class ScanArgs(intervalSize: Int32) extends GStruct[ScanArgs] @@ -107,66 +104,99 @@ object GPipe: val newValue = oldValue + addValue GIO.write[Int32](layout.ints, mid, newValue) + // Stitch together many upsweep / downsweep program phases recursively @annotation.tailrec - def upsweepPhases(exec: GExecution[ScanParams, ScanLayout, ?], inSize: Int, intervalSize: Int): GExecution[ScanParams, ScanLayout, ?] = + def upsweepPhases( + exec: GExecution[ScanParams, ScanLayout, ScanLayout], + inSize: Int, + intervalSize: Int, + ): GExecution[ScanParams, ScanLayout, ScanLayout] = if intervalSize >= inSize then exec else val newExec = exec.addProgram(upsweep)(params => ScanParams(inSize, intervalSize), layout => layout) upsweepPhases(newExec, inSize, intervalSize * 2) - val upsweepInitialExec = GExecution[ScanParams, ScanLayout]() - val upsweepExec = upsweepPhases(upsweepInitialExec, 256, 2) - @annotation.tailrec - def downsweepPhases(exec: GExecution[ScanParams, ScanLayout, ?], inSize: Int, intervalSize: Int): GExecution[ScanParams, ScanLayout, ?] = + def downsweepPhases( + exec: GExecution[ScanParams, ScanLayout, ScanLayout], + inSize: Int, + intervalSize: Int, + ): GExecution[ScanParams, ScanLayout, ScanLayout] = if intervalSize < 2 then exec else val newExec = exec.addProgram(downsweep)(params => ScanParams(inSize, intervalSize), layout => layout) downsweepPhases(newExec, inSize, intervalSize / 2) - val downsweepExec = downsweepPhases(upsweepInitialExec, 256, 128) - val scanParams = ScanParams(256, 2) - - // TODO implement compaction - case class CompactParams() - case class CompactLayout(in: GBuffer[C], intIn: GBuffer[Int32], out: GBuffer[C]) extends Layout - val compactedStreamSize: Int = ??? // TODO how to get this out of prefix sum results - - val compactProgram = GProgram[CompactParams, CompactLayout](layout = params => ???, dispatch = (layout, params) => ???): compactLayout => - ??? - val compactExec = GExecution[CompactParams, CompactLayout]() + val initExec = GExecution[ScanParams, ScanLayout]() // no program + val upsweepExec = upsweepPhases(initExec, 256, 2) // add all upsweep phases + val scanExec = downsweepPhases(upsweepExec, 256, 128) // add all downsweep phases - // TODO: connect all the layouts/executions into one - case class PredScanCompactParams(inSize: Int) - case class PredScanCompactLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C]) extends Layout + // Stream compaction + case class CompactLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C]) extends Layout - // How to "connect" many GExecutions? with flatMap? - val predScanCompactExec = GExecution[PredScanCompactParams, PredScanCompactLayout]() - // predExec - // .flatMap(predLayout => ???) // add downsweepExec - // .flatMap(layout => ???) // add compactExec - val predScanCompactParams = PredScanCompactParams(256) // TODO + val compactProgram = GProgram[Params, CompactLayout]( + layout = params => CompactLayout(in = GBuffer[C](params.inSize), scan = GBuffer[Int32](params.inSize), out = GBuffer[C](params.inSize)), + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), + ): layout => + val invocId = GIO.invocationId + val element = GIO.read[C](layout.in, invocId) + val prefixSum = GIO.read[Int32](layout.scan, invocId) + val prevScan = when(invocId > 0)(GIO.read[Int32](layout.scan, invocId - 1)).otherwise(prefixSum) + val condt = when(invocId > 0)(when(prevScan < prefixSum)(1: Int32).otherwise(0)).otherwise(when(prefixSum > 0)(1: Int32).otherwise(0)) + val index = when(invocId > 0)(when(prevScan < prefixSum)(prevScan).otherwise(0)).otherwise(0) + GIO.repeat(condt): _ => + GIO.write[C](layout.out, index, element) + + // connect all the layouts/executions into one + case class FilterLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C]) extends Layout + + val filterExec = GExecution[Params, FilterLayout]() + // val filterExec = predicateProgram + // .flatMap[ScanLayout, ScanParams]: predLayout => + // scanExec + // .contramap[ScanLayout](layout => ScanLayout(???, ???)) + // .contramapParams[ScanParams](params => ScanParams(???, ???)) + // .map(_ => predLayout) + // .flatMap[FilterLayout, Params]: scanLayout => + // compactProgram + // .contramap[FilterLayout](layout => CompactLayout(???, ???, ???)) + // .contramapParams[Params](params => params) + // .map(_ => scanLayout) + + val filterParams = Params(256) // TODO + + // case class FilterParams(intervalSize: ScanArgs()) + // case class FilterLayout(inBuf: GBuffer[C], scanBuf: GBuffer[Int32]) + // val filterExec = GExecution[FilterParams, FilterLayout]() + // .addProgram(predicateProgram)(params => PredParams(params.inSize), layout => PredLayout(layout.in, layout.pred)) + // .flatMap[FilterLayout, FilterParams](l => + // downsweepExec + // .contramap[FilterLayout](layout => ScanLayout(layout.pred, layout.intervalSize)) + // .contramapParams[FilterParams](p => ScanParams(p.inSize, 2)) + // .map(_ => l) + // ) val region = GBufferRegion - .allocate[PredScanCompactLayout] + .allocate[FilterLayout] .map: layout => - predScanCompactExec.execute(predScanCompactParams, layout) + filterExec.execute(filterParams, layout) val typeSize = typeStride(Tag.apply[C]) val intSize = typeStride(Tag.apply[Int32]) + val params = Params(256) // these are allocated once, reused for many chunks - val predBuf = BufferUtils.createByteBuffer(predParams.inSize * typeSize) - val scanBuf = BufferUtils.createByteBuffer(predParams.inSize * intSize) - val compactBuf = BufferUtils.createByteBuffer(compactedStreamSize * typeSize) + val predBuf = BufferUtils.createByteBuffer(params.inSize * typeSize) + val scanBuf = BufferUtils.createByteBuffer(params.inSize * intSize) + val compactBuf = BufferUtils.createByteBuffer(256 * typeSize) stream - .chunkMin(predScanCompactParams.inSize) + .chunkMin(filterParams.inSize) .flatMap: chunk => bridge.toByteBuffer(predBuf, chunk) region.runUnsafe( - init = PredScanCompactLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf)), + init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf)), onDone = layout => layout.out.read(compactBuf), ) - val arr = bridge.fromByteBuffer(compactBuf, new Array[S](compactedStreamSize)) + val arr = bridge.fromByteBuffer(compactBuf, new Array[S](256)) Stream.emits(arr) From 77deb47c1c70caa87b6ae3b4c47ab70bbfdb2d11 Mon Sep 17 00:00:00 2001 From: spamegg Date: Tue, 26 Aug 2025 17:22:00 +0300 Subject: [PATCH 33/59] finish filter --- .../computenode/cyfra/fs2interop/GPipe.scala | 72 +++++++++---------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 85346448..ddab40c1 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -58,12 +58,11 @@ object GPipe: def filter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: Bridge[C, S]): Pipe[F, S, S] = (stream: Stream[F, S]) => - case class Params(inSize: Int) // used commonly by many program layouts - // Predicate mapping + case class PredParams(inSize: Int) case class PredLayout(in: GBuffer[C], out: GBuffer[Int32]) extends Layout - val predicateProgram = GProgram[Params, PredLayout]( + val predicateProgram = GProgram[PredParams, PredLayout]( layout = params => PredLayout(in = GBuffer[C](params.inSize), out = GBuffer[Int32](params.inSize)), dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), ): layout => @@ -132,9 +131,10 @@ object GPipe: val scanExec = downsweepPhases(upsweepExec, 256, 128) // add all downsweep phases // Stream compaction + case class CompactParams(inSize: Int) case class CompactLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C]) extends Layout - val compactProgram = GProgram[Params, CompactLayout]( + val compactProgram = GProgram[CompactParams, CompactLayout]( layout = params => CompactLayout(in = GBuffer[C](params.inSize), scan = GBuffer[Int32](params.inSize), out = GBuffer[C](params.inSize)), dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), ): layout => @@ -148,54 +148,48 @@ object GPipe: GIO.write[C](layout.out, index, element) // connect all the layouts/executions into one - case class FilterLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C]) extends Layout - - val filterExec = GExecution[Params, FilterLayout]() - // val filterExec = predicateProgram - // .flatMap[ScanLayout, ScanParams]: predLayout => - // scanExec - // .contramap[ScanLayout](layout => ScanLayout(???, ???)) - // .contramapParams[ScanParams](params => ScanParams(???, ???)) - // .map(_ => predLayout) - // .flatMap[FilterLayout, Params]: scanLayout => - // compactProgram - // .contramap[FilterLayout](layout => CompactLayout(???, ???, ???)) - // .contramapParams[Params](params => params) - // .map(_ => scanLayout) - - val filterParams = Params(256) // TODO - - // case class FilterParams(intervalSize: ScanArgs()) - // case class FilterLayout(inBuf: GBuffer[C], scanBuf: GBuffer[Int32]) - // val filterExec = GExecution[FilterParams, FilterLayout]() - // .addProgram(predicateProgram)(params => PredParams(params.inSize), layout => PredLayout(layout.in, layout.pred)) - // .flatMap[FilterLayout, FilterParams](l => - // downsweepExec - // .contramap[FilterLayout](layout => ScanLayout(layout.pred, layout.intervalSize)) - // .contramapParams[FilterParams](p => ScanParams(p.inSize, 2)) - // .map(_ => l) - // ) - + case class FilterParams(inSize: Int, intervalSize: Int) + case class FilterLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C], intervalSize: GUniform[ScanArgs]) extends Layout + + val filterExec = GExecution[FilterParams, FilterLayout]() + .addProgram(predicateProgram)( + filterParams => PredParams(filterParams.inSize), + filterLayout => PredLayout(in = filterLayout.in, out = filterLayout.scan), + ) + .flatMap[FilterLayout, FilterParams]: filterLayout => + scanExec + .contramap[FilterLayout]: filterLayout => + ScanLayout(filterLayout.scan, filterLayout.intervalSize) + .contramapParams[FilterParams](filterParams => ScanParams(filterParams.inSize, filterParams.intervalSize)) + .map(scanLayout => filterLayout) + .flatMap[FilterLayout, FilterParams]: filterLayout => + compactProgram + .contramap[FilterLayout]: filterLayout => + CompactLayout(filterLayout.in, filterLayout.scan, filterLayout.out) + .contramapParams[FilterParams](filterParams => CompactParams(filterParams.inSize)) + .map(compactLayout => filterLayout) + + // finally setup buffers, region, parameters, and run the program + val filterParams = FilterParams(256, 2) val region = GBufferRegion .allocate[FilterLayout] - .map: layout => - filterExec.execute(filterParams, layout) + .map: filterLayout => + filterExec.execute(filterParams, filterLayout) val typeSize = typeStride(Tag.apply[C]) val intSize = typeStride(Tag.apply[Int32]) - val params = Params(256) // these are allocated once, reused for many chunks - val predBuf = BufferUtils.createByteBuffer(params.inSize * typeSize) - val scanBuf = BufferUtils.createByteBuffer(params.inSize * intSize) - val compactBuf = BufferUtils.createByteBuffer(256 * typeSize) + val predBuf = BufferUtils.createByteBuffer(filterParams.inSize * typeSize) + val scanBuf = BufferUtils.createByteBuffer(filterParams.inSize * intSize) + val compactBuf = BufferUtils.createByteBuffer(filterParams.inSize * typeSize) stream .chunkMin(filterParams.inSize) .flatMap: chunk => bridge.toByteBuffer(predBuf, chunk) region.runUnsafe( - init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf)), + init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf), intervalSize = ???), onDone = layout => layout.out.read(compactBuf), ) val arr = bridge.fromByteBuffer(compactBuf, new Array[S](256)) From dcfe4f9a9ca711553244a2d256fa950b34a946ed Mon Sep 17 00:00:00 2001 From: spamegg Date: Tue, 26 Aug 2025 17:23:41 +0300 Subject: [PATCH 34/59] small fix --- .../src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index ddab40c1..d3aa531e 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -189,7 +189,7 @@ object GPipe: .flatMap: chunk => bridge.toByteBuffer(predBuf, chunk) region.runUnsafe( - init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf), intervalSize = ???), + init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf), intervalSize = GUniform()), onDone = layout => layout.out.read(compactBuf), ) val arr = bridge.fromByteBuffer(compactBuf, new Array[S](256)) From 0f92e5d4360a95f86348f277d42fff274e972ba5 Mon Sep 17 00:00:00 2001 From: spamegg Date: Wed, 27 Aug 2025 14:26:32 +0300 Subject: [PATCH 35/59] implement GIO.when and use for-expression in compactProgram --- .../scala/io/computenode/cyfra/dsl/gio/GIO.scala | 6 ++++++ .../io/computenode/cyfra/fs2interop/GPipe.scala | 13 +++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala index 02a018f8..cbac2470 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala @@ -6,6 +6,7 @@ import io.computenode.cyfra.dsl.Value.FromExpr.fromExpr import io.computenode.cyfra.dsl.binding.{GBuffer, ReadBuffer, WriteBuffer} import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.gio.GIO.* +import io.computenode.cyfra.dsl.control.When import izumi.reflect.Tag trait GIO[T]: @@ -35,6 +36,11 @@ object GIO: def repeat(n: Int32)(f: Int32 => GIO[?]): GIO[Unit] = Repeat(n, f) + def when(cond: GBoolean)(thenCode: GIO[?]): GIO[Unit] = + val n = When.when(cond)(1: Int32).otherwise(0) + repeat(n): _ => + thenCode + def write[T <: Value](buffer: GBuffer[T], index: Int32, value: T): GIO[Unit] = WriteBuffer(buffer, index, value) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index d3aa531e..00553c01 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -142,10 +142,15 @@ object GPipe: val element = GIO.read[C](layout.in, invocId) val prefixSum = GIO.read[Int32](layout.scan, invocId) val prevScan = when(invocId > 0)(GIO.read[Int32](layout.scan, invocId - 1)).otherwise(prefixSum) - val condt = when(invocId > 0)(when(prevScan < prefixSum)(1: Int32).otherwise(0)).otherwise(when(prefixSum > 0)(1: Int32).otherwise(0)) - val index = when(invocId > 0)(when(prevScan < prefixSum)(prevScan).otherwise(0)).otherwise(0) - GIO.repeat(condt): _ => - GIO.write[C](layout.out, index, element) + for + _ <- GIO.when(invocId > 0): + val prevScan = GIO.read[Int32](layout.scan, invocId - 1) + GIO.when(prevScan < prefixSum): + GIO.write(layout.out, prevScan, element) + _ <- GIO.when(invocId === 0): + GIO.when(prefixSum > 0): + GIO.write(layout.out, invocId, element) + yield () // connect all the layouts/executions into one case class FilterParams(inSize: Int, intervalSize: Int) From 2840c28e873c835777c5a83dbf2f9ecfb95058a5 Mon Sep 17 00:00:00 2001 From: spamegg Date: Wed, 27 Aug 2025 14:40:31 +0300 Subject: [PATCH 36/59] small cleanup --- .../src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 00553c01..cd61a423 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -141,7 +141,6 @@ object GPipe: val invocId = GIO.invocationId val element = GIO.read[C](layout.in, invocId) val prefixSum = GIO.read[Int32](layout.scan, invocId) - val prevScan = when(invocId > 0)(GIO.read[Int32](layout.scan, invocId - 1)).otherwise(prefixSum) for _ <- GIO.when(invocId > 0): val prevScan = GIO.read[Int32](layout.scan, invocId - 1) From 40aa8e2892055cc09e5672985f1cb83baa57aa91 Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Wed, 3 Sep 2025 20:14:31 +0200 Subject: [PATCH 37/59] more^ --- .../cyfra/runtime/ExecutionHandler.scala | 2 +- .../cyfra/runtime/PendingExecution.scala | 22 ++++++++++--------- .../cyfra/runtime/VkAllocation.scala | 2 +- .../cyfra/vulkan/command/Semaphore.scala | 2 +- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index a20efbbb..89473f8c 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -74,7 +74,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte val externalBindings = (summon[LayoutBinding[EL]].toBindings(layout) ++ summon[LayoutBinding[RL]].toBindings(result)) .map(VkAllocation.getUnderlying) val deps = externalBindings.flatMap(_.execution.fold(Seq(_), _.toSeq)) - val pe = new PendingExecution(commandBuffer, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, deps, cleanup) + val pe = new PendingExecution(commandBuffer, deps, cleanup) externalBindings.foreach(_.execution = Left(pe)) result diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala index b213c0c9..63cf516f 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala @@ -5,14 +5,13 @@ import io.computenode.cyfra.vulkan.core.{Device, Queue} import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObject import org.lwjgl.vulkan.VK13.{VK_PIPELINE_STAGE_2_COPY_BIT, vkQueueSubmit2} -import org.lwjgl.vulkan.{VkCommandBuffer, VkCommandBufferSubmitInfo, VkSemaphoreSubmitInfo, VkSubmitInfo2} +import org.lwjgl.vulkan.{VK13, VkCommandBuffer, VkCommandBufferSubmitInfo, VkSemaphoreSubmitInfo, VkSubmitInfo2} import scala.collection.mutable -class PendingExecution(protected val handle: VkCommandBuffer, val waitStage: Long, val dependencies: Seq[PendingExecution], cleanup: () => Unit)( - using Device, -) extends VulkanObject[VkCommandBuffer]: - private val semaphore: Semaphore = Semaphore(waitStage) +class PendingExecution(protected val handle: VkCommandBuffer, val dependencies: Seq[PendingExecution], cleanup: () => Unit)(using Device) + extends VulkanObject[VkCommandBuffer]: + private val semaphore: Semaphore = Semaphore() private var fence: Option[Fence] = None override protected def close(): Unit = cleanup() @@ -35,10 +34,13 @@ class PendingExecution(protected val handle: VkCommandBuffer, val waitStage: Lon object PendingExecution: def executeAll(executions: Seq[PendingExecution], queue: Queue)(using Device): Fence = pushStack: stack => - val gathered = executions.flatMap(_.gatherForSubmission).toSet.groupMap(_._2)(_._1).toSeq + val exec = + val gathered = executions.flatMap(_.gatherForSubmission) + val ordering = gathered.zipWithIndex.map(x => (x._1._1._1, x._2)).toMap + gathered.toSet.groupMap(_._2)(_._1).toSeq.sortBy(x => x._2.map(_._1).map(ordering).min) - val submitInfos = VkSubmitInfo2.calloc(gathered.size, stack) - gathered.foreach: (semaphores, executions) => + val submitInfos = VkSubmitInfo2.calloc(exec.size, stack) + exec.foreach: (semaphores, executions) => val pCommandBuffersSI = VkCommandBufferSubmitInfo.calloc(executions.size, stack) val signalSemaphoreSI = VkSemaphoreSubmitInfo.calloc(executions.size, stack) executions.foreach: (cb, s) => @@ -51,7 +53,7 @@ object PendingExecution: .get() .sType$Default() .semaphore(s.get) - .stageMask(s.stage) + .stageMask(VK13.VK_PIPELINE_STAGE_2_COPY_BIT | VK13.VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT) pCommandBuffersSI.flip() signalSemaphoreSI.flip() @@ -62,7 +64,7 @@ object PendingExecution: .get() .sType$Default() .semaphore(s.get) - .stageMask(s.stage) + .stageMask(VK13.VK_PIPELINE_STAGE_2_COPY_BIT | VK13.VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT) waitSemaphoreSI.flip() diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index a851389e..4ce9692c 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -53,7 +53,7 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) val cleanup = () => commandPool.freeCommandBuffer(cb) stagingBuffer.destroy() - val pe = new PendingExecution(cb, VK_PIPELINE_STAGE_2_COPY_BIT, binding.execution.fold(Seq(_), _.toSeq), cleanup) + val pe = new PendingExecution(cb, binding.execution.fold(Seq(_), _.toSeq), cleanup) binding.execution = Left(pe) case _ => throw new IllegalArgumentException(s"Tried to write to non-VkBinding $buffer") diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala index 88386710..2e86ef68 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala @@ -9,7 +9,7 @@ import org.lwjgl.vulkan.VkSemaphoreCreateInfo /** @author * MarconZet Created 30.10.2019 */ -private[cyfra] class Semaphore(val stage: Long)(using device: Device) extends VulkanObjectHandle: +private[cyfra] class Semaphore()(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => val semaphoreCreateInfo = VkSemaphoreCreateInfo .calloc(stack) From 1a01f99d2f8d596e5ee7220f7563bd4b0da6d12e Mon Sep 17 00:00:00 2001 From: Szymon Date: Sat, 6 Sep 2025 22:33:41 +0200 Subject: [PATCH 38/59] No warnings now --- .../io/computenode/cyfra/spirv/Context.scala | 2 +- .../cyfra/spirv/compilers/DSLCompiler.scala | 5 +- .../spirv/compilers/GStructCompiler.scala | 14 +++- .../compilers/SpirvProgramCompiler.scala | 81 +++++++++++-------- .../cyfra/e2e/RuntimeEnduranceTest.scala | 8 +- 5 files changed, 69 insertions(+), 41 deletions(-) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala index 8e8f5f96..62daf3d1 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala @@ -25,7 +25,7 @@ private[cyfra] case class Context( nextResultId: Int = HEADER_REFS_TOP, nextBinding: Int = 0, exprNames: Map[Int, String] = Map(), - memberNames: Map[Int, String] = Map(), + names: Set[String] = Set(), functions: Map[FnIdentifier, SprivFunction] = Map(), ): def joinNested(ctx: Context): Context = diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala index 09dd9999..84252ca7 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala @@ -79,7 +79,6 @@ private[cyfra] object DSLCompiler: case (_: GUniform[?], _) => false .asInstanceOf[(List[(GBuffer[?], Int)], List[(GUniform[?], Int)])] val uniforms = uniformsWithIndices.map(_._1) - val buffers = buffersWithIndices.map(_._1) val uniformSchemas = uniforms.map(_.schema) val structsInCode = (allExprs.collect { @@ -87,8 +86,8 @@ private[cyfra] object DSLCompiler: case gf: GetField[?, ?] => gf.resultSchema } ::: uniformSchemas).distinct val (structDefs, structCtx) = defineStructTypes(structsInCode, typedContext) - val structNames = getStructNames(structsInCode, structCtx) - val (decorations, uniformDefs, uniformContext) = initAndDecorateBuffers(buffersWithIndices, structCtx) + val (structNames, structNamesCtx) = getStructNames(structsInCode, structCtx) + val (decorations, uniformDefs, uniformContext) = initAndDecorateBuffers(buffersWithIndices, structNamesCtx) val (uniformStructDecorations, uniformStructInsns, uniformStructContext) = createAndInitUniformBlocks(uniformsWithIndices, uniformContext) val blockNames = getBlockNames(uniformContext, uniforms) val (inputDefs, inputContext) = createInvocationId(uniformStructContext) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala index fe3faacc..2542e1f8 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala @@ -29,13 +29,19 @@ private[cyfra] object GStructCompiler: ) } - def getStructNames(schemas: List[GStructSchema[?]], context: Context): List[Words] = - schemas.flatMap { schema => - val structName = schema.structTag.tag.shortName + def getStructNames(schemas: List[GStructSchema[?]], context: Context): (List[Words], Context) = + schemas.distinctBy(_.structTag).foldLeft((List.empty[Words], context)) { case ((wordsAcc, currCtx), schema) => + var structName = schema.structTag.tag.shortName + var nameSuffix = 0 + while currCtx.names.contains(structName) do + structName = s"${schema.structTag.tag.shortName}_$nameSuffix" + nameSuffix += 1 val structType = context.valueTypeMap(schema.structTag.tag) - Instruction(Op.OpName, List(ResultRef(structType), Text(structName))) :: schema.fields.zipWithIndex.map { case ((name, _, tag), i) => + val words = Instruction(Op.OpName, List(ResultRef(structType), Text(structName))) :: schema.fields.zipWithIndex.map { case ((name, _, tag), i) => Instruction(Op.OpMemberName, List(ResultRef(structType), IntWord(i), Text(name))) } + val updatedCtx = currCtx.copy(names = currCtx.names + structName) + (wordsAcc ::: words, updatedCtx) } private def sortSchemasDag(schemas: List[GStructSchema[?]]): List[GStructSchema[?]] = diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index 997c93b2..f9f86447 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -45,18 +45,6 @@ private[cyfra] object SpirvProgramCompiler: val (vars, nonVarsBody) = bubbleUpVars(body) val end = List( -// TODO Remove - Write is a part of GIO now -// Instruction( -// Op.OpAccessChain, -// List( -// ResultRef(codeCtx.uniformPointerMap(codeCtx.valueTypeMap(resultType.tag))), -// ResultRef(codeCtx.nextResultId), -// ResultRef(codeCtx.outBufferBlocks.head.blockVarRef), -// ResultRef(codeCtx.constRefs((Int32Tag, 0))), -// ResultRef(codeCtx.workerIndexRef), -// ), -// ), -// Instruction(Op.OpStore, List(ResultRef(codeCtx.nextResultId), ResultRef(codeCtx.exprRefs(tree.tree.treeid)))), Instruction(Op.OpReturn, List()), Instruction(Op.OpFunctionEnd, List()), ) @@ -128,21 +116,45 @@ private[cyfra] object SpirvProgramCompiler: (blockDecor, voidsDef ::: blockDef, voidCtx) def createAndInitBlocks(blocks: List[(GBuffer[?], Int)], context: Context): (List[Words], List[Words], Context) = + var membersVisited = Set[Int]() + var structsVisited = Set[Int]() val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { case ((decAcc, insnAcc, ctx), (buff, binding)) => val tpe = buff.tag val block = ArrayBufferBlock(ctx.nextResultId, ctx.nextResultId + 1, ctx.nextResultId + 2, ctx.nextResultId + 3, binding) - val decorationInstructions = List[Words]( - Instruction(Op.OpDecorate, List(ResultRef(block.memberArrayTypeRef), Decoration.ArrayStride, IntWord(typeStride(tpe)))), // OpDecorate %_runtimearr_X ArrayStride [typeStride(type)] - Instruction(Op.OpMemberDecorate, List(ResultRef(block.structTypeRef), IntWord(0), Decoration.Offset, IntWord(0))), // OpMemberDecorate %BufferX 0 Offset 0 - Instruction(Op.OpDecorate, List(ResultRef(block.structTypeRef), Decoration.BufferBlock)), // OpDecorate %BufferX BufferBlock + val (structDecoration, structDefinition) = if structsVisited.contains(block.structTypeRef) then + (Nil, Nil) + else + structsVisited += block.structTypeRef + ( + List( + Instruction(Op.OpMemberDecorate, List(ResultRef(block.structTypeRef), IntWord(0), Decoration.Offset, IntWord(0))), // OpMemberDecorate %BufferX 0 Offset 0 + Instruction(Op.OpDecorate, List(ResultRef(block.structTypeRef), Decoration.BufferBlock)), // OpDecorate %BufferX BufferBlock + ), + List( + Instruction(Op.OpTypeStruct, List(ResultRef(block.structTypeRef), IntWord(block.memberArrayTypeRef))), // %BufferX = OpTypeStruct %_runtimearr_X + ) + ) + + val (memberDecoration, memberDefinition) = if membersVisited.contains(block.memberArrayTypeRef) then + (Nil, Nil) + else + membersVisited += block.memberArrayTypeRef + ( + List( + Instruction(Op.OpDecorate, List(ResultRef(block.memberArrayTypeRef), Decoration.ArrayStride, IntWord(typeStride(tpe)))), // OpDecorate %_runtimearr_X ArrayStride [typeStride(type)] + ), + List( + Instruction(Op.OpTypeRuntimeArray, List(ResultRef(block.memberArrayTypeRef), IntWord(context.valueTypeMap(tpe.tag)))), // %_runtimearr_X = OpTypeRuntimeArray %[typeOf(tpe)] + ) + ) + + val decorationInstructions = memberDecoration ::: structDecoration ::: List[Words]( Instruction(Op.OpDecorate, List(ResultRef(block.blockVarRef), Decoration.DescriptorSet, IntWord(0))), // OpDecorate %_X DescriptorSet 0 Instruction(Op.OpDecorate, List(ResultRef(block.blockVarRef), Decoration.Binding, IntWord(block.binding))), // OpDecorate %_X Binding [binding] ) - val definitionInstructions = List[Words]( - Instruction(Op.OpTypeRuntimeArray, List(ResultRef(block.memberArrayTypeRef), IntWord(context.valueTypeMap(tpe.tag)))), // %_runtimearr_X = OpTypeRuntimeArray %[typeOf(tpe)] - Instruction(Op.OpTypeStruct, List(ResultRef(block.structTypeRef), IntWord(block.memberArrayTypeRef))), // %BufferX = OpTypeStruct %_runtimearr_X + val definitionInstructions = memberDefinition ::: structDefinition ::: List[Words]( Instruction(Op.OpTypePointer, List(ResultRef(block.blockPointerRef), StorageClass.Uniform, ResultRef(block.structTypeRef))), // %_ptr_Uniform_BufferX= OpTypePointer Uniform %BufferX Instruction(Op.OpVariable, List(ResultRef(block.blockPointerRef), ResultRef(block.blockVarRef), StorageClass.Uniform)), // %_X = OpVariable %_ptr_Uniform_X Uniform ) @@ -174,22 +186,26 @@ private[cyfra] object SpirvProgramCompiler: typeStride(t) .sum - def createAndInitUniformBlocks(schemas: List[(GUniform[?], Int)], ctx: Context): (List[Words], List[Words], Context) = + def createAndInitUniformBlocks(schemas: List[(GUniform[?], Int)], ctx: Context): (List[Words], List[Words], Context) = { + var decoratedOffsets = Set[Int]() schemas.foldLeft((List.empty[Words], List.empty[Words], ctx)) { case ((decorationsAcc, definitionsAcc, currentCtx), (uniform, binding)) => val schema = uniform.schema val uniformStructTypeRef = currentCtx.valueTypeMap(schema.structTag.tag) - val (offsetDecorations, _) = schema.fields.zipWithIndex.foldLeft[(List[Words], Int)](List.empty[Words], 0): - case ((acc, offset), ((name, fromExpr, tag), idx)) => - val stride = - if tag <:< schema.gStructTag then - val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] - totalStride(constructor.schema) - else typeStride(tag) - val offsetDecoration = Instruction(Op.OpMemberDecorate, List(ResultRef(uniformStructTypeRef), IntWord(idx), Decoration.Offset, IntWord(offset))) - (acc :+ offsetDecoration, offset + stride) - - val uniformBlockDecoration = Instruction(Op.OpDecorate, List(ResultRef(uniformStructTypeRef), Decoration.Block)) + val structDecorations = + if decoratedOffsets.contains(uniformStructTypeRef) then Nil + else + decoratedOffsets += uniformStructTypeRef + schema.fields.zipWithIndex.foldLeft[(List[Words], Int)](List.empty[Words], 0): + case ((acc, offset), ((name, fromExpr, tag), idx)) => + val stride = + if tag <:< schema.gStructTag then + val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] + totalStride(constructor.schema) + else typeStride(tag) + val offsetDecoration = Instruction(Op.OpMemberDecorate, List(ResultRef(uniformStructTypeRef), IntWord(idx), Decoration.Offset, IntWord(offset))) + (acc :+ offsetDecoration, offset + stride) + ._1 ::: List(Instruction(Op.OpDecorate, List(ResultRef(uniformStructTypeRef), Decoration.Block))) val uniformPointerUniformRef = currentCtx.nextResultId val uniformPointerUniform = @@ -201,7 +217,7 @@ private[cyfra] object SpirvProgramCompiler: val uniformDecorateDescriptorSet = Instruction(Op.OpDecorate, List(ResultRef(uniformVarRef), Decoration.DescriptorSet, IntWord(0))) val uniformDecorateBinding = Instruction(Op.OpDecorate, List(ResultRef(uniformVarRef), Decoration.Binding, IntWord(binding))) - val newDecorations = decorationsAcc ::: offsetDecorations ::: List(uniformDecorateDescriptorSet, uniformDecorateBinding, uniformBlockDecoration) + val newDecorations = decorationsAcc ::: structDecorations ::: List(uniformDecorateDescriptorSet, uniformDecorateBinding) val newDefinitions = definitionsAcc ::: List(uniformPointerUniform, uniformVar) val newCtx = currentCtx.copy( nextResultId = currentCtx.nextResultId + 2, @@ -212,6 +228,7 @@ private[cyfra] object SpirvProgramCompiler: (newDecorations, newDefinitions, newCtx) } + } val predefinedConsts = List((Int32Tag, 0), (UInt32Tag, 0), (Int32Tag, 1)) def defineConstants(exprs: List[E[?]], ctx: Context): (List[Words], Context) = diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala index 4d002c19..dec27507 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala @@ -10,10 +10,13 @@ import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.struct.GStruct.Empty import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.runtime.VkCyfraRuntime +import io.computenode.cyfra.spirvtools.{SpirvCross, SpirvDisassembler, SpirvToolsRunner} +import io.computenode.cyfra.spirvtools.SpirvTool.ToFile import io.computenode.cyfra.utility.Logger.logger import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil +import java.nio.file.Paths import scala.concurrent.ExecutionContext.Implicits.global import java.util.concurrent.atomic.AtomicInteger import scala.concurrent.{Await, Future} @@ -174,7 +177,10 @@ class RuntimeEnduranceTest extends munit.FunSuite: def runEnduranceTest(nRuns: Int): Unit = logger.info(s"Starting endurance test with ${nRuns} runs...") - given runtime: VkCyfraRuntime = VkCyfraRuntime() + given runtime: VkCyfraRuntime = VkCyfraRuntime( + spirvToolsRunner = SpirvToolsRunner( + crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))), + disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/dis.spvdis"))))) val bufferSize = 1280 val params = AddProgramParams(bufferSize, addA = 0, addB = 1) From c5d7da0cc84779108d324de177bc54730e286902 Mon Sep 17 00:00:00 2001 From: Szymon Date: Sun, 7 Sep 2025 18:47:49 +0200 Subject: [PATCH 39/59] Rebase & adjustments --- .../io/computenode/cyfra/spirv/Context.scala | 1 + .../cyfra/spirv/SpirvConstants.scala | 5 +- .../cyfra/spirv/compilers/DSLCompiler.scala | 23 +++++- .../cyfra/spirv/compilers/GIOCompiler.scala | 16 ++++ .../compilers/SpirvProgramCompiler.scala | 16 ++++ .../cyfra/core/layout/LayoutStruct.scala | 4 +- .../io/computenode/cyfra/dsl/gio/GIO.scala | 8 +- .../cyfra/e2e/fs2interop/Fs2Tests.scala | 23 ++++-- .../computenode/cyfra/fs2interop/GPipe.scala | 51 ++++++++----- .../cyfra/runtime/ExecutionHandler.scala | 69 ++++++++++++----- .../cyfra/runtime/VkAllocation.scala | 2 +- .../cyfra/vulkan/VulkanContext.scala | 2 +- .../cyfra/vulkan/core/Instance.scala | 76 +++++++++++++++++-- 13 files changed, 237 insertions(+), 59 deletions(-) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala index 62daf3d1..0312d9db 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala @@ -27,6 +27,7 @@ private[cyfra] case class Context( exprNames: Map[Int, String] = Map(), names: Set[String] = Set(), functions: Map[FnIdentifier, SprivFunction] = Map(), + stringLiterals: Map[String, Int] = Map() ): def joinNested(ctx: Context): Context = this.copy(nextResultId = ctx.nextResultId, exprNames = ctx.exprNames ++ this.exprNames, functions = ctx.functions ++ this.functions) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvConstants.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvConstants.scala index 6711afff..00a3f615 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvConstants.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvConstants.scala @@ -9,10 +9,13 @@ private[cyfra] object SpirvConstants: val BOUND_VARIABLE = "bound" val GLSL_EXT_NAME = "GLSL.std.450" + val NON_SEMANTIC_DEBUG_PRINTF = "NonSemantic.DebugPrintf" val GLSL_EXT_REF = 1 val TYPE_VOID_REF = 2 val VOID_FUNC_TYPE_REF = 3 val MAIN_FUNC_REF = 4 val GL_GLOBAL_INVOCATION_ID_REF = 5 val GL_WORKGROUP_SIZE_REF = 6 - val HEADER_REFS_TOP = 7 + val DEBUG_PRINTF_REF = 7 + + val HEADER_REFS_TOP = 8 diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala index 84252ca7..f5975295 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala @@ -31,7 +31,7 @@ private[cyfra] object DSLCompiler: pending match case Nil => acc case GIO.Pure(v) :: tail => - getAllExprsFlattened(tail, getAllExprsFlattened(v.tree, visitDetached), visitDetached) + getAllExprsFlattened(tail, getAllExprsFlattened(v.tree, visitDetached) ::: acc, visitDetached) case GIO.FlatMap(v, n) :: tail => getAllExprsFlattened(v :: n :: tail, acc, visitDetached) case GIO.Repeat(n, gio) :: tail => @@ -44,6 +44,9 @@ private[cyfra] object DSLCompiler: case WriteUniform(_, value) :: tail => val valueAllExprs = getAllExprsFlattened(value.tree, visitDetached) getAllExprsFlattened(tail, valueAllExprs ::: acc, visitDetached) + case GIO.Printf(_, args*) :: tail => + val argsAllExprs = args.flatMap(a => getAllExprsFlattened(a.tree, visitDetached)).toList + getAllExprsFlattened(tail, argsAllExprs ::: acc, visitDetached) // TODO: Not traverse same fn scopes for each fn call private def getAllExprsFlattened(root: E[?], visitDetached: Boolean): List[E[?]] = @@ -68,12 +71,26 @@ private[cyfra] object DSLCompiler: allScopesCache(root.treeid) = result result + // So far only used for printf + private def getAllStrings(pending: List[GIO[?]], acc: Set[String]): Set[String] = + pending match + case Nil => acc + case GIO.FlatMap(v, n) :: tail => + getAllStrings(v :: n :: tail, acc) + case GIO.Repeat(_, gio) :: tail => + getAllStrings(gio :: tail, acc) + case GIO.Printf(format, _*) :: tail => + getAllStrings(tail, acc + format) + case _ :: tail => getAllStrings(tail, acc) + def compile(bodyIo: GIO[?], bindings: List[GBinding[?]]): ByteBuffer = val allExprs = getAllExprsFlattened(List(bodyIo), Nil, visitDetached = true) val typesInCode = allExprs.map(_.tag).distinct val allTypes = (typesInCode ::: bindings.map(_.tag)).distinct def scalarTypes = allTypes.filter(_.tag <:< summon[Tag[Scalar]].tag) val (typeDefs, typedContext) = defineScalarTypes(scalarTypes, Context.initialContext) + val allStrings = getAllStrings(List(bodyIo), Set.empty) + val (stringDefs, ctxWithStrings) = defineStrings(allStrings.toList, typedContext) val (buffersWithIndices, uniformsWithIndices) = bindings.zipWithIndex.partition: case (_: GBuffer[?], _) => true case (_: GUniform[?], _) => false @@ -85,7 +102,7 @@ private[cyfra] object DSLCompiler: case cs: ComposeStruct[?] => cs.resultSchema case gf: GetField[?, ?] => gf.resultSchema } ::: uniformSchemas).distinct - val (structDefs, structCtx) = defineStructTypes(structsInCode, typedContext) + val (structDefs, structCtx) = defineStructTypes(structsInCode, ctxWithStrings) val (structNames, structNamesCtx) = getStructNames(structsInCode, structCtx) val (decorations, uniformDefs, uniformContext) = initAndDecorateBuffers(buffersWithIndices, structNamesCtx) val (uniformStructDecorations, uniformStructInsns, uniformStructContext) = createAndInitUniformBlocks(uniformsWithIndices, uniformContext) @@ -98,7 +115,7 @@ private[cyfra] object DSLCompiler: val nameDecorations = getNameDecorations(ctxWithFnDefs) val code: List[Words] = - SpirvProgramCompiler.headers ::: blockNames ::: nameDecorations ::: structNames ::: SpirvProgramCompiler.workgroupDecorations ::: + SpirvProgramCompiler.headers ::: stringDefs ::: blockNames ::: nameDecorations ::: structNames ::: SpirvProgramCompiler.workgroupDecorations ::: decorations ::: uniformStructDecorations ::: typeDefs ::: structDefs ::: fnTypeDefs ::: uniformDefs ::: uniformStructInsns ::: inputDefs ::: constDefs ::: varDefs ::: main ::: fnDefs diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala index dd1d853c..231d8f97 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala @@ -5,6 +5,7 @@ import io.computenode.cyfra.spirv.Context import io.computenode.cyfra.spirv.Opcodes.* import io.computenode.cyfra.dsl.binding.* import io.computenode.cyfra.dsl.gio.GIO.CurrentRepeatIndex +import io.computenode.cyfra.spirv.SpirvConstants.{DEBUG_PRINTF_REF, TYPE_VOID_REF} import io.computenode.cyfra.spirv.SpirvTypes.{GBooleanTag, Int32Tag, LInt32Tag} object GIOCompiler: @@ -125,6 +126,21 @@ object GIOCompiler: (acc ::: nInsts ::: preheader ::: header ::: bodyBlk ::: contBlk ::: mergeBlk, finalCtx) + case GIO.Printf(format, args*) => + val (argsInsts, ctxAfterArgs) = args.foldLeft((List.empty[Words], ctx)) { case ((instsAcc, cAcc), arg) => + val (argInsts, cAfterArg) = ExpressionCompiler.compileBlock(arg.tree, cAcc) + (instsAcc ::: argInsts, cAfterArg) + } + val argResults = args.map(a => ResultRef(ctxAfterArgs.exprRefs(a.tree.treeid))).toList + val printf = Instruction(Op.OpExtInst, List( + ResultRef(TYPE_VOID_REF), + ResultRef(ctxAfterArgs.nextResultId), + ResultRef(DEBUG_PRINTF_REF), + IntWord(1), + ResultRef(ctx.stringLiterals(format)), + ) ::: argResults) + (acc ::: argsInsts ::: List(printf), ctxAfterArgs.copy(nextResultId = ctxAfterArgs.nextResultId + 1)) + diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index f9f86447..ee523d35 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -74,7 +74,9 @@ private[cyfra] object SpirvProgramCompiler: WordVariable(BOUND_VARIABLE) :: // Bound: To be calculated Word(Array(0x00, 0x00, 0x00, 0x00)) :: // Schema: 0 Instruction(Op.OpCapability, List(Capability.Shader)) :: // OpCapability Shader + Instruction(Op.OpExtension, List(Text("SPV_KHR_non_semantic_info"))) :: // OpExtension "SPV_KHR_non_semantic_info" Instruction(Op.OpExtInstImport, List(ResultRef(GLSL_EXT_REF), Text(GLSL_EXT_NAME))) :: // OpExtInstImport "GLSL.std.450" + Instruction(Op.OpExtInstImport, List(ResultRef(DEBUG_PRINTF_REF), Text(NON_SEMANTIC_DEBUG_PRINTF))) :: // OpExtInstImport "NonSemantic.DebugPrintf" Instruction(Op.OpMemoryModel, List(AddressingModel.Logical, MemoryModel.GLSL450)) :: // OpMemoryModel Logical GLSL450 Instruction(Op.OpEntryPoint, List(ExecutionModel.GLCompute, ResultRef(MAIN_FUNC_REF), Text("main"), ResultRef(GL_GLOBAL_INVOCATION_ID_REF))) :: // OpEntryPoint GLCompute %MAIN_FUNC_REF "main" %GL_GLOBAL_INVOCATION_ID_REF Instruction(Op.OpExecutionMode, List(ResultRef(MAIN_FUNC_REF), ExecutionMode.LocalSize, IntWord(256), IntWord(1), IntWord(1))) :: // OpExecutionMode %4 LocalSize 128 1 1 @@ -185,6 +187,20 @@ private[cyfra] object SpirvProgramCompiler: case (_, _, t) => typeStride(t) .sum + + def defineStrings(strings: List[String], ctx: Context): (List[Words], Context) = + strings.foldLeft((List.empty[Words], ctx)): + case ((insnsAcc, currentCtx), str) => + if currentCtx.stringLiterals.contains(str) then + (insnsAcc, currentCtx) + else + val strRef = currentCtx.nextResultId + val strInsns = List( + Instruction(Op.OpString, List(ResultRef(strRef), Text(str))), + ) + val newCtx = currentCtx.copy(stringLiterals = currentCtx.stringLiterals + (str -> strRef), nextResultId = currentCtx.nextResultId + 1) + (insnsAcc ::: strInsns, newCtx) + def createAndInitUniformBlocks(schemas: List[(GUniform[?], Int)], ctx: Context): (List[Words], List[Words], Context) = { var decoratedOffsets = Set[Int]() diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala index 0703bbbb..76d8ffa8 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala @@ -59,14 +59,14 @@ object LayoutStruct: (tpe, ftype) match case ('[type t <: Value; t], '[type tg <: GBuffer[?]; tg]) => '{ - BufferRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }) + BufferRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using ${ tag.asExprOf[Tag[t]] }, ${ fromExpr.asExprOf[FromExpr[t]] }) } case ('[type t <: GStruct[?]; t], '[type tg <: GUniform[?]; tg]) => val structSchema = Expr.summon[GStructSchema[t]] match case Some(s) => s case None => report.errorAndAbort(s"Cannot summon GStructSchema for type") '{ - UniformRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using summon[Tag[t]], ${ fromExpr.asExprOf[FromExpr[t]] }, ${ structSchema }) + UniformRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using ${ tag.asExprOf[Tag[t]] }, ${ fromExpr.asExprOf[FromExpr[t]] }, ${ structSchema }) } val constructor = sym.primaryConstructor diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala index 9d5c5220..0448fcf0 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala @@ -29,6 +29,9 @@ object GIO: // TODO repeat that collects results case class Repeat(n: Int32, f: GIO[?]) extends GIO[Empty]: override def underlying: Empty = Empty() + + case class Printf(format: String, args: Value*) extends GIO[Empty]: + override def underlying: Empty = Empty() def pure[T <: Value](value: T): GIO[T] = Pure(value) @@ -42,8 +45,11 @@ object GIO: def write[T <: Value](buffer: GBuffer[T], index: Int32, value: T): GIO[Empty] = WriteBuffer(buffer, index, value) + + def printf(format: String, args: Value*): GIO[Empty] = + Printf(s"|$format", args*) - def when(cond: GBoolean)(thenCode: GIO[?]): GIO[Unit] = + def when(cond: GBoolean)(thenCode: GIO[?]): GIO[Empty] = val n = When.when(cond)(1: Int32).otherwise(0) repeat(n): _ => thenCode diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala index daba84cd..941ba3cc 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala @@ -1,12 +1,19 @@ package io.computenode.cyfra.e2e.fs2interop -import io.computenode.cyfra.core.archive.*, mem.*, GMem.fRGBA -import io.computenode.cyfra.dsl.{*, given}, algebra.VectorAlgebra -import io.computenode.cyfra.fs2interop.*, Bridge.given +import io.computenode.cyfra.core.archive.* +import mem.* +import GMem.fRGBA +import io.computenode.cyfra.dsl.{*, given} +import algebra.VectorAlgebra +import io.computenode.cyfra.fs2interop.* +import Bridge.given import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.runtime.VkCyfraRuntime - import fs2.{io as fs2io, *} +import _root_.io.computenode.cyfra.spirvtools.{SpirvCross, SpirvDisassembler, SpirvToolsRunner} +import _root_.io.computenode.cyfra.spirvtools.SpirvTool.ToFile + +import java.nio.file.Paths extension (f: fRGBA) def neg = (-f._1, -f._2, -f._3, -f._4) @@ -16,7 +23,13 @@ extension (f: fRGBA) Math.abs(f._1 - g._1) < eps && Math.abs(f._2 - g._2) < eps && Math.abs(f._3 - g._3) < eps && Math.abs(f._4 - g._4) < eps class Fs2Tests extends munit.FunSuite: - given cr: CyfraRuntime = VkCyfraRuntime() + given cr: CyfraRuntime = VkCyfraRuntime( + spirvToolsRunner = SpirvToolsRunner( + crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))), + disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/disassembled.spv"))) + ) + ) + test("fs2 through GPipe map, just ints"): val inSeq = (0 until 256).toSeq diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index cd61a423..77ceb323 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -1,11 +1,17 @@ package io.computenode.cyfra.fs2interop -import io.computenode.cyfra.core.{Allocation, layout}, layout.Layout +import io.computenode.cyfra.core.{Allocation, layout} +import layout.Layout import io.computenode.cyfra.core.{CyfraRuntime, GBufferRegion, GExecution, GProgram} -import io.computenode.cyfra.dsl.{*, given}, gio.GIO, binding.{GBuffer, GUniform, GBinding} +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.core.layout.LayoutBinding +import io.computenode.cyfra.core.layout.LayoutStruct +import gio.GIO +import binding.{GBinding, GBuffer, GUniform} import io.computenode.cyfra.spirv.SpirvTypes.typeStride -import struct.GStruct, GStruct.Empty, Empty.given - +import struct.GStruct +import GStruct.Empty +import Empty.given import fs2.* import java.nio.ByteBuffer import org.lwjgl.BufferUtils @@ -14,7 +20,7 @@ import izumi.reflect.Tag import scala.reflect.ClassTag object GPipe: - def map[F[_], C1 <: Value: FromExpr: Tag, C2 <: Value: FromExpr: Tag, S1: ClassTag, S2: ClassTag]( + def map[F[_], C1 <: Value: {FromExpr, Tag}, C2 <: Value: {FromExpr, Tag}, S1: ClassTag, S2: ClassTag]( f: C1 => C2, )(using cr: CyfraRuntime, bridge1: Bridge[C1, S1], bridge2: Bridge[C2, S2]): Pipe[F, S1, S2] = (stream: Stream[F, S1]) => @@ -27,11 +33,16 @@ object GPipe: val gProg = GProgram[Params, PLayout]( layout = params => PLayout(in = GBuffer[C1](params.inSize), out = GBuffer[C2](params.inSize)), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), - ): layout => + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / 256, 1, 1)), + )(layout => { val invocId = GIO.invocationId val element = GIO.read[C1](layout.in, invocId) - GIO.write[C2](layout.out, invocId, f(element)) + val res = f(element) + for + _ <- GIO.printf("Element %d -> %v4f", invocId, res) + _ <- GIO.write[C2](layout.out, invocId, res) + yield Empty() + }) val execution = GExecution[Params, PLayout]() .addProgram(gProg)(params => Params(params.inSize), layout => PLayout(layout.in, layout.out)) @@ -64,21 +75,24 @@ object GPipe: val predicateProgram = GProgram[PredParams, PredLayout]( layout = params => PredLayout(in = GBuffer[C](params.inSize), out = GBuffer[Int32](params.inSize)), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / 256, 1, 1)), ): layout => val invocId = GIO.invocationId val element = GIO.read[C](layout.in, invocId) val result = when(pred(element))(1: Int32).otherwise(0) - GIO.write[Int32](layout.out, invocId, result) + for + _ <- GIO.printf("Element %d -> %d", invocId, result) + _ <- GIO.write[Int32](layout.out, invocId, result) + yield Empty() // Prefix sum (inclusive), upsweep/downsweep case class ScanParams(inSize: Int, intervalSize: Int) case class ScanArgs(intervalSize: Int32) extends GStruct[ScanArgs] - case class ScanLayout(ints: GBuffer[Int32], intervalSize: GUniform[ScanArgs]) extends Layout + case class ScanLayout(ints: GBuffer[Int32], intervalSize: GUniform[ScanArgs] = GUniform.fromParams) extends Layout val upsweep = GProgram[ScanParams, ScanLayout]( layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize, 1, 1)), + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize / 256, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read val invocId = GIO.invocationId @@ -92,7 +106,7 @@ object GPipe: val downsweep = GProgram[ScanParams, ScanLayout]( layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize, 1, 1)), + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize / 256, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read val invocId = GIO.invocationId @@ -136,12 +150,13 @@ object GPipe: val compactProgram = GProgram[CompactParams, CompactLayout]( layout = params => CompactLayout(in = GBuffer[C](params.inSize), scan = GBuffer[Int32](params.inSize), out = GBuffer[C](params.inSize)), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize, 1, 1)), + dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / 256, 1, 1)), ): layout => val invocId = GIO.invocationId val element = GIO.read[C](layout.in, invocId) val prefixSum = GIO.read[Int32](layout.scan, invocId) for + _ <- GIO.printf("Element %d, prefix sum %d", invocId, prefixSum) _ <- GIO.when(invocId > 0): val prevScan = GIO.read[Int32](layout.scan, invocId - 1) GIO.when(prevScan < prefixSum): @@ -149,11 +164,11 @@ object GPipe: _ <- GIO.when(invocId === 0): GIO.when(prefixSum > 0): GIO.write(layout.out, invocId, element) - yield () + yield Empty() // connect all the layouts/executions into one case class FilterParams(inSize: Int, intervalSize: Int) - case class FilterLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C], intervalSize: GUniform[ScanArgs]) extends Layout + case class FilterLayout(in: GBuffer[C], scan: GBuffer[Int32], out: GBuffer[C]) extends Layout val filterExec = GExecution[FilterParams, FilterLayout]() .addProgram(predicateProgram)( @@ -163,7 +178,7 @@ object GPipe: .flatMap[FilterLayout, FilterParams]: filterLayout => scanExec .contramap[FilterLayout]: filterLayout => - ScanLayout(filterLayout.scan, filterLayout.intervalSize) + ScanLayout(filterLayout.scan) .contramapParams[FilterParams](filterParams => ScanParams(filterParams.inSize, filterParams.intervalSize)) .map(scanLayout => filterLayout) .flatMap[FilterLayout, FilterParams]: filterLayout => @@ -193,7 +208,7 @@ object GPipe: .flatMap: chunk => bridge.toByteBuffer(predBuf, chunk) region.runUnsafe( - init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf), intervalSize = GUniform()), + init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf)), onDone = layout => layout.out.read(compactBuf), ) val arr = bridge.fromByteBuffer(compactBuf, new Array[S](256)) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index d0ad3a5a..b87033ac 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -38,7 +38,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte val (result, shaderCalls) = interpret(execution, params, layout) val descriptorSets = shaderCalls.map: - case ShaderCall(pipeline, layout, _) => + case ShaderCall(pipeline, layout, _, _) => pipeline.pipelineLayout.sets .map(dsManager.allocate) .zip(layout) @@ -50,7 +50,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte val dispatches: Seq[Dispatch] = shaderCalls .zip(descriptorSets) .map: - case (ShaderCall(pipeline, layout, dispatch), sets) => + case (ShaderCall(pipeline, layout, dispatch, _), sets) => Dispatch(pipeline, layout, sets, dispatch) val (executeSteps, _) = dispatches.foldLeft((Seq.empty[ExecutionStep], Set.empty[GBinding[?]])): @@ -90,9 +90,8 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte case x: ExecutionBinding[?] => x case x: GBinding[?] => val e = ExecutionBinding(x)(using x.fromExpr, x.tag) - bindingsAcc.put(e, mutable.Buffer(x)) + bindingsAcc.put(e, mutable.Buffer(x)) // store only base contribution here e - mapper.fromBindings(res) // noinspection TypeParameterShadow @@ -125,33 +124,51 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte val layoutInit = val initProgram: InitProgramLayout = summon[VkAllocation].getInitProgramLayout program.layout(initProgram)(params) - lb.toBindings(layout) - .zip(lb.toBindings(layoutInit)) - .foreach: - case (binding, initBinding) => - bindingsAcc(binding).append(initBinding) + + val callInits: Map[GBinding[?], Seq[GBinding[?]]] = + lb + .toBindings(layout) + .zip(lb.toBindings(layoutInit)) + .groupMap(_._1)(_._2) + val dispatch = program.dispatch(layout, params) match case GProgram.DynamicDispatch(buffer, offset) => DispatchType.Indirect(buffer, offset) case GProgram.StaticDispatch(size) => DispatchType.Direct(size._1, size._2, size._3) // noinspection ScalaRedundantCast - (layout.asInstanceOf[RL], Seq(ShaderCall(shader.underlying, shader.shaderBindings(layout), dispatch))) + (layout.asInstanceOf[RL], Seq(ShaderCall(shader.underlying, shader.shaderBindings(layout), dispatch, callInits))) case _ => ??? val (rl, steps) = interpretImpl(execution, params, mockBindings(layout)) - val bingingToVk = bindingsAcc.map(x => (x._1, interpretBinding(x._1, x._2.toSeq))) + + val finalBindingForRl: mutable.Map[GBinding[?], GBinding[?]] = mutable.Map.empty val nextSteps = steps.map: - case ShaderCall(pipeline, layout, dispatch) => + case ShaderCall(pipeline, layout, dispatch, callInits) => val nextLayout = layout.map: _.map: - case Binding(binding, operation) => Binding(bingingToVk(binding), operation) + case Binding(binding, operation) => + val base = bindingsAcc.getOrElse(binding, mutable.Buffer.empty).toSeq + val extras = callInits.getOrElse(binding, Seq.empty) + val resolved = interpretBinding(binding, base ++ extras) + finalBindingForRl.update(binding, resolved) + Binding(resolved, operation) + val nextDispatch = dispatch match - case x: Direct => x - case Indirect(buffer, offset) => Indirect(bingingToVk(buffer), offset) - ShaderCall(pipeline, nextLayout, nextDispatch) + case x: DispatchType.Direct => x + case DispatchType.Indirect(buffer, offset) => + val base = bindingsAcc.getOrElse(buffer, mutable.Buffer.empty).toSeq + val extras = callInits.getOrElse(buffer, Seq.empty) + val resolved = interpretBinding(buffer, base ++ extras) + finalBindingForRl.update(buffer, resolved) + DispatchType.Indirect(resolved, offset) + + ShaderCall(pipeline, nextLayout, nextDispatch, Map.empty) val mapper = summon[LayoutBinding[RL]] - val res = mapper.fromBindings(mapper.toBindings(rl).map(bingingToVk.apply)) + val rlBindings = mapper.toBindings(rl).map: b => + finalBindingForRl.getOrElse(b, interpretBinding(b, bindingsAcc.getOrElse(b, mutable.Buffer.empty).toSeq)) + val res = mapper.fromBindings(rlBindings) + (res, nextSteps) private def interpretBinding(binding: GBinding[?], bindings: Seq[GBinding[?]])(using VkAllocation): GBinding[?] = @@ -227,13 +244,23 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte commandBuffer object ExecutionHandler: - case class ShaderCall(pipeline: ComputePipeline, layout: ShaderLayout, dispatch: DispatchType) + case class ShaderCall( + pipeline: ComputePipeline, + layout: ShaderLayout, + dispatch: DispatchType, + callInits: Map[GBinding[?], Seq[GBinding[?]]] // per-program contributions + ) sealed trait ExecutionStep - case class Dispatch(pipeline: ComputePipeline, layout: ShaderLayout, descriptorSets: Seq[DescriptorSet], dispatch: DispatchType) - extends ExecutionStep - case object PipelineBarrier extends ExecutionStep + case class Dispatch( + pipeline: ComputePipeline, + layout: ShaderLayout, + descriptorSets: Seq[DescriptorSet], + dispatch: DispatchType + ) extends ExecutionStep + + case object PipelineBarrier extends ExecutionStep sealed trait DispatchType object DispatchType: case class Direct(x: Int, y: Int, z: Int) extends DispatchType diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index 350f0369..dc878c5b 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -56,7 +56,7 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) if buff.remaining() % sizeOfT != 0 then ??? GBuffer[T](length).tap(_.write(buff)) - extension (buffers: GUniform.type) + extension (uniforms: GUniform.type) def apply[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}](buff: ByteBuffer): GUniform[T] = GUniform[T]().tap(_.write(buff)) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala index 9c8c99c6..e979d3ca 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala @@ -16,7 +16,7 @@ import scala.jdk.CollectionConverters.* */ private[cyfra] object VulkanContext: val ValidationLayer: String = "VK_LAYER_KHRONOS_validation" - private val ValidationLayers: Boolean = System.getProperty("io.computenode.cyfra.vulkan.validation", "false").toBoolean + private val ValidationLayers: Boolean = System.getProperty("io.computenode.cyfra.vulkan.validation", "true").toBoolean if Configuration.STACK_SIZE.get() < 100 then logger.warn(s"Small stack size. Increase with org.lwjgl.system.stackSize") private[cyfra] class VulkanContext: diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala index 43072840..812c14d6 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala @@ -8,11 +8,13 @@ import org.lwjgl.system.{MemoryStack, MemoryUtil} import org.lwjgl.system.MemoryUtil.NULL import org.lwjgl.vulkan.* import org.lwjgl.vulkan.EXTDebugReport.VK_EXT_DEBUG_REPORT_EXTENSION_NAME -import org.lwjgl.vulkan.EXTLayerSettings.VK_LAYER_SETTING_TYPE_BOOL32_EXT +import org.lwjgl.vulkan.EXTLayerSettings.{VK_LAYER_SETTING_TYPE_BOOL32_EXT, VK_LAYER_SETTING_TYPE_STRING_EXT, VK_LAYER_SETTING_TYPE_UINT32_EXT} import org.lwjgl.vulkan.KHRPortabilityEnumeration.{VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME} import org.lwjgl.vulkan.VK10.* +import org.lwjgl.vulkan.EXTValidationFeatures.* +import org.lwjgl.vulkan.EXTDebugUtils.* -import java.nio.ByteBuffer +import java.nio.{ByteBuffer, LongBuffer} import scala.collection.mutable import scala.jdk.CollectionConverters.given import scala.util.chaining.* @@ -21,7 +23,11 @@ import scala.util.chaining.* * MarconZet Created 13.04.2020 */ object Instance: - val ValidationLayersExtensions: Seq[String] = List(VK_EXT_DEBUG_REPORT_EXTENSION_NAME) + val ValidationLayersExtensions: Seq[String] = List( + VK_EXT_DEBUG_REPORT_EXTENSION_NAME, + VK_EXT_DEBUG_UTILS_EXTENSION_NAME, + VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME + ) val MoltenVkExtensions: Seq[String] = List(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) lazy val (extensions, layers): (Seq[String], Seq[String]) = pushStack: stack => @@ -69,7 +75,7 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj .ppEnabledLayerNames(ppEnabledLayerNames) if enableValidationLayers then - val layerSettings = VkLayerSettingEXT.calloc(1, stack) + val layerSettings = VkLayerSettingEXT.calloc(2, stack) layerSettings .get(0) .pLayerName(stack.ASCII(ValidationLayer)) @@ -77,13 +83,69 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj .`type`(VK_LAYER_SETTING_TYPE_BOOL32_EXT) .valueCount(1) .pValues(MemoryUtil.memByteBuffer(stack.ints(1))) + + layerSettings + .get(1) + .pLayerName(stack.ASCII(ValidationLayer)) + .pSettingName(stack.ASCII("printf_buffer_size")) + .`type`(VK_LAYER_SETTING_TYPE_UINT32_EXT) + .valueCount(1) + .pValues(MemoryUtil.memByteBuffer(stack.ints(1024 * 1024))) + + val layerSettingsCI = VkLayerSettingsCreateInfoEXT.calloc(stack).sType$Default().pSettings(layerSettings) - pCreateInfo.pNext(layerSettingsCI) + + val validationFeatures = VkValidationFeaturesEXT.calloc(stack) + .sType$Default() + .pEnabledValidationFeatures(stack.ints(VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT)) + .pNext(0) + + layerSettingsCI.pNext(validationFeatures.address()) + pCreateInfo.pNext(layerSettingsCI.address()) val pInstance = stack.mallocPointer(1) check(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance") new VkInstance(pInstance.get(0), pCreateInfo) + protected val debugMessenger: Option[LongBuffer] = + if enableValidationLayers then pushStack: stack => + Some: + val callback = new VkDebugUtilsMessengerCallbackEXT(): + override def invoke(messageSeverity: Int, messageTypes: Int, pCallbackData: Long, pUserData: Long): Int = + val message = VkDebugUtilsMessengerCallbackDataEXT.create(pCallbackData).pMessageString() + val debugMessage = "[VK DEBUG] " + message.split("\\|").last + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0 then + logger.error(debugMessage) + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0 then + logger.warn(debugMessage) + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0 then + logger.info(debugMessage) + else + logger.debug(debugMessage) + VK_FALSE + + + val debugMessengerCreate = VkDebugUtilsMessengerCreateInfoEXT.calloc(stack) + .sType$Default() + .messageSeverity( + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT + ) + .messageType( + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT + ) + .pfnUserCallback(callback) + + val debugMessengerBuff = stack.callocLong(1) + check(vkCreateDebugUtilsMessengerEXT( + handle, + debugMessengerCreate, + null, + debugMessengerBuff + )) + debugMessengerBuff + else None + + lazy val enabledLayers: Seq[String] = List .empty[String] .pipe: x => @@ -93,8 +155,10 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj x else x - override protected def close(): Unit = + override protected def close(): Unit = { + debugMessenger.foreach(b => vkDestroyDebugUtilsMessengerEXT(handle, b.get(0), null)) vkDestroyInstance(handle, null) + } private def getInstanceExtensions(stack: MemoryStack) = val n = stack.callocInt(1) From aa91317208858b45f7638c65c57ce7cafbd9f5ce Mon Sep 17 00:00:00 2001 From: Szymon Date: Mon, 8 Sep 2025 00:48:20 +0200 Subject: [PATCH 40/59] More adjustments and printf --- .../cyfra/spirv/compilers/GIOCompiler.scala | 16 ++-- .../cyfra/e2e/fs2interop/Fs2Tests.scala | 9 +- .../computenode/cyfra/fs2interop/Bridge.scala | 30 ++++-- .../computenode/cyfra/fs2interop/GPipe.scala | 26 +++-- .../cyfra/runtime/VkAllocation.scala | 7 +- .../cyfra/vulkan/command/CommandPool.scala | 2 + .../cyfra/vulkan/core/Instance.scala | 95 +++++++++++-------- .../cyfra/vulkan/memory/Buffer.scala | 1 - 8 files changed, 113 insertions(+), 73 deletions(-) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala index 231d8f97..5d54fc2b 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala @@ -39,9 +39,8 @@ object GIOCompiler: case GIO.FlatMap(v, n) => val (vInsts, ctxAfterV) = compileGio(v, ctx, acc) compileGio(n, ctxAfterV, vInsts) - + case GIO.Repeat(n, f) => - // Compile 'n' first (so we can use its id in the comparison) val (nInsts, ctxWithN) = ExpressionCompiler.compileBlock(n.tree, ctx) @@ -68,7 +67,7 @@ object GIOCompiler: nextResultId = baseId + 8, exprRefs = ctxWithN.exprRefs + (CurrentRepeatIndex.treeid -> phiId) ) - val (bodyInsts, ctxAfterBody) = compileGio(f, bodyCtx) + val (bodyInsts, ctxAfterBody) = compileGio(f, bodyCtx) // ← Capture the context after body compilation // Preheader: close current block and jump to header through a dedicated block val preheader = List( @@ -118,14 +117,13 @@ object GIOCompiler: Instruction(Op.OpLabel, List(ResultRef(mergeId))) ) - val finalNextId = math.max(ctxAfterBody.nextResultId, addId + 1) - val finalCtx = ctxAfterBody.copy( - nextResultId = finalNextId, - exprRefs = ctxAfterBody.exprRefs - CurrentRepeatIndex.treeid - ) + // Use the highest nextResultId to avoid ID collisions + val finalNextId = math.max(ctxAfterBody.nextResultId, addId + 1) // ← Use ctxAfterBody.nextResultId + // Use ctxWithN as base to prevent loop-local values from being referenced outside + val finalCtx = ctxWithN.copy(nextResultId = finalNextId) (acc ::: nInsts ::: preheader ::: header ::: bodyBlk ::: contBlk ::: mergeBlk, finalCtx) - + case GIO.Printf(format, args*) => val (argsInsts, ctxAfterArgs) = args.foldLeft((List.empty[Words], ctx)) { case ((instsAcc, cAcc), arg) => val (argInsts, cAfterArg) = ExpressionCompiler.compileBlock(arg.tree, cAcc) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala index 941ba3cc..7c8414c9 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala @@ -23,13 +23,16 @@ extension (f: fRGBA) Math.abs(f._1 - g._1) < eps && Math.abs(f._2 - g._2) < eps && Math.abs(f._3 - g._3) < eps && Math.abs(f._4 - g._4) < eps class Fs2Tests extends munit.FunSuite: - given cr: CyfraRuntime = VkCyfraRuntime( + given cr: VkCyfraRuntime = VkCyfraRuntime( spirvToolsRunner = SpirvToolsRunner( crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))), disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/disassembled.spv"))) ) ) + override def afterAll(): Unit = + //cr.close() + super.afterAll() test("fs2 through GPipe map, just ints"): val inSeq = (0 until 256).toSeq @@ -43,11 +46,13 @@ class Fs2Tests extends munit.FunSuite: assert(res == exp, s"Expected $exp, got $res") test("fs2 through GPipe map, floats and vectors"): - val inSeq = (0 to 255).map(_.toFloat).toSeq + val n = 16 + val inSeq = (0 to (n * 256 - 1)).map(_.toFloat).toSeq val stream = Stream.emits(inSeq) val pipe = GPipe.map[Pure, Float32, Vec4[Float32], Float, fRGBA](f => (f, f + 1f, f + 2f, f + 3f)) val result = stream.through(pipe).compile.toList val expected = inSeq.map(f => (f, f + 1f, f + 2f, f + 3f)) + println("DONE!") result .zip(expected) .foreach: (res, exp) => diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala index 41d366c3..b148a53b 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala @@ -1,13 +1,12 @@ +// scala package io.computenode.cyfra.fs2interop import io.computenode.cyfra.core.archive.mem.GMem.fRGBA import io.computenode.cyfra.dsl.* - import fs2.* -import java.nio.ByteBuffer -import org.lwjgl.BufferUtils -import izumi.reflect.Tag +import java.nio.{ByteBuffer, ByteOrder} +import izumi.reflect.Tag import scala.reflect.ClassTag trait Bridge[CyfraType <: Value: FromExpr: Tag, ScalaType: ClassTag]: @@ -17,22 +16,33 @@ trait Bridge[CyfraType <: Value: FromExpr: Tag, ScalaType: ClassTag]: object Bridge: given Bridge[Int32, Int]: def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[Int]): ByteBuffer = - inBuf.asIntBuffer().put(chunk.toArray[Int]).flip() + inBuf.clear().order(ByteOrder.nativeOrder()) + val ib = inBuf.asIntBuffer() + ib.put(chunk.toArray[Int]) + inBuf.position(ib.position() * java.lang.Integer.BYTES).flip() inBuf def fromByteBuffer(outBuf: ByteBuffer, arr: Array[Int]): Array[Int] = - outBuf.asIntBuffer().get(arr).flip() + outBuf.order(ByteOrder.nativeOrder()) + outBuf.asIntBuffer().get(arr) + outBuf.rewind() arr given Bridge[Float32, Float]: def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[Float]): ByteBuffer = - inBuf.asFloatBuffer().put(chunk.toArray[Float]).flip() + inBuf.clear().order(ByteOrder.nativeOrder()) + val fb = inBuf.asFloatBuffer() + fb.put(chunk.toArray[Float]) + inBuf.position(fb.position() * java.lang.Float.BYTES).flip() inBuf def fromByteBuffer(outBuf: ByteBuffer, arr: Array[Float]): Array[Float] = - outBuf.asFloatBuffer().get(arr).flip() + outBuf.order(ByteOrder.nativeOrder()) + outBuf.asFloatBuffer().get(arr) + outBuf.rewind() arr given Bridge[Vec4[Float32], fRGBA]: def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[fRGBA]): ByteBuffer = + inBuf.clear().order(ByteOrder.nativeOrder()) val vecs = chunk.toArray[fRGBA] vecs.foreach: case (x, y, z, a) => @@ -46,7 +56,7 @@ object Bridge: def fromByteBuffer(outBuf: ByteBuffer, arr: Array[fRGBA]): Array[fRGBA] = val res = outBuf.asFloatBuffer() for i <- 0 until arr.size do arr(i) = (res.get(), res.get(), res.get(), res.get()) - outBuf.flip() + outBuf.rewind() arr given Bridge[GBoolean, Boolean]: @@ -55,4 +65,4 @@ object Bridge: inBuf def fromByteBuffer(outBuf: ByteBuffer, arr: Array[Boolean]): Array[Boolean] = outBuf.get(arr.asInstanceOf[Array[Byte]]).flip() - arr + arr \ No newline at end of file diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 77ceb323..95c86efc 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -38,8 +38,7 @@ object GPipe: val invocId = GIO.invocationId val element = GIO.read[C1](layout.in, invocId) val res = f(element) - for - _ <- GIO.printf("Element %d -> %v4f", invocId, res) + for _ <- GIO.write[C2](layout.out, invocId, res) yield Empty() }) @@ -57,10 +56,15 @@ object GPipe: val outBuf = BufferUtils.createByteBuffer(params.inSize * outTypeSize) stream - .chunkMin(params.inSize) + .chunkN(params.inSize) .flatMap: chunk => bridge1.toByteBuffer(inBuf, chunk) - region.runUnsafe(init = PLayout(in = GBuffer[C1](inBuf), out = GBuffer[C2](outBuf)), onDone = layout => layout.out.read(outBuf)) + region.runUnsafe(init = PLayout( + in = GBuffer[C1](inBuf), + out = GBuffer[C2](outBuf)), + onDone = layout => + layout.out.read(outBuf) + ) Stream.emits(bridge2.fromByteBuffer(outBuf, new Array[S2](params.inSize))) // Overload for convenient single type version @@ -81,7 +85,7 @@ object GPipe: val element = GIO.read[C](layout.in, invocId) val result = when(pred(element))(1: Int32).otherwise(0) for - _ <- GIO.printf("Element %d -> %d", invocId, result) + _ <- GIO.printf("Pred: Element %d -> %d", invocId, result) _ <- GIO.write[Int32](layout.out, invocId, result) yield Empty() @@ -102,7 +106,10 @@ object GPipe: val oldValue = GIO.read[Int32](layout.ints, end) val addValue = GIO.read[Int32](layout.ints, mid) val newValue = oldValue + addValue - GIO.write[Int32](layout.ints, end, newValue) + for + _ <- GIO.printf("Upsweep: invocId %d, root %d, mid %d, end %d, oldValue %d, addValue %d, newValue %d", invocId, root, mid, end, oldValue, addValue, newValue) + _ <- GIO.write[Int32](layout.ints, end, newValue) + yield Empty() val downsweep = GProgram[ScanParams, ScanLayout]( layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), @@ -115,7 +122,10 @@ object GPipe: val oldValue = GIO.read[Int32](layout.ints, mid) val addValue = when(end > 0)(GIO.read[Int32](layout.ints, end)).otherwise(0) val newValue = oldValue + addValue - GIO.write[Int32](layout.ints, mid, newValue) + for + _ <- GIO.printf("Downsweep: invocId %d, end %d, mid %d, oldValue %d, addValue %d, newValue %d", invocId, end, mid, oldValue, addValue, newValue) + _ <- GIO.write[Int32](layout.ints, mid, newValue) + yield Empty() // Stitch together many upsweep / downsweep program phases recursively @annotation.tailrec @@ -204,7 +214,7 @@ object GPipe: val compactBuf = BufferUtils.createByteBuffer(filterParams.inSize * typeSize) stream - .chunkMin(filterParams.inSize) + .chunkN(filterParams.inSize) .flatMap: chunk => bridge.toByteBuffer(predBuf, chunk) region.runUnsafe( diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index dc878c5b..8cb67f8b 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -50,10 +50,11 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) def apply[T <: Value: {Tag, FromExpr}](length: Int): GBuffer[T] = VkBuffer[T](length).tap(bindings += _) - def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] = + def apply[T <: Value : {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] = val sizeOfT = typeStride(summon[Tag[T]]) - val length = buff.remaining() / sizeOfT - if buff.remaining() % sizeOfT != 0 then ??? + val length = buff.capacity() / sizeOfT + if buff.capacity() % sizeOfT != 0 then + throw new IllegalArgumentException(s"ByteBuffer size ${buff.capacity()} is not a multiple of element size $sizeOfT") GBuffer[T](length).tap(_.write(buff)) extension (uniforms: GUniform.type) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala index 3db65668..fe0d0636 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala @@ -43,6 +43,7 @@ private[cyfra] abstract class CommandPool private (flags: Int, val queue: Queue) val commandBuffer = beginSingleTimeCommands() block(commandBuffer) endSingleTimeCommands(commandBuffer).block().destroy() + //vkDeviceWaitIdle(device.get) freeCommandBuffer(commandBuffer) private def beginSingleTimeCommands(): VkCommandBuffer = @@ -74,6 +75,7 @@ private[cyfra] abstract class CommandPool private (flags: Int, val queue: Queue) val pointerBuffer = stack.callocPointer(commandBuffer.length) commandBuffer.foreach(pointerBuffer.put) pointerBuffer.flip() + vkDeviceWaitIdle(device.get) vkFreeCommandBuffers(device.get, commandPool, pointerBuffer) protected def close(): Unit = diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala index 812c14d6..a1680c0e 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala @@ -90,61 +90,77 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj .pSettingName(stack.ASCII("printf_buffer_size")) .`type`(VK_LAYER_SETTING_TYPE_UINT32_EXT) .valueCount(1) - .pValues(MemoryUtil.memByteBuffer(stack.ints(1024 * 1024))) + .pValues(MemoryUtil.memByteBuffer(stack.ints(1024*1024))) val layerSettingsCI = VkLayerSettingsCreateInfoEXT.calloc(stack).sType$Default().pSettings(layerSettings) val validationFeatures = VkValidationFeaturesEXT.calloc(stack) .sType$Default() - .pEnabledValidationFeatures(stack.ints(VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT)) + .pEnabledValidationFeatures(stack.ints( + VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT, + )) + .pNext(0) + + val validationFeaturesPCreate = VkValidationFeaturesEXT.calloc(stack) + .sType$Default() + .pEnabledValidationFeatures(stack.ints( + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + )) .pNext(0) layerSettingsCI.pNext(validationFeatures.address()) pCreateInfo.pNext(layerSettingsCI.address()) + validationFeaturesPCreate.pNext(validationFeaturesPCreate.address()) val pInstance = stack.mallocPointer(1) check(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance") new VkInstance(pInstance.get(0), pCreateInfo) - protected val debugMessenger: Option[LongBuffer] = - if enableValidationLayers then pushStack: stack => - Some: - val callback = new VkDebugUtilsMessengerCallbackEXT(): - override def invoke(messageSeverity: Int, messageTypes: Int, pCallbackData: Long, pUserData: Long): Int = - val message = VkDebugUtilsMessengerCallbackDataEXT.create(pCallbackData).pMessageString() - val debugMessage = "[VK DEBUG] " + message.split("\\|").last - if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0 then - logger.error(debugMessage) - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0 then - logger.warn(debugMessage) - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0 then - logger.info(debugMessage) - else - logger.debug(debugMessage) - VK_FALSE - - - val debugMessengerCreate = VkDebugUtilsMessengerCreateInfoEXT.calloc(stack) - .sType$Default() - .messageSeverity( - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT - ) - .messageType( - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT - ) - .pfnUserCallback(callback) - - val debugMessengerBuff = stack.callocLong(1) - check(vkCreateDebugUtilsMessengerEXT( - handle, - debugMessengerCreate, - null, - debugMessengerBuff - )) - debugMessengerBuff + protected val callback: Option[VkDebugUtilsMessengerCallbackEXT] = + if enableValidationLayers then Some: + new VkDebugUtilsMessengerCallbackEXT(): + override def invoke(messageSeverity: Int, messageTypes: Int, pCallbackData: Long, pUserData: Long): Int = + val message = VkDebugUtilsMessengerCallbackDataEXT.create(pCallbackData).pMessageString() + val debugMessage = "[VK DEBUG] " + message.split("\\|").last + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0 then + logger.error(debugMessage) + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0 then + logger.warn(debugMessage) + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0 then + logger.info(debugMessage) + else + logger.debug(debugMessage) + VK_FALSE else None + protected val debugMessenger: Option[LongBuffer] = callback.map: c => + pushStack: stack => + val debugMessengerCreate = VkDebugUtilsMessengerCreateInfoEXT.calloc(1) + .sType$Default() + .messageSeverity( + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT + ) + .messageType( + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT + ) + .pfnUserCallback(c) + + val debugMessengerBuff = stack.callocLong(1) + check(vkCreateDebugUtilsMessengerEXT( + handle, + debugMessengerCreate.get(0), + null, + debugMessengerBuff + )) + debugMessengerBuff + lazy val enabledLayers: Seq[String] = List .empty[String] @@ -155,10 +171,9 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj x else x - override protected def close(): Unit = { + override protected def close(): Unit = debugMessenger.foreach(b => vkDestroyDebugUtilsMessengerEXT(handle, b.get(0), null)) vkDestroyInstance(handle, null) - } private def getInstanceExtensions(stack: MemoryStack) = val n = stack.callocInt(1) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala index 963aa1cd..78b99dc4 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala @@ -57,7 +57,6 @@ object Buffer: def copyTo(dst: ByteBuffer, srcOffset: Int): Unit = pushStack: stack => vmaCopyAllocationToMemory(allocator.get, allocation, srcOffset, dst) - def copyFrom(src: ByteBuffer, dstOffset: Int): Unit = pushStack: stack => vmaCopyMemoryToAllocation(allocator.get, src, allocation, dstOffset) From 6354e4214ae56383f3ad3f64b210b3131da631f2 Mon Sep 17 00:00:00 2001 From: Szymon Date: Mon, 8 Sep 2025 01:06:50 +0200 Subject: [PATCH 41/59] Works!!! --- .../scala/io/computenode/cyfra/fs2interop/GPipe.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 95c86efc..492a4d7d 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -33,7 +33,7 @@ object GPipe: val gProg = GProgram[Params, PLayout]( layout = params => PLayout(in = GBuffer[C1](params.inSize), out = GBuffer[C2](params.inSize)), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / 256, 1, 1)), + dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize / 256f).toInt, 1, 1)), )(layout => { val invocId = GIO.invocationId val element = GIO.read[C1](layout.in, invocId) @@ -79,7 +79,7 @@ object GPipe: val predicateProgram = GProgram[PredParams, PredLayout]( layout = params => PredLayout(in = GBuffer[C](params.inSize), out = GBuffer[Int32](params.inSize)), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / 256, 1, 1)), + dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize.toFloat / 256).toInt, 1, 1)), ): layout => val invocId = GIO.invocationId val element = GIO.read[C](layout.in, invocId) @@ -96,7 +96,7 @@ object GPipe: val upsweep = GProgram[ScanParams, ScanLayout]( layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize / 256, 1, 1)), + dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize.toFloat / params.intervalSize / 256).toInt, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read val invocId = GIO.invocationId @@ -113,7 +113,7 @@ object GPipe: val downsweep = GProgram[ScanParams, ScanLayout]( layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / params.intervalSize / 256, 1, 1)), + dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize.toFloat / params.intervalSize / 256).toInt, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read val invocId = GIO.invocationId @@ -160,7 +160,7 @@ object GPipe: val compactProgram = GProgram[CompactParams, CompactLayout]( layout = params => CompactLayout(in = GBuffer[C](params.inSize), scan = GBuffer[Int32](params.inSize), out = GBuffer[C](params.inSize)), - dispatch = (layout, params) => GProgram.StaticDispatch((params.inSize / 256, 1, 1)), + dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize.toFloat / 256).toInt, 1, 1)), ): layout => val invocId = GIO.invocationId val element = GIO.read[C](layout.in, invocId) From a052ba2265802ea7b6cb8e4c07d16f3ca825bae3 Mon Sep 17 00:00:00 2001 From: Szymon Date: Mon, 8 Sep 2025 21:34:17 +0200 Subject: [PATCH 42/59] Improvements --- .../cyfra/e2e/fs2interop/Fs2Tests.scala | 9 +-- .../computenode/cyfra/fs2interop/GPipe.scala | 62 +++++++++++-------- .../cyfra/runtime/VkCyfraRuntime.scala | 15 +++-- .../cyfra/vulkan/command/CommandPool.scala | 4 +- 4 files changed, 51 insertions(+), 39 deletions(-) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala index 7c8414c9..289426ec 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala @@ -47,7 +47,7 @@ class Fs2Tests extends munit.FunSuite: test("fs2 through GPipe map, floats and vectors"): val n = 16 - val inSeq = (0 to (n * 256 - 1)).map(_.toFloat).toSeq + val inSeq = (0 until n * 256).map(_.toFloat) val stream = Stream.emits(inSeq) val pipe = GPipe.map[Pure, Float32, Vec4[Float32], Float, fRGBA](f => (f, f + 1f, f + 2f, f + 3f)) val result = stream.through(pipe).compile.toList @@ -59,11 +59,12 @@ class Fs2Tests extends munit.FunSuite: assert(res.close(exp)(0.001f), s"Expected $exp, got $res") test("fs2 through GPipe filter, just ints"): - val inSeq = (0 until 256).toSeq + val n = 16 + val inSeq = (0 until n * 256) val stream = Stream.emits(inSeq) - val pipe = GPipe.filter[Pure, Int32, Int](_.mod(2) === 0) + val pipe = GPipe.filter[Pure, Int32, Int](_.mod(7) === 0) val result = stream.through(pipe).compile.toList - val expected = inSeq.filter(_ % 2 == 0) + val expected = inSeq.filter(_ % 7 == 0) result .zip(expected) .foreach: (res, exp) => diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 492a4d7d..c79946be 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -73,6 +73,8 @@ object GPipe: def filter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: Bridge[C, S]): Pipe[F, S, S] = (stream: Stream[F, S]) => + val chunkInSize = 256 + // Predicate mapping case class PredParams(inSize: Int) case class PredLayout(in: GBuffer[C], out: GBuffer[Int32]) extends Layout @@ -99,33 +101,35 @@ object GPipe: dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize.toFloat / params.intervalSize / 256).toInt, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read - val invocId = GIO.invocationId - val root = invocId * size - val mid = root + (size / 2) - 1 - val end = root + size - 1 - val oldValue = GIO.read[Int32](layout.ints, end) - val addValue = GIO.read[Int32](layout.ints, mid) - val newValue = oldValue + addValue - for - _ <- GIO.printf("Upsweep: invocId %d, root %d, mid %d, end %d, oldValue %d, addValue %d, newValue %d", invocId, root, mid, end, oldValue, addValue, newValue) - _ <- GIO.write[Int32](layout.ints, end, newValue) - yield Empty() + GIO.when(GIO.invocationId < ((chunkInSize: Int32) / size)): + val invocId = GIO.invocationId + val root = invocId * size + val mid = root + (size / 2) - 1 + val end = root + size - 1 + val oldValue = GIO.read[Int32](layout.ints, end) + val addValue = GIO.read[Int32](layout.ints, mid) + val newValue = oldValue + addValue + for + _ <- GIO.printf("Upsweep: invocId %d, root %d, size %d, mid %d, end %d, oldValue %d, addValue %d, newValue %d", invocId, root, size, mid, end, oldValue, addValue, newValue) + _ <- GIO.write[Int32](layout.ints, end, newValue) + yield Empty() val downsweep = GProgram[ScanParams, ScanLayout]( layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize.toFloat / params.intervalSize / 256).toInt, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read - val invocId = GIO.invocationId - val end = invocId * size - 1 // if invocId = 0, this is -1 (out of bounds) - val mid = end + (size / 2) - val oldValue = GIO.read[Int32](layout.ints, mid) - val addValue = when(end > 0)(GIO.read[Int32](layout.ints, end)).otherwise(0) - val newValue = oldValue + addValue - for - _ <- GIO.printf("Downsweep: invocId %d, end %d, mid %d, oldValue %d, addValue %d, newValue %d", invocId, end, mid, oldValue, addValue, newValue) - _ <- GIO.write[Int32](layout.ints, mid, newValue) - yield Empty() + GIO.when(GIO.invocationId < ((chunkInSize: Int32) / size)): + val invocId = GIO.invocationId + val end = invocId * size - 1 // if invocId = 0, this is -1 (out of bounds) + val mid = end + (size / 2) + val oldValue = GIO.read[Int32](layout.ints, mid) + val addValue = when(end > 0)(GIO.read[Int32](layout.ints, end)).otherwise(0) + val newValue = oldValue + addValue + for + _ <- GIO.printf("Downsweep: invocId %d, end %d, mid %d, oldValue %d, addValue %d, newValue %d", invocId, end, mid, oldValue, addValue, newValue) + _ <- GIO.write[Int32](layout.ints, mid, newValue) + yield Empty() // Stitch together many upsweep / downsweep program phases recursively @annotation.tailrec @@ -199,7 +203,7 @@ object GPipe: .map(compactLayout => filterLayout) // finally setup buffers, region, parameters, and run the program - val filterParams = FilterParams(256, 2) + val filterParams = FilterParams(chunkInSize, 2) val region = GBufferRegion .allocate[FilterLayout] .map: filterLayout => @@ -210,16 +214,20 @@ object GPipe: // these are allocated once, reused for many chunks val predBuf = BufferUtils.createByteBuffer(filterParams.inSize * typeSize) - val scanBuf = BufferUtils.createByteBuffer(filterParams.inSize * intSize) + val filteredCount = BufferUtils.createByteBuffer(intSize) val compactBuf = BufferUtils.createByteBuffer(filterParams.inSize * typeSize) stream - .chunkN(filterParams.inSize) + .chunkN(chunkInSize) .flatMap: chunk => bridge.toByteBuffer(predBuf, chunk) region.runUnsafe( - init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](scanBuf), out = GBuffer[C](compactBuf)), - onDone = layout => layout.out.read(compactBuf), + init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](filterParams.inSize), out = GBuffer[C](filterParams.inSize)), + onDone = layout => { + layout.scan.read(filteredCount, (filterParams.inSize - 2) * intSize) + layout.out.read(compactBuf) + } ) - val arr = bridge.fromByteBuffer(compactBuf, new Array[S](256)) + val filteredN = filteredCount.getInt(0) + val arr = bridge.fromByteBuffer(compactBuf, new Array[S](filteredN)) Stream.emits(arr) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala index c6383665..e38648f4 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala @@ -16,14 +16,17 @@ class VkCyfraRuntime(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()) ex private val shaderCache = mutable.Map[GProgram[?, ?], VkShader[?]]() private[cyfra] def getOrLoadProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}](program: GProgram[Params, L]): VkShader[L] = synchronized: - val spirvProgram = program match - case p: GioProgram[?, ?] => compile(p) - case p: SpirvProgram[?, ?] => p - case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") + if (shaderCache.contains(program)) then + shaderCache(program).asInstanceOf[VkShader[L]] + else + val spirvProgram = program match + case p: GioProgram[?, ?] => compile(p) + case p: SpirvProgram[?, ?] => p + case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") - shaderCache.getOrElseUpdate(program, VkShader(spirvProgram)).asInstanceOf[VkShader[L]] + shaderCache.getOrElseUpdate(program, VkShader(spirvProgram)).asInstanceOf[VkShader[L]] - private def compile[Params, L <: Layout: {LayoutBinding as lbinding, LayoutStruct as lstruct}](program: GioProgram[Params, L]): SpirvProgram[Params, L] = + private def compile[Params, L <: Layout: {LayoutBinding as lbinding, LayoutStruct as lstruct}](program: GioProgram[Params, L]): SpirvProgram[Params, L] = val GioProgram(_, layout, dispatch, _) = program val bindings = lbinding.toBindings(lstruct.layoutRef).toList val compiled = DSLCompiler.compile(program.body(summon[LayoutStruct[L]].layoutRef), bindings) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala index fe0d0636..863770cf 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala @@ -43,7 +43,6 @@ private[cyfra] abstract class CommandPool private (flags: Int, val queue: Queue) val commandBuffer = beginSingleTimeCommands() block(commandBuffer) endSingleTimeCommands(commandBuffer).block().destroy() - //vkDeviceWaitIdle(device.get) freeCommandBuffer(commandBuffer) private def beginSingleTimeCommands(): VkCommandBuffer = @@ -75,7 +74,8 @@ private[cyfra] abstract class CommandPool private (flags: Int, val queue: Queue) val pointerBuffer = stack.callocPointer(commandBuffer.length) commandBuffer.foreach(pointerBuffer.put) pointerBuffer.flip() - vkDeviceWaitIdle(device.get) + // TODO remove vkQueueWaitIdle, but currently crashes without it - Likely the printf debug buffer is still in use? + vkQueueWaitIdle(queue.get) vkFreeCommandBuffers(device.get, commandPool, pointerBuffer) protected def close(): Unit = From 62c383c7b9b84e4256d21122ff13d8dc188e493e Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Mon, 8 Sep 2025 22:38:41 +0200 Subject: [PATCH 43/59] curret std^ --- .../io/computenode/cyfra/core/GBufferRegion.scala | 10 +++++----- .../cyfra/runtime/ExecutionHandler.scala | 13 ++----------- .../io/computenode/cyfra/vulkan/VulkanContext.scala | 1 - 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala index cfd3ad8d..d0c02fbb 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala @@ -1,6 +1,7 @@ package io.computenode.cyfra.core import io.computenode.cyfra.core.Allocation +import io.computenode.cyfra.core.GBufferRegion.MapRegion import io.computenode.cyfra.core.GProgram.BufferLengthSpec import io.computenode.cyfra.core.layout.{Layout, LayoutBinding} import io.computenode.cyfra.dsl.Value @@ -10,8 +11,10 @@ import izumi.reflect.Tag import java.nio.ByteBuffer -sealed trait GBufferRegion[ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding] - +sealed trait GBufferRegion[ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding]: + def map[NewAlloc <: Layout: LayoutBinding](f: Allocation ?=> ResAlloc => NewAlloc): GBufferRegion[ReqAlloc, NewAlloc] = + MapRegion(this, (alloc: Allocation) => (resAlloc: ResAlloc) => f(using alloc)(resAlloc)) + object GBufferRegion: def allocate[Alloc <: Layout: LayoutBinding]: GBufferRegion[Alloc, Alloc] = AllocRegion() @@ -24,9 +27,6 @@ object GBufferRegion: ) extends GBufferRegion[ReqAlloc, ResAlloc] extension [ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding](region: GBufferRegion[ReqAlloc, ResAlloc]) - def map[NewAlloc <: Layout: LayoutBinding](f: Allocation ?=> ResAlloc => NewAlloc): GBufferRegion[ReqAlloc, NewAlloc] = - MapRegion(region, (alloc: Allocation) => (resAlloc: ResAlloc) => f(using alloc)(resAlloc)) - def runUnsafe(init: Allocation ?=> ReqAlloc, onDone: Allocation ?=> ResAlloc => Unit)(using cyfraRuntime: CyfraRuntime): Unit = cyfraRuntime.withAllocation: allocation => diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index 89473f8c..b15fa95a 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -8,15 +8,7 @@ import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} -import io.computenode.cyfra.runtime.ExecutionHandler.{ - BindingLogicError, - Dispatch, - DispatchType, - ExecutionBinding, - ExecutionStep, - PipelineBarrier, - ShaderCall, -} +import io.computenode.cyfra.runtime.ExecutionHandler.{BindingLogicError, Dispatch, DispatchType, ExecutionBinding, ExecutionStep, PipelineBarrier, ShaderCall} import io.computenode.cyfra.runtime.ExecutionHandler.DispatchType.* import io.computenode.cyfra.runtime.ExecutionHandler.ExecutionBinding.{BufferBinding, UniformBinding} import io.computenode.cyfra.utility.Utility.timed @@ -29,7 +21,7 @@ import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import izumi.reflect.Tag import org.lwjgl.vulkan.VK10.* import org.lwjgl.vulkan.VK13.{VK_ACCESS_2_SHADER_READ_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, vkCmdPipelineBarrier2} -import org.lwjgl.vulkan.{VkCommandBuffer, VkCommandBufferBeginInfo, VkDependencyInfo, VkMemoryBarrier2, VkSubmitInfo} +import org.lwjgl.vulkan.{VK13, VkCommandBuffer, VkCommandBufferBeginInfo, VkDependencyInfo, VkMemoryBarrier2, VkSubmitInfo} import scala.collection.mutable @@ -198,7 +190,6 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte .flags(0) check(vkBeginCommandBuffer(commandBuffer, commandBufferBeginInfo), "Failed to begin recording command buffer") - steps.foreach: case PipelineBarrier => val memoryBarrier = VkMemoryBarrier2 // TODO don't synchronise everything diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala index 9c8c99c6..67d612fe 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala @@ -17,7 +17,6 @@ import scala.jdk.CollectionConverters.* private[cyfra] object VulkanContext: val ValidationLayer: String = "VK_LAYER_KHRONOS_validation" private val ValidationLayers: Boolean = System.getProperty("io.computenode.cyfra.vulkan.validation", "false").toBoolean - if Configuration.STACK_SIZE.get() < 100 then logger.warn(s"Small stack size. Increase with org.lwjgl.system.stackSize") private[cyfra] class VulkanContext: private val instance: Instance = new Instance(ValidationLayers) From 6993f85e3840d4d016ab379f3536bf9da0b8a505 Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Tue, 9 Sep 2025 00:16:35 +0200 Subject: [PATCH 44/59] working^ --- .../cyfra/samples/TestingStuff.scala | 15 ++++++++++++-- .../cyfra/runtime/ExecutionHandler.scala | 20 ++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index 8b9a5014..a389efc4 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -12,9 +12,16 @@ import io.computenode.cyfra.runtime.VkCyfraRuntime import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil +import java.nio.ByteBuffer import java.util.concurrent.atomic.AtomicInteger import scala.collection.parallel.CollectionConverters.given +def printBuffer(bb: ByteBuffer): Unit = { + val l = bb.asIntBuffer() + val s = (0 until l.remaining()).map(l.get).toList + println(s.mkString(" ")) +} + object TestingStuff: given GContext = GContext() @@ -111,10 +118,12 @@ object TestingStuff: emitBuffer = GBuffer[Int32](data.length * 2), filterBuffer = GBuffer[GBoolean](data.length * 2), ), - onDone = layout => layout.filterBuffer.read(rbb), + onDone = layout => + layout.filterBuffer.read(rbb) ) runtime.close() + printBuffer(rbb) val actual = (0 until 2 * 1024).map(i => result.get(i * 1) != 0) val expected = (0 until 1024).flatMap(x => Seq.fill(emitFilterParams.emitN)(x)).map(_ == emitFilterParams.filterValue) expected @@ -191,7 +200,7 @@ object TestingStuff: def testAddProgram10Times = given runtime: VkCyfraRuntime = VkCyfraRuntime() val bufferSize = 1280 - val params = AddProgramParams(bufferSize, addA = 0, addB = 1) + val params = AddProgramParams(bufferSize, addA = 5, addB = 10) val region = GBufferRegion .allocate[AddProgramExecLayout] .map: region => @@ -226,6 +235,8 @@ object TestingStuff: }, ) runtime.close() + + printBuffer(rbbList(0)) val expected = inData.map(_ + 11 * (params.addA + params.addB)) outBuffers.foreach { buf => (0 until bufferSize).foreach { i => diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index b15fa95a..cca151fb 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -8,7 +8,15 @@ import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} -import io.computenode.cyfra.runtime.ExecutionHandler.{BindingLogicError, Dispatch, DispatchType, ExecutionBinding, ExecutionStep, PipelineBarrier, ShaderCall} +import io.computenode.cyfra.runtime.ExecutionHandler.{ + BindingLogicError, + Dispatch, + DispatchType, + ExecutionBinding, + ExecutionStep, + PipelineBarrier, + ShaderCall, +} import io.computenode.cyfra.runtime.ExecutionHandler.DispatchType.* import io.computenode.cyfra.runtime.ExecutionHandler.ExecutionBinding.{BufferBinding, UniformBinding} import io.computenode.cyfra.utility.Utility.timed @@ -63,8 +71,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte descriptorSets.flatten.foreach(dsManager.free) commandPool.freeCommandBuffer(commandBuffer) - val externalBindings = (summon[LayoutBinding[EL]].toBindings(layout) ++ summon[LayoutBinding[RL]].toBindings(result)) - .map(VkAllocation.getUnderlying) + val externalBindings = getAllBindings(executeSteps).map(VkAllocation.getUnderlying) val deps = externalBindings.flatMap(_.execution.fold(Seq(_), _.toSeq)) val pe = new PendingExecution(commandBuffer, deps, cleanup) externalBindings.foreach(_.execution = Left(pe)) @@ -220,6 +227,13 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") commandBuffer + private def getAllBindings(steps: Seq[ExecutionStep]): Seq[GBinding[?]] = + steps + .flatMap: + case Dispatch(_, layout, _, _) => layout.flatten.map(_.binding) + case PipelineBarrier => Seq.empty + .distinct + object ExecutionHandler: case class ShaderCall(pipeline: ComputePipeline, layout: ShaderLayout, dispatch: DispatchType) From 226c1215e37d196be1c7768dcc8510bdd4cac5f8 Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Tue, 9 Sep 2025 00:30:33 +0200 Subject: [PATCH 45/59] todo^ --- .../io/computenode/cyfra/runtime/ExecutionHandler.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index cca151fb..f8624b27 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -74,7 +74,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte val externalBindings = getAllBindings(executeSteps).map(VkAllocation.getUnderlying) val deps = externalBindings.flatMap(_.execution.fold(Seq(_), _.toSeq)) val pe = new PendingExecution(commandBuffer, deps, cleanup) - externalBindings.foreach(_.execution = Left(pe)) + externalBindings.foreach(_.execution = Left(pe)) // TODO we assume all accesses are read-write result private def interpret[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding]( @@ -231,8 +231,8 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte steps .flatMap: case Dispatch(_, layout, _, _) => layout.flatten.map(_.binding) - case PipelineBarrier => Seq.empty - .distinct + case PipelineBarrier => Seq.empty + .distinct object ExecutionHandler: case class ShaderCall(pipeline: ComputePipeline, layout: ShaderLayout, dispatch: DispatchType) From fdc9ee2134581ebe2f4168998b92f70a5186111b Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Tue, 9 Sep 2025 00:34:23 +0200 Subject: [PATCH 46/59] foramt^^ --- .../main/scala/io/computenode/cyfra/core/GBufferRegion.scala | 2 +- .../main/scala/io/computenode/cyfra/samples/TestingStuff.scala | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala index d0c02fbb..633b3e1b 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala @@ -14,7 +14,7 @@ import java.nio.ByteBuffer sealed trait GBufferRegion[ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding]: def map[NewAlloc <: Layout: LayoutBinding](f: Allocation ?=> ResAlloc => NewAlloc): GBufferRegion[ReqAlloc, NewAlloc] = MapRegion(this, (alloc: Allocation) => (resAlloc: ResAlloc) => f(using alloc)(resAlloc)) - + object GBufferRegion: def allocate[Alloc <: Layout: LayoutBinding]: GBufferRegion[Alloc, Alloc] = AllocRegion() diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index a389efc4..c45680ea 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -118,8 +118,7 @@ object TestingStuff: emitBuffer = GBuffer[Int32](data.length * 2), filterBuffer = GBuffer[GBoolean](data.length * 2), ), - onDone = layout => - layout.filterBuffer.read(rbb) + onDone = layout => layout.filterBuffer.read(rbb), ) runtime.close() From 1ab927aea92c9023b5bf816cc73d8c040110ecf6 Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Tue, 9 Sep 2025 21:44:31 +0200 Subject: [PATCH 47/59] not working destroy^ --- .../computenode/cyfra/core/Allocation.scala | 2 + .../cyfra/core/GBufferRegion.scala | 16 +++-- .../cyfra/runtime/ExecutionHandler.scala | 1 + .../cyfra/runtime/PendingExecution.scala | 58 ++++++++++++------- .../cyfra/runtime/VkAllocation.scala | 16 +++++ .../computenode/cyfra/runtime/VkBinding.scala | 15 +++-- 6 files changed, 76 insertions(+), 32 deletions(-) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala index bdc1d5a7..d279bb88 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala @@ -10,6 +10,8 @@ import izumi.reflect.Tag import java.nio.ByteBuffer trait Allocation: + def reportLayout[L <: Layout: LayoutBinding](layout: L): Unit + extension (buffer: GBinding[?]) def read(bb: ByteBuffer, offset: Int = 0): Unit diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala index 633b3e1b..65ad0b41 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala @@ -9,9 +9,13 @@ import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.GBuffer import izumi.reflect.Tag +import scala.util.chaining.given import java.nio.ByteBuffer sealed trait GBufferRegion[ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding]: + def reqAllocBinding: LayoutBinding[ReqAlloc] = summon[LayoutBinding[ReqAlloc]] + def resAllocBinding: LayoutBinding[ResAlloc] = summon[LayoutBinding[ResAlloc]] + def map[NewAlloc <: Layout: LayoutBinding](f: Allocation ?=> ResAlloc => NewAlloc): GBufferRegion[ReqAlloc, NewAlloc] = MapRegion(this, (alloc: Allocation) => (resAlloc: ResAlloc) => f(using alloc)(resAlloc)) @@ -31,13 +35,13 @@ object GBufferRegion: cyfraRuntime.withAllocation: allocation => // noinspection ScalaRedundantCast - val steps: Seq[Allocation => Layout => Layout] = Seq.unfold(region: GBufferRegion[?, ?]): - case _: AllocRegion[?] => None - case MapRegion(req, f) => - Some((f.asInstanceOf[Allocation => Layout => Layout], req)) + val steps: Seq[(Allocation => Layout => Layout, LayoutBinding[Layout])] = Seq.unfold(region: GBufferRegion[?, ?]): + case _: AllocRegion[?] => None + case m @ MapRegion(req, f) => + Some(((f.asInstanceOf[Allocation => Layout => Layout], req.resAllocBinding.asInstanceOf[LayoutBinding[Layout]]), req)) - val initAlloc = init(using allocation) + val initAlloc = init(using allocation).tap(allocation.reportLayout) val bodyAlloc = steps.foldLeft[Layout](initAlloc): (acc, step) => - step(allocation)(acc) + step._1(allocation)(acc).tap(allocation.reportLayout(_)(using step._2)) onDone(using allocation)(bodyAlloc.asInstanceOf[ResAlloc]) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index f8624b27..9b9b385d 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -74,6 +74,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte val externalBindings = getAllBindings(executeSteps).map(VkAllocation.getUnderlying) val deps = externalBindings.flatMap(_.execution.fold(Seq(_), _.toSeq)) val pe = new PendingExecution(commandBuffer, deps, cleanup) + summon[VkAllocation].addExecution(pe) externalBindings.foreach(_.execution = Left(pe)) // TODO we assume all accesses are read-write result diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala index 63cf516f..15e595f1 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala @@ -9,32 +9,50 @@ import org.lwjgl.vulkan.{VK13, VkCommandBuffer, VkCommandBufferSubmitInfo, VkSem import scala.collection.mutable -class PendingExecution(protected val handle: VkCommandBuffer, val dependencies: Seq[PendingExecution], cleanup: () => Unit)(using Device) - extends VulkanObject[VkCommandBuffer]: +class PendingExecution(protected val handle: VkCommandBuffer, val dependencies: Seq[PendingExecution], cleanup: () => Unit)(using Device): private val semaphore: Semaphore = Semaphore() private var fence: Option[Fence] = None - override protected def close(): Unit = cleanup() - - private def setFence(otherFence: Fence): Unit = - if fence.isDefined then return - fence = Some(otherFence) - dependencies.foreach(_.setFence(otherFence)) + def isPending: Boolean = fence.isEmpty + def isRunning: Boolean = fence.exists(!_.isSignaled) + def isFinished: Boolean = fence.exists(_.isSignaled) + + def block(): Unit = fence.foreach(_.block()) + + private var closed = false + def isClosed: Boolean = closed + private def close(): Unit = + assert(!closed, "PendingExecution already closed") + assert(isFinished, "Cannot close a PendingExecution that is not finished") + cleanup() + closed = true + + private var destroyed = false + def destroy(): Unit = + assert(!destroyed, "PendingExecution already destroyed") + assert(isFinished, "Cannot destroy a PendingExecution that is not finished") + if !closed then close() + semaphore.destroy() + fence.foreach(x => if x.isAlive then x.destroy()) + destroyed = true + + private def setFence(f: Fence): Unit = { + if !isPending then return + fence = Some(f) + dependencies.foreach(_.setFence(f)) + } - private def gatherForSubmission: Seq[((VkCommandBuffer, Semaphore), Set[Semaphore])] = { - if fence.isDefined then return Seq.empty + private def gatherForSubmission: Seq[((VkCommandBuffer, Semaphore), Set[Semaphore])] = + if !isPending then return Seq.empty val mySubmission = ((handle, semaphore), dependencies.map(_.semaphore).toSet) dependencies.flatMap(_.gatherForSubmission).appended(mySubmission) - } - - def block(): Unit = - fence match - case Some(f) => f.block() - case None => throw new IllegalStateException("No fence set for this execution") object PendingExecution: def executeAll(executions: Seq[PendingExecution], queue: Queue)(using Device): Fence = pushStack: stack => - val exec = + assert(executions.forall(_.isPending), "All executions must be pending") + assert(executions.nonEmpty, "At least one execution must be provided") + + val exec: Seq[(Set[Semaphore], Set[(VkCommandBuffer, Semaphore)])] = val gathered = executions.flatMap(_.gatherForSubmission) val ordering = gathered.zipWithIndex.map(x => (x._1._1._1, x._2)).toMap gathered.toSet.groupMap(_._2)(_._1).toSeq.sortBy(x => x._2.map(_._1).map(ordering).min) @@ -79,13 +97,13 @@ object PendingExecution: submitInfos.flip() val fence = Fence() - executions.foreach(_.setFence(fence)) check(vkQueueSubmit2(queue.get, submitInfos, fence.get), "Failed to submit command buffer to queue") + executions.foreach(_.setFence(fence)) fence def cleanupAll(executions: Seq[PendingExecution]): Unit = def cleanupRec(ex: PendingExecution): Unit = - if !ex.isAlive then return - ex.destroy() + if !ex.isClosed then return + ex.close() ex.dependencies.foreach(cleanupRec) executions.foreach(cleanupRec) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index 4ce9692c..0db6a108 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -29,6 +29,15 @@ import scala.util.chaining.* class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler)(using Allocator, Device) extends Allocation: given VkAllocation = this + override def reportLayout[L <: Layout: LayoutBinding](layout: L): Unit = + val executions = summon[LayoutBinding[L]] + .toBindings(layout) + .map(getUnderlying) + .flatMap(_.execution.fold(Seq(_), _.toSeq)) + .filter(_.isPending) + + PendingExecution.executeAll(executions, commandPool.queue) + extension (buffer: GBinding[?]) def read(bb: ByteBuffer, offset: Int = 0): Unit = val size = bb.remaining() @@ -54,6 +63,7 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) commandPool.freeCommandBuffer(cb) stagingBuffer.destroy() val pe = new PendingExecution(cb, binding.execution.fold(Seq(_), _.toSeq), cleanup) + addExecution(pe) binding.execution = Left(pe) case _ => throw new IllegalArgumentException(s"Tried to write to non-VkBinding $buffer") @@ -89,8 +99,14 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) case _ => ??? direct(bb) + private val executions = mutable.Buffer[PendingExecution]() + + def addExecution(pe: PendingExecution): Unit = + executions += pe + private val bindings = mutable.Buffer[VkUniform[?] | VkBuffer[?]]() private[cyfra] def close(): Unit = + executions.foreach(_.destroy()) bindings.map(getUnderlying).foreach(_.buffer.destroy()) private def getStagingBuffer(size: Int): Buffer.HostBuffer = diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala index f83f39fb..acda99f3 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala @@ -33,12 +33,15 @@ sealed abstract class VkBinding[T <: Value: {Tag, FromExpr}](val buffer: Buffer) */ var execution: Either[PendingExecution, mutable.Buffer[PendingExecution]] = Right(mutable.Buffer.empty) - def materialise(queue: Queue)(using Device): Unit = execution match - case Left(exec) if exec.isAlive => - PendingExecution.executeAll(Seq(exec), queue) - exec.block() - PendingExecution.cleanupAll(Seq(exec)) - case _ => () + def materialise(queue: Queue)(using Device): Unit = + val (pendingExecs, runningExecs) = execution.fold(Seq(_), _.toSeq).partition(_.isPending) // TODO better handle read only executions + if pendingExecs.nonEmpty then + val fence = PendingExecution.executeAll(pendingExecs, queue) + fence.block() + PendingExecution.cleanupAll(pendingExecs) + + runningExecs.foreach(_.block()) + PendingExecution.cleanupAll(runningExecs) object VkBinding: def unapply(binding: GBinding[?]): Option[Buffer] = binding match From 2d75933e926e4a3f11c70bb9aed58986ecf3b546 Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Wed, 10 Sep 2025 00:04:59 +0200 Subject: [PATCH 48/59] working intermediete submission^ --- .../io/computenode/cyfra/runtime/PendingExecution.scala | 9 ++++----- .../io/computenode/cyfra/runtime/VkAllocation.scala | 1 + .../io/computenode/cyfra/vulkan/memory/Buffer.scala | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala index 15e595f1..52aea0f2 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala @@ -4,6 +4,7 @@ import io.computenode.cyfra.vulkan.command.{CommandPool, Fence, Semaphore} import io.computenode.cyfra.vulkan.core.{Device, Queue} import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObject +import org.lwjgl.vulkan.VK10.VK_TRUE import org.lwjgl.vulkan.VK13.{VK_PIPELINE_STAGE_2_COPY_BIT, vkQueueSubmit2} import org.lwjgl.vulkan.{VK13, VkCommandBuffer, VkCommandBufferSubmitInfo, VkSemaphoreSubmitInfo, VkSubmitInfo2} @@ -22,16 +23,14 @@ class PendingExecution(protected val handle: VkCommandBuffer, val dependencies: private var closed = false def isClosed: Boolean = closed private def close(): Unit = - assert(!closed, "PendingExecution already closed") - assert(isFinished, "Cannot close a PendingExecution that is not finished") + if closed then return cleanup() closed = true private var destroyed = false def destroy(): Unit = - assert(!destroyed, "PendingExecution already destroyed") - assert(isFinished, "Cannot destroy a PendingExecution that is not finished") - if !closed then close() + if destroyed then return + close() semaphore.destroy() fence.foreach(x => if x.isAlive then x.destroy()) destroyed = true diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index 0db6a108..a799f98c 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -48,6 +48,7 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) val stagingBuffer = getStagingBuffer(size) Buffer.copyBuffer(binding.buffer, stagingBuffer, offset, 0, size, commandPool) stagingBuffer.copyTo(bb, 0) + stagingBuffer.destroy() case _ => throw new IllegalArgumentException(s"Tried to read from non-VkBinding $buffer") def write(bb: ByteBuffer, offset: Int = 0): Unit = diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala index 1f677f04..c1f34b40 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala @@ -74,7 +74,7 @@ object Buffer: val fence = Fence() check(vkQueueSubmit(commandPool.queue.get, submitInfo, fence.get), "Failed to submit single time command buffer") - fence.block() + fence.block().destroy() def copyBufferCommandBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool): VkCommandBuffer = commandPool.recordSingleTimeCommand: commandBuffer => From 19c0bfec5a57b4fd8801130da5edd4166764eba1 Mon Sep 17 00:00:00 2001 From: Szymon Date: Wed, 10 Sep 2025 01:29:23 +0200 Subject: [PATCH 49/59] Various fixes and improvements --- .../io/computenode/cyfra/core/GProgram.scala | 17 ++ .../computenode/cyfra/core/SpirvProgram.scala | 25 ++- .../cyfra/e2e/SpirvRuntimeEnduranceTest.scala | 209 ++++++++++++++++++ .../e2e/{ => dsl}/ArithmeticsE2eTest.scala | 6 +- .../e2e/{ => dsl}/FunctionsE2eTest.scala | 7 +- .../cyfra/e2e/{ => dsl}/GStructE2eTest.scala | 6 +- .../cyfra/e2e/{ => dsl}/GseqE2eTest.scala | 6 +- .../cyfra/e2e/{ => dsl}/WhenE2eTest.scala | 6 +- .../computenode/cyfra/fs2interop/GPipe.scala | 7 +- .../cyfra/runtime/VkCyfraRuntime.scala | 23 +- .../cyfra/vulkan/core/Instance.scala | 2 +- 11 files changed, 283 insertions(+), 31 deletions(-) create mode 100644 cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{ => dsl}/ArithmeticsE2eTest.scala (95%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{ => dsl}/FunctionsE2eTest.scala (94%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{ => dsl}/GStructE2eTest.scala (96%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{ => dsl}/GseqE2eTest.scala (94%) rename cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/{ => dsl}/WhenE2eTest.scala (91%) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala index f1cef442..7154e47f 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala @@ -12,6 +12,10 @@ import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import io.computenode.cyfra.dsl.struct.GStruct.Empty import izumi.reflect.Tag +import java.io.FileInputStream +import java.nio.file.Path +import scala.util.Using + trait GProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}] extends GExecution[Params, L, L]: val layout: InitProgramLayout => Params => L val dispatch: (L, Params) => ProgramDispatch @@ -32,6 +36,19 @@ object GProgram: )(body: L => GIO[?]): GProgram[Params, L] = new GioProgram[Params, L](body, s => layout(using s), dispatch, workgroupSize) + def fromSpirvFile[Params, L <: Layout : {LayoutBinding, LayoutStruct}]( + layout: InitProgramLayout ?=> Params => L, + dispatch: (L, Params) => ProgramDispatch, + path: Path + ): SpirvProgram[Params, L] = + Using.resource(new FileInputStream(path.toFile)): fis => + val fc = fis.getChannel + val size = fc.size().toInt + val bb = ByteBuffer.allocateDirect(size) + fc.read(bb) + bb.flip() + SpirvProgram(layout, dispatch, bb) + private[cyfra] class BufferLengthSpec[T <: Value: {Tag, FromExpr}](val length: Int) extends GBuffer[T]: private[cyfra] def materialise()(using Allocation): GBuffer[T] = GBuffer.apply[T](length) private[cyfra] class DynamicUniform[T <: GStruct[T]: {Tag, FromExpr, GStructSchema}]() extends GUniform[T] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala index b4bcbd85..f60c02e3 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala @@ -14,6 +14,8 @@ import java.io.File import java.io.FileInputStream import java.nio.ByteBuffer import java.nio.channels.FileChannel +import java.nio.file.Path +import java.security.MessageDigest import java.util.Objects import scala.util.Try import scala.util.Using @@ -26,7 +28,26 @@ case class SpirvProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}] priv code: ByteBuffer, entryPoint: String, shaderBindings: L => ShaderLayout, -) extends GProgram[Params, L] +) extends GProgram[Params, L]: + + /** + * A hash of the shader code, entry point, workgroup size, and layout bindings. + * Layout and dispatch are not taken into account. + */ + lazy val shaderHash: (Long, Long) = + val md = MessageDigest.getInstance("SHA-256") + md.update(code) + code.rewind() + md.update(entryPoint.getBytes) + md.update(workgroupSize.toList + .flatMap(BigInt(_).toByteArray).toArray) + val layout = shaderBindings(summon[LayoutStruct[L]].layoutRef) + layout.flatten.foreach: binding => + md.update(binding.binding.tag.toString.getBytes) + md.update(binding.operation.toString.getBytes) + val digest = md.digest() + val bb = java.nio.ByteBuffer.wrap(digest) + (bb.getLong(), bb.getLong()) object SpirvProgram: type ShaderLayout = Seq[Seq[Binding]] @@ -41,7 +62,7 @@ object SpirvProgram: dispatch: (L, Params) => ProgramDispatch, code: ByteBuffer ): SpirvProgram[Params, L] = - val workgroupSize = (128, 1, 1) // TODO Extract form shader + val workgroupSize = (128, 1, 1) // TODO Extract form shader val main = "main" val f: L => ShaderLayout = { case layout: Product => layout.productIterator.zipWithIndex.map { case (binding: GBinding[?], i) => Binding(binding, ReadWrite) }.toSeq.pipe(Seq(_)) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala new file mode 100644 index 00000000..95833a22 --- /dev/null +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala @@ -0,0 +1,209 @@ +package io.computenode.cyfra.e2e + +import io.computenode.cyfra.core.archive.GContext +import io.computenode.cyfra.core.layout.* +import io.computenode.cyfra.core.{GBufferRegion, GExecution, GProgram} +import io.computenode.cyfra.dsl.Value.{GBoolean, Int32} +import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} +import io.computenode.cyfra.dsl.gio.GIO +import io.computenode.cyfra.dsl.struct.GStruct +import io.computenode.cyfra.dsl.struct.GStruct.Empty +import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.runtime.VkCyfraRuntime +import io.computenode.cyfra.spirvtools.{SpirvCross, SpirvDisassembler, SpirvToolsRunner} +import io.computenode.cyfra.spirvtools.SpirvTool.ToFile +import io.computenode.cyfra.utility.Logger.logger +import org.lwjgl.BufferUtils +import org.lwjgl.system.MemoryUtil + +import java.nio.file.Paths +import scala.concurrent.ExecutionContext.Implicits.global +import java.util.concurrent.atomic.AtomicInteger +import scala.concurrent.{Await, Future} + + +class SpirvRuntimeEnduranceTest extends munit.FunSuite: + + test("Endurance test for GExecution with multiple SPIRV programs loaded from files"): + runEnduranceTest(10000) + + // === Emit program === + + case class EmitProgramParams(inSize: Int, emitN: Int) + + case class EmitProgramUniform(emitN: Int32) extends GStruct[EmitProgramUniform] + + case class EmitProgramLayout( + in: GBuffer[Int32], + out: GBuffer[Int32], + args: GUniform[EmitProgramUniform] = GUniform.fromParams, // todo will be different in the future + ) extends Layout + + val emitProgram = GProgram.fromSpirvFile[EmitProgramParams, EmitProgramLayout]( + layout = params => + EmitProgramLayout( + in = GBuffer[Int32](params.inSize), + out = GBuffer[Int32](params.inSize * params.emitN), + args = GUniform(EmitProgramUniform(params.emitN)), + ), + dispatch = (_, args) => GProgram.StaticDispatch((args.inSize / 128, 1, 1)), + Paths.get(getClass.getResource("/emit.spv").toURI) + ) + + // === Filter program === + + case class FilterProgramParams(inSize: Int, filterValue: Int) + + case class FilterProgramUniform(filterValue: Int32) extends GStruct[FilterProgramUniform] + + case class FilterProgramLayout(in: GBuffer[Int32], out: GBuffer[GBoolean], params: GUniform[FilterProgramUniform] = GUniform.fromParams) + extends Layout + + val filterProgram = GProgram.fromSpirvFile[FilterProgramParams, FilterProgramLayout]( + layout = params => + FilterProgramLayout( + in = GBuffer[Int32](params.inSize), + out = GBuffer[GBoolean](params.inSize), + params = GUniform(FilterProgramUniform(params.filterValue)), + ), + dispatch = (_, args) => GProgram.StaticDispatch((args.inSize / 128, 1, 1)), + Paths.get(getClass.getResource("/filter.spv").toURI) + ) + // === GExecution === + + case class EmitFilterParams(inSize: Int, emitN: Int, filterValue: Int) + + case class EmitFilterLayout(inBuffer: GBuffer[Int32], emitBuffer: GBuffer[Int32], filterBuffer: GBuffer[GBoolean]) extends Layout + + case class EmitFilterResult(out: GBuffer[GBoolean]) extends Layout + + val emitFilterExecution = GExecution[EmitFilterParams, EmitFilterLayout]() + .addProgram(emitProgram)( + params => EmitProgramParams(inSize = params.inSize, emitN = params.emitN), + layout => EmitProgramLayout(in = layout.inBuffer, out = layout.emitBuffer), + ) + .addProgram(filterProgram)( + params => FilterProgramParams(inSize = 2 * params.inSize, filterValue = params.filterValue), + layout => FilterProgramLayout(in = layout.emitBuffer, out = layout.filterBuffer), + ) + + // Test case: Use one program 10 times, copying values from five input buffers to five output buffers and adding values from two uniforms + case class AddProgramParams(bufferSize: Int, addA: Int, addB: Int) + + case class AddProgramUniform(a: Int32) extends GStruct[AddProgramUniform] + + case class AddProgramLayout( + in1: GBuffer[Int32], + in2: GBuffer[Int32], + in3: GBuffer[Int32], + in4: GBuffer[Int32], + in5: GBuffer[Int32], + out1: GBuffer[Int32], + out2: GBuffer[Int32], + out3: GBuffer[Int32], + out4: GBuffer[Int32], + out5: GBuffer[Int32], + u1: GUniform[AddProgramUniform] = GUniform.fromParams, + u2: GUniform[AddProgramUniform] = GUniform.fromParams, + ) extends Layout + + case class AddProgramExecLayout( + in1: GBuffer[Int32], + in2: GBuffer[Int32], + in3: GBuffer[Int32], + in4: GBuffer[Int32], + in5: GBuffer[Int32], + out1: GBuffer[Int32], + out2: GBuffer[Int32], + out3: GBuffer[Int32], + out4: GBuffer[Int32], + out5: GBuffer[Int32], + ) extends Layout + + val addProgram: GProgram[AddProgramParams, AddProgramLayout] = GProgram.fromSpirvFile[AddProgramParams, AddProgramLayout]( + layout = params => + AddProgramLayout( + in1 = GBuffer[Int32](params.bufferSize), + in2 = GBuffer[Int32](params.bufferSize), + in3 = GBuffer[Int32](params.bufferSize), + in4 = GBuffer[Int32](params.bufferSize), + in5 = GBuffer[Int32](params.bufferSize), + out1 = GBuffer[Int32](params.bufferSize), + out2 = GBuffer[Int32](params.bufferSize), + out3 = GBuffer[Int32](params.bufferSize), + out4 = GBuffer[Int32](params.bufferSize), + out5 = GBuffer[Int32](params.bufferSize), + u1 = GUniform(AddProgramUniform(params.addA)), + u2 = GUniform(AddProgramUniform(params.addB)), + ), + dispatch = (layout, args) => GProgram.StaticDispatch((args.bufferSize / 128, 1, 1)), + Paths.get(getClass.getResource("/addOne.spv").toURI) + ) + + def swap(l: AddProgramLayout): AddProgramLayout = + val AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5, u1, u2) = l + AddProgramLayout(out1, out2, out3, out4, out5, in1, in2, in3, in4, in5, u1, u2) + + def fromExecLayout(l: AddProgramExecLayout): AddProgramLayout = + val AddProgramExecLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5) = l + AddProgramLayout(in1, in2, in3, in4, in5, out1, out2, out3, out4, out5) + + val execution = (0 until 11).foldLeft( + GExecution[AddProgramParams, AddProgramExecLayout]().asInstanceOf[GExecution[AddProgramParams, AddProgramExecLayout, AddProgramExecLayout]], + )((x, i) => + if i % 2 == 0 then x.addProgram(addProgram)(mapParams = identity[AddProgramParams], mapLayout = fromExecLayout) + else x.addProgram(addProgram)(mapParams = identity, mapLayout = x => swap(fromExecLayout(x))), + ) + + def runEnduranceTest(nRuns: Int): Unit = + logger.info(s"Starting endurance test with ${nRuns} runs...") + + given runtime: VkCyfraRuntime = VkCyfraRuntime( + spirvToolsRunner = SpirvToolsRunner( + crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))), + disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/dis.spvdis"))))) + + val bufferSize = 1280 + val params = AddProgramParams(bufferSize, addA = 0, addB = 1) + val region = GBufferRegion + .allocate[AddProgramExecLayout] + .map: region => + execution.execute(params, region) + val aInt = new AtomicInteger(0) + val runs = (1 to nRuns).map: + i => Future: + val inBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) + val wbbList = inBuffers.map(MemoryUtil.memByteBuffer) + val rbbList = List.fill(5)(BufferUtils.createByteBuffer(bufferSize * 4)) + + val inData = (0 until bufferSize).toArray + inBuffers.foreach(_.put(inData).flip()) + region.runUnsafe( + init = AddProgramExecLayout( + in1 = GBuffer[Int32](wbbList(0)), + in2 = GBuffer[Int32](wbbList(1)), + in3 = GBuffer[Int32](wbbList(2)), + in4 = GBuffer[Int32](wbbList(3)), + in5 = GBuffer[Int32](wbbList(4)), + out1 = GBuffer[Int32](bufferSize), + out2 = GBuffer[Int32](bufferSize), + out3 = GBuffer[Int32](bufferSize), + out4 = GBuffer[Int32](bufferSize), + out5 = GBuffer[Int32](bufferSize), + ), + onDone = layout => { + layout.out1.read(rbbList(0)) + layout.out2.read(rbbList(1)) + layout.out3.read(rbbList(2)) + layout.out4.read(rbbList(3)) + layout.out5.read(rbbList(4)) + }, + ) + val prev = aInt.getAndAdd(1) + if prev % 50 == 0 then logger.info(s"Iteration $prev completed") + + val allRuns = Future.sequence(runs) + Await.result(allRuns, scala.concurrent.duration.Duration.Inf) + + runtime.close() + logger.info("Endurance test completed successfully") diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticsE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala similarity index 95% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticsE2eTest.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala index 17797a77..78843776 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/ArithmeticsE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala @@ -1,8 +1,8 @@ -package io.computenode.cyfra.e2e +package io.computenode.cyfra.e2e.dsl import io.computenode.cyfra.core.archive.* -import mem.* -import GMem.fRGBA +import io.computenode.cyfra.core.archive.mem.* +import io.computenode.cyfra.core.archive.mem.GMem.fRGBA import io.computenode.cyfra.dsl.algebra.VectorAlgebra import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala similarity index 94% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsE2eTest.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala index 31966edf..990906e8 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/FunctionsE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala @@ -1,9 +1,10 @@ -package io.computenode.cyfra.e2e +package io.computenode.cyfra.e2e.dsl -import io.computenode.cyfra.core.archive.*, mem.* +import io.computenode.cyfra.core.archive.* +import io.computenode.cyfra.core.archive.mem.* +import io.computenode.cyfra.core.archive.mem.GMem.fRGBA import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} -import GMem.fRGBA class FunctionsE2eTest extends munit.FunSuite: given gc: GContext = GContext() diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala similarity index 96% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructE2eTest.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala index c1183c2a..20e15843 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GStructE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala @@ -1,9 +1,9 @@ -package io.computenode.cyfra.e2e +package io.computenode.cyfra.e2e.dsl +import io.computenode.cyfra.core.archive.* +import io.computenode.cyfra.core.archive.mem.* import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.core.archive.* -import mem.* import io.computenode.cyfra.dsl.{*, given} class GStructE2eTest extends munit.FunSuite: diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala similarity index 94% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala index d10cca51..318201b1 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/GseqE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala @@ -1,9 +1,9 @@ -package io.computenode.cyfra.e2e +package io.computenode.cyfra.e2e.dsl +import io.computenode.cyfra.core.archive.* +import io.computenode.cyfra.core.archive.mem.* import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.core.archive.* -import mem.* import io.computenode.cyfra.dsl.{*, given} class GseqE2eTest extends munit.FunSuite: diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/WhenE2eTest.scala similarity index 91% rename from cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenE2eTest.scala rename to cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/WhenE2eTest.scala index 0a374c26..416f9148 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/WhenE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/WhenE2eTest.scala @@ -1,8 +1,8 @@ -package io.computenode.cyfra.e2e +package io.computenode.cyfra.e2e.dsl -import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.core.archive.* -import mem.* +import io.computenode.cyfra.core.archive.mem.* +import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} class WhenE2eTest extends munit.FunSuite: diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index c79946be..0efefce1 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -138,7 +138,7 @@ object GPipe: inSize: Int, intervalSize: Int, ): GExecution[ScanParams, ScanLayout, ScanLayout] = - if intervalSize >= inSize then exec + if intervalSize > inSize then exec else val newExec = exec.addProgram(upsweep)(params => ScanParams(inSize, intervalSize), layout => layout) upsweepPhases(newExec, inSize, intervalSize * 2) @@ -170,7 +170,7 @@ object GPipe: val element = GIO.read[C](layout.in, invocId) val prefixSum = GIO.read[Int32](layout.scan, invocId) for - _ <- GIO.printf("Element %d, prefix sum %d", invocId, prefixSum) + _ <- GIO.printf("Compact: Element %d, prefix sum %d", invocId, prefixSum) _ <- GIO.when(invocId > 0): val prevScan = GIO.read[Int32](layout.scan, invocId - 1) GIO.when(prevScan < prefixSum): @@ -224,10 +224,11 @@ object GPipe: region.runUnsafe( init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](filterParams.inSize), out = GBuffer[C](filterParams.inSize)), onDone = layout => { - layout.scan.read(filteredCount, (filterParams.inSize - 2) * intSize) + layout.scan.read(filteredCount, (filterParams.inSize - 1) * intSize) layout.out.read(compactBuf) } ) val filteredN = filteredCount.getInt(0) val arr = bridge.fromByteBuffer(compactBuf, new Array[S](filteredN)) + println(arr) Stream.emits(arr) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala index e38648f4..17b90fab 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala @@ -8,23 +8,26 @@ import io.computenode.cyfra.spirvtools.SpirvToolsRunner import io.computenode.cyfra.vulkan.VulkanContext import io.computenode.cyfra.vulkan.compute.ComputePipeline +import java.security.MessageDigest import scala.collection.mutable class VkCyfraRuntime(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()) extends CyfraRuntime: private val context = new VulkanContext() import context.given - private val shaderCache = mutable.Map[GProgram[?, ?], VkShader[?]]() + private val gProgramCache = mutable.Map[GProgram[?, ?], SpirvProgram[?, ?]]() + private val shaderCache = mutable.Map[(Long, Long), VkShader[?]]() + private[cyfra] def getOrLoadProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}](program: GProgram[Params, L]): VkShader[L] = synchronized: - if (shaderCache.contains(program)) then - shaderCache(program).asInstanceOf[VkShader[L]] - else - val spirvProgram = program match - case p: GioProgram[?, ?] => compile(p) - case p: SpirvProgram[?, ?] => p - case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") - - shaderCache.getOrElseUpdate(program, VkShader(spirvProgram)).asInstanceOf[VkShader[L]] + + val spirvProgram: SpirvProgram[Params, L] = program match + case p: GioProgram[Params, L] if gProgramCache.contains(p) => + gProgramCache(p).asInstanceOf + case p: GioProgram[Params, L] => compile(p) + case p: SpirvProgram[Params, L] => p + case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") + + shaderCache.getOrElseUpdate(spirvProgram.shaderHash, VkShader(spirvProgram)).asInstanceOf[VkShader[L]] private def compile[Params, L <: Layout: {LayoutBinding as lbinding, LayoutStruct as lstruct}](program: GioProgram[Params, L]): SpirvProgram[Params, L] = val GioProgram(_, layout, dispatch, _) = program diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala index a1680c0e..2f3d3df5 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala @@ -152,7 +152,7 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj ) .pfnUserCallback(c) - val debugMessengerBuff = stack.callocLong(1) + val debugMessengerBuff = MemoryUtil.memAllocLong(1) check(vkCreateDebugUtilsMessengerEXT( handle, debugMessengerCreate.get(0), From 92d021907fc3b0d7bb7911154d5f3226a146fcaf Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Wed, 10 Sep 2025 11:43:13 +0200 Subject: [PATCH 50/59] fix --- .../main/scala/io/computenode/cyfra/core/Allocation.scala | 2 +- .../scala/io/computenode/cyfra/samples/TestingStuff.scala | 8 ++++---- .../scala/io/computenode/cyfra/runtime/VkBinding.scala | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala index d279bb88..908c452e 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala @@ -10,7 +10,7 @@ import izumi.reflect.Tag import java.nio.ByteBuffer trait Allocation: - def reportLayout[L <: Layout: LayoutBinding](layout: L): Unit + def reportLayout[L <: Layout: LayoutBinding](layout: L): Unit extension (buffer: GBinding[?]) def read(bb: ByteBuffer, offset: Int = 0): Unit diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index c45680ea..2f1b2799 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -16,11 +16,11 @@ import java.nio.ByteBuffer import java.util.concurrent.atomic.AtomicInteger import scala.collection.parallel.CollectionConverters.given -def printBuffer(bb: ByteBuffer): Unit = { +def printBuffer(bb: ByteBuffer): Unit = val l = bb.asIntBuffer() - val s = (0 until l.remaining()).map(l.get).toList - println(s.mkString(" ")) -} + val a = new Array[Int](l.remaining()) + l.get(a) + println(a.mkString(" ")) object TestingStuff: diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala index acda99f3..6283ad78 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala @@ -39,7 +39,7 @@ sealed abstract class VkBinding[T <: Value: {Tag, FromExpr}](val buffer: Buffer) val fence = PendingExecution.executeAll(pendingExecs, queue) fence.block() PendingExecution.cleanupAll(pendingExecs) - + runningExecs.foreach(_.block()) PendingExecution.cleanupAll(runningExecs) From cdb7900c2fbb0a8ffbe2f0b7e4ba0eecb5772534 Mon Sep 17 00:00:00 2001 From: marcin-zlakowski Date: Thu, 11 Sep 2025 13:16:45 +0200 Subject: [PATCH 51/59] fixes^ --- .../computenode/cyfra/core/Allocation.scala | 2 +- .../cyfra/core/GBufferRegion.scala | 8 ++--- .../cyfra/runtime/PendingExecution.scala | 32 ++++++++++++------- .../cyfra/runtime/VkAllocation.scala | 2 +- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala index 908c452e..493b6a6e 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala @@ -10,7 +10,7 @@ import izumi.reflect.Tag import java.nio.ByteBuffer trait Allocation: - def reportLayout[L <: Layout: LayoutBinding](layout: L): Unit + def submitLayout[L <: Layout: LayoutBinding](layout: L): Unit extension (buffer: GBinding[?]) def read(bb: ByteBuffer, offset: Int = 0): Unit diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala index 65ad0b41..b80bc679 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala @@ -36,12 +36,12 @@ object GBufferRegion: // noinspection ScalaRedundantCast val steps: Seq[(Allocation => Layout => Layout, LayoutBinding[Layout])] = Seq.unfold(region: GBufferRegion[?, ?]): - case _: AllocRegion[?] => None - case m @ MapRegion(req, f) => + case AllocRegion => None + case MapRegion(req, f) => Some(((f.asInstanceOf[Allocation => Layout => Layout], req.resAllocBinding.asInstanceOf[LayoutBinding[Layout]]), req)) - val initAlloc = init(using allocation).tap(allocation.reportLayout) + val initAlloc = init(using allocation).tap(allocation.submitLayout) val bodyAlloc = steps.foldLeft[Layout](initAlloc): (acc, step) => - step._1(allocation)(acc).tap(allocation.reportLayout(_)(using step._2)) + step._1(allocation)(acc).tap(allocation.submitLayout(_)(using step._2)) onDone(using allocation)(bodyAlloc.asInstanceOf[ResAlloc]) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala index 52aea0f2..1fe09725 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala @@ -10,6 +10,12 @@ import org.lwjgl.vulkan.{VK13, VkCommandBuffer, VkCommandBufferSubmitInfo, VkSem import scala.collection.mutable +/** A command buffer that is pending execution, along with its dependencies and cleanup actions. + * + * You can call `close()` only when `isFinished || isPending` is true + * + * You can call `destroy()` only when all dependants are `isClosed` + */ class PendingExecution(protected val handle: VkCommandBuffer, val dependencies: Seq[PendingExecution], cleanup: () => Unit)(using Device): private val semaphore: Semaphore = Semaphore() private var fence: Option[Fence] = None @@ -23,6 +29,7 @@ class PendingExecution(protected val handle: VkCommandBuffer, val dependencies: private var closed = false def isClosed: Boolean = closed private def close(): Unit = + assert(isFinished || isPending, "Cannot close a PendingExecution that is not finished or pending") if closed then return cleanup() closed = true @@ -35,24 +42,29 @@ class PendingExecution(protected val handle: VkCommandBuffer, val dependencies: fence.foreach(x => if x.isAlive then x.destroy()) destroyed = true - private def setFence(f: Fence): Unit = { - if !isPending then return - fence = Some(f) - dependencies.foreach(_.setFence(f)) - } - - private def gatherForSubmission: Seq[((VkCommandBuffer, Semaphore), Set[Semaphore])] = + /** Gathers all command buffers and their semaphores for submission to the queue, in the correct order. + * + * When you call this method, you are expected to submit the command buffers to the queue, and signal the provided fence when done. + * @param f + * The fence to signal when the command buffers are done executing. + * @return + * A sequence of tuples, each containing a command buffer, semaphore to signal, and a set of semaphores to wait on. + */ + private def gatherForSubmission(f: Fence): Seq[((VkCommandBuffer, Semaphore), Set[Semaphore])] = if !isPending then return Seq.empty val mySubmission = ((handle, semaphore), dependencies.map(_.semaphore).toSet) - dependencies.flatMap(_.gatherForSubmission).appended(mySubmission) + fence = Some(f) + dependencies.flatMap(_.gatherForSubmission(f)).appended(mySubmission) object PendingExecution: def executeAll(executions: Seq[PendingExecution], queue: Queue)(using Device): Fence = pushStack: stack => assert(executions.forall(_.isPending), "All executions must be pending") assert(executions.nonEmpty, "At least one execution must be provided") + val fence = Fence() + val exec: Seq[(Set[Semaphore], Set[(VkCommandBuffer, Semaphore)])] = - val gathered = executions.flatMap(_.gatherForSubmission) + val gathered = executions.flatMap(_.gatherForSubmission(fence)) val ordering = gathered.zipWithIndex.map(x => (x._1._1._1, x._2)).toMap gathered.toSet.groupMap(_._2)(_._1).toSeq.sortBy(x => x._2.map(_._1).map(ordering).min) @@ -95,9 +107,7 @@ object PendingExecution: submitInfos.flip() - val fence = Fence() check(vkQueueSubmit2(queue.get, submitInfos, fence.get), "Failed to submit command buffer to queue") - executions.foreach(_.setFence(fence)) fence def cleanupAll(executions: Seq[PendingExecution]): Unit = diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index a799f98c..ea80f7c6 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -29,7 +29,7 @@ import scala.util.chaining.* class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler)(using Allocator, Device) extends Allocation: given VkAllocation = this - override def reportLayout[L <: Layout: LayoutBinding](layout: L): Unit = + override def submitLayout[L <: Layout: LayoutBinding](layout: L): Unit = val executions = summon[LayoutBinding[L]] .toBindings(layout) .map(getUnderlying) From dbcae9d87f794661637ee203a507d4e9e08a8b6a Mon Sep 17 00:00:00 2001 From: MarconZet <25779550+MarconZet@users.noreply.github.com> Date: Thu, 11 Sep 2025 22:25:59 +0200 Subject: [PATCH 52/59] Lazy and concurrent command buffer evaluation (#68) --- .../computenode/cyfra/spirv/SpirvTypes.scala | 1 + .../computenode/cyfra/core/Allocation.scala | 2 + .../cyfra/core/GBufferRegion.scala | 22 ++-- .../cyfra/samples/TestingStuff.scala | 12 +- .../cyfra/runtime/ExecutionHandler.scala | 36 +++--- .../cyfra/runtime/PendingExecution.scala | 118 ++++++++++++++++++ .../cyfra/runtime/VkAllocation.scala | 67 ++++++---- .../computenode/cyfra/runtime/VkBinding.scala | 72 +++++++++++ .../computenode/cyfra/runtime/VkBuffer.scala | 23 ---- .../computenode/cyfra/runtime/VkUniform.scala | 21 ---- .../cyfra/vulkan/VulkanContext.scala | 1 - .../cyfra/vulkan/command/CommandPool.scala | 37 ++---- .../cyfra/vulkan/command/Semaphore.scala | 2 +- .../cyfra/vulkan/memory/Buffer.scala | 21 +++- .../cyfra/vulkan/util/VulkanObject.scala | 1 + 15 files changed, 309 insertions(+), 127 deletions(-) create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala create mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala delete mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala delete mode 100644 cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala index 9fe1b386..7adeb972 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvTypes.scala @@ -54,6 +54,7 @@ private[cyfra] object SpirvTypes: case LGBooleanTag => 4 case v if v <:< LVecTag => vecSize(v) * typeStride(v.typeArgs.head) + case _ => 4 def typeStride(tag: Tag[?]): Int = typeStride(tag.tag) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala index bdc1d5a7..493b6a6e 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/Allocation.scala @@ -10,6 +10,8 @@ import izumi.reflect.Tag import java.nio.ByteBuffer trait Allocation: + def submitLayout[L <: Layout: LayoutBinding](layout: L): Unit + extension (buffer: GBinding[?]) def read(bb: ByteBuffer, offset: Int = 0): Unit diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala index cfd3ad8d..cfc041cf 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala @@ -1,6 +1,7 @@ package io.computenode.cyfra.core import io.computenode.cyfra.core.Allocation +import io.computenode.cyfra.core.GBufferRegion.MapRegion import io.computenode.cyfra.core.GProgram.BufferLengthSpec import io.computenode.cyfra.core.layout.{Layout, LayoutBinding} import io.computenode.cyfra.dsl.Value @@ -8,9 +9,15 @@ import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.GBuffer import izumi.reflect.Tag +import scala.util.chaining.given import java.nio.ByteBuffer -sealed trait GBufferRegion[ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding] +sealed trait GBufferRegion[ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding]: + def reqAllocBinding: LayoutBinding[ReqAlloc] = summon[LayoutBinding[ReqAlloc]] + def resAllocBinding: LayoutBinding[ResAlloc] = summon[LayoutBinding[ResAlloc]] + + def map[NewAlloc <: Layout: LayoutBinding](f: Allocation ?=> ResAlloc => NewAlloc): GBufferRegion[ReqAlloc, NewAlloc] = + MapRegion(this, (alloc: Allocation) => (resAlloc: ResAlloc) => f(using alloc)(resAlloc)) object GBufferRegion: @@ -24,20 +31,17 @@ object GBufferRegion: ) extends GBufferRegion[ReqAlloc, ResAlloc] extension [ReqAlloc <: Layout: LayoutBinding, ResAlloc <: Layout: LayoutBinding](region: GBufferRegion[ReqAlloc, ResAlloc]) - def map[NewAlloc <: Layout: LayoutBinding](f: Allocation ?=> ResAlloc => NewAlloc): GBufferRegion[ReqAlloc, NewAlloc] = - MapRegion(region, (alloc: Allocation) => (resAlloc: ResAlloc) => f(using alloc)(resAlloc)) - def runUnsafe(init: Allocation ?=> ReqAlloc, onDone: Allocation ?=> ResAlloc => Unit)(using cyfraRuntime: CyfraRuntime): Unit = cyfraRuntime.withAllocation: allocation => // noinspection ScalaRedundantCast - val steps: Seq[Allocation => Layout => Layout] = Seq.unfold(region: GBufferRegion[?, ?]): - case _: AllocRegion[?] => None + val steps: Seq[(Allocation => Layout => Layout, LayoutBinding[Layout])] = Seq.unfold(region: GBufferRegion[?, ?]): + case AllocRegion() => None case MapRegion(req, f) => - Some((f.asInstanceOf[Allocation => Layout => Layout], req)) + Some(((f.asInstanceOf[Allocation => Layout => Layout], req.resAllocBinding.asInstanceOf[LayoutBinding[Layout]]), req)) - val initAlloc = init(using allocation) + val initAlloc = init(using allocation).tap(allocation.submitLayout) val bodyAlloc = steps.foldLeft[Layout](initAlloc): (acc, step) => - step(allocation)(acc) + step._1(allocation)(acc).tap(allocation.submitLayout(_)(using step._2)) onDone(using allocation)(bodyAlloc.asInstanceOf[ResAlloc]) diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index 8b9a5014..2f1b2799 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -12,9 +12,16 @@ import io.computenode.cyfra.runtime.VkCyfraRuntime import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil +import java.nio.ByteBuffer import java.util.concurrent.atomic.AtomicInteger import scala.collection.parallel.CollectionConverters.given +def printBuffer(bb: ByteBuffer): Unit = + val l = bb.asIntBuffer() + val a = new Array[Int](l.remaining()) + l.get(a) + println(a.mkString(" ")) + object TestingStuff: given GContext = GContext() @@ -115,6 +122,7 @@ object TestingStuff: ) runtime.close() + printBuffer(rbb) val actual = (0 until 2 * 1024).map(i => result.get(i * 1) != 0) val expected = (0 until 1024).flatMap(x => Seq.fill(emitFilterParams.emitN)(x)).map(_ == emitFilterParams.filterValue) expected @@ -191,7 +199,7 @@ object TestingStuff: def testAddProgram10Times = given runtime: VkCyfraRuntime = VkCyfraRuntime() val bufferSize = 1280 - val params = AddProgramParams(bufferSize, addA = 0, addB = 1) + val params = AddProgramParams(bufferSize, addA = 5, addB = 10) val region = GBufferRegion .allocate[AddProgramExecLayout] .map: region => @@ -226,6 +234,8 @@ object TestingStuff: }, ) runtime.close() + + printBuffer(rbbList(0)) val expected = inData.map(_ + 11 * (params.addA + params.addB)) outBuffers.foreach { buf => (0 until bufferSize).foreach { i => diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index 782b2a85..9b9b385d 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -29,7 +29,7 @@ import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import izumi.reflect.Tag import org.lwjgl.vulkan.VK10.* import org.lwjgl.vulkan.VK13.{VK_ACCESS_2_SHADER_READ_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, vkCmdPipelineBarrier2} -import org.lwjgl.vulkan.{VkCommandBuffer, VkCommandBufferBeginInfo, VkDependencyInfo, VkMemoryBarrier2, VkSubmitInfo} +import org.lwjgl.vulkan.{VK13, VkCommandBuffer, VkCommandBufferBeginInfo, VkDependencyInfo, VkMemoryBarrier2, VkSubmitInfo} import scala.collection.mutable @@ -51,7 +51,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte .zip(layout) .map: case (set, bindings) => - set.update(bindings.map(x => VkAllocation.getUnderlying(x.binding))) + set.update(bindings.map(x => VkAllocation.getUnderlying(x.binding).buffer)) set val dispatches: Seq[Dispatch] = shaderCalls @@ -67,19 +67,15 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte else (steps.appended(step), dirty ++ bindings) val commandBuffer = recordCommandBuffer(executeSteps) - pushStack: stack => - val pCommandBuffer = stack.callocPointer(1).put(0, commandBuffer) - val submitInfo = VkSubmitInfo - .calloc(stack) - .sType$Default() - .pCommandBuffers(pCommandBuffer) - - val fence = new Fence() - timed("Vulkan render command"): - check(vkQueueSubmit(commandPool.queue.get, submitInfo, fence.get), "Failed to submit command buffer to queue") - fence.block().destroy() - commandPool.freeCommandBuffer(commandBuffer) - descriptorSets.flatten.foreach(dsManager.free) + val cleanup = () => + descriptorSets.flatten.foreach(dsManager.free) + commandPool.freeCommandBuffer(commandBuffer) + + val externalBindings = getAllBindings(executeSteps).map(VkAllocation.getUnderlying) + val deps = externalBindings.flatMap(_.execution.fold(Seq(_), _.toSeq)) + val pe = new PendingExecution(commandBuffer, deps, cleanup) + summon[VkAllocation].addExecution(pe) + externalBindings.foreach(_.execution = Left(pe)) // TODO we assume all accesses are read-write result private def interpret[Params, EL <: Layout: LayoutBinding, RL <: Layout: LayoutBinding]( @@ -202,7 +198,6 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte .flags(0) check(vkBeginCommandBuffer(commandBuffer, commandBufferBeginInfo), "Failed to begin recording command buffer") - steps.foreach: case PipelineBarrier => val memoryBarrier = VkMemoryBarrier2 // TODO don't synchronise everything @@ -228,11 +223,18 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte dispatch match case Direct(x, y, z) => vkCmdDispatch(commandBuffer, x, y, z) - case Indirect(buffer, offset) => vkCmdDispatchIndirect(commandBuffer, VkAllocation.getUnderlying(buffer).get, offset) + case Indirect(buffer, offset) => vkCmdDispatchIndirect(commandBuffer, VkAllocation.getUnderlying(buffer).buffer.get, offset) check(vkEndCommandBuffer(commandBuffer), "Failed to finish recording command buffer") commandBuffer + private def getAllBindings(steps: Seq[ExecutionStep]): Seq[GBinding[?]] = + steps + .flatMap: + case Dispatch(_, layout, _, _) => layout.flatten.map(_.binding) + case PipelineBarrier => Seq.empty + .distinct + object ExecutionHandler: case class ShaderCall(pipeline: ComputePipeline, layout: ShaderLayout, dispatch: DispatchType) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala new file mode 100644 index 00000000..9ed42d7d --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala @@ -0,0 +1,118 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.vulkan.command.{CommandPool, Fence, Semaphore} +import io.computenode.cyfra.vulkan.core.{Device, Queue} +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObject +import org.lwjgl.vulkan.VK10.VK_TRUE +import org.lwjgl.vulkan.VK13.{VK_PIPELINE_STAGE_2_COPY_BIT, vkQueueSubmit2} +import org.lwjgl.vulkan.{VK13, VkCommandBuffer, VkCommandBufferSubmitInfo, VkSemaphoreSubmitInfo, VkSubmitInfo2} + +import scala.collection.mutable + +/** A command buffer that is pending execution, along with its dependencies and cleanup actions. + * + * You can call `close()` only when `isFinished || isPending` is true + * + * You can call `destroy()` only when all dependants are `isClosed` + */ +class PendingExecution(protected val handle: VkCommandBuffer, val dependencies: Seq[PendingExecution], cleanup: () => Unit)(using Device): + private val semaphore: Semaphore = Semaphore() + private var fence: Option[Fence] = None + + def isPending: Boolean = fence.isEmpty + def isRunning: Boolean = fence.exists(f => f.isAlive && !f.isSignaled) + def isFinished: Boolean = fence.exists(f => !f.isAlive || f.isSignaled) + + def block(): Unit = fence.foreach(_.block()) + + private var closed = false + def isClosed: Boolean = closed + private def close(): Unit = + assert(isFinished || isPending, "Cannot close a PendingExecution that is not finished or pending") + if closed then return + cleanup() + closed = true + + private var destroyed = false + def destroy(): Unit = + if destroyed then return + close() + semaphore.destroy() + fence.foreach(x => if x.isAlive then x.destroy()) + destroyed = true + + /** Gathers all command buffers and their semaphores for submission to the queue, in the correct order. + * + * When you call this method, you are expected to submit the command buffers to the queue, and signal the provided fence when done. + * @param f + * The fence to signal when the command buffers are done executing. + * @return + * A sequence of tuples, each containing a command buffer, semaphore to signal, and a set of semaphores to wait on. + */ + private def gatherForSubmission(f: Fence): Seq[((VkCommandBuffer, Semaphore), Set[Semaphore])] = + if !isPending then return Seq.empty + val mySubmission = ((handle, semaphore), dependencies.map(_.semaphore).toSet) + fence = Some(f) + dependencies.flatMap(_.gatherForSubmission(f)).appended(mySubmission) + +object PendingExecution: + def executeAll(executions: Seq[PendingExecution], queue: Queue)(using Device): Fence = pushStack: stack => + assert(executions.forall(_.isPending), "All executions must be pending") + assert(executions.nonEmpty, "At least one execution must be provided") + + val fence = Fence() + + val exec: Seq[(Set[Semaphore], Set[(VkCommandBuffer, Semaphore)])] = + val gathered = executions.flatMap(_.gatherForSubmission(fence)) + val ordering = gathered.zipWithIndex.map(x => (x._1._1._1, x._2)).toMap + gathered.toSet.groupMap(_._2)(_._1).toSeq.sortBy(x => x._2.map(_._1).map(ordering).min) + + val submitInfos = VkSubmitInfo2.calloc(exec.size, stack) + exec.foreach: (semaphores, executions) => + val pCommandBuffersSI = VkCommandBufferSubmitInfo.calloc(executions.size, stack) + val signalSemaphoreSI = VkSemaphoreSubmitInfo.calloc(executions.size, stack) + executions.foreach: (cb, s) => + pCommandBuffersSI + .get() + .sType$Default() + .commandBuffer(cb) + .deviceMask(0) + signalSemaphoreSI + .get() + .sType$Default() + .semaphore(s.get) + .stageMask(VK13.VK_PIPELINE_STAGE_2_COPY_BIT | VK13.VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT) + + pCommandBuffersSI.flip() + signalSemaphoreSI.flip() + + val waitSemaphoreSI = VkSemaphoreSubmitInfo.calloc(semaphores.size, stack) + semaphores.foreach: s => + waitSemaphoreSI + .get() + .sType$Default() + .semaphore(s.get) + .stageMask(VK13.VK_PIPELINE_STAGE_2_COPY_BIT | VK13.VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT) + + waitSemaphoreSI.flip() + + submitInfos + .get() + .sType$Default() + .flags(0) + .pCommandBufferInfos(pCommandBuffersSI) + .pSignalSemaphoreInfos(signalSemaphoreSI) + .pWaitSemaphoreInfos(waitSemaphoreSI) + + submitInfos.flip() + + check(vkQueueSubmit2(queue.get, submitInfos, fence.get), "Failed to submit command buffer to queue") + fence + + def cleanupAll(executions: Seq[PendingExecution]): Unit = + def cleanupRec(ex: PendingExecution): Unit = + if !ex.isClosed then return + ex.close() + ex.dependencies.foreach(cleanupRec) + executions.foreach(cleanupRec) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index a038ac7b..ea80f7c6 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -14,37 +14,59 @@ import io.computenode.cyfra.vulkan.command.CommandPool import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} import io.computenode.cyfra.vulkan.util.Util.pushStack import io.computenode.cyfra.dsl.Value.Int32 +import io.computenode.cyfra.vulkan.core.Device import izumi.reflect.Tag import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil import org.lwjgl.vulkan.VK10 +import org.lwjgl.vulkan.VK13.VK_PIPELINE_STAGE_2_COPY_BIT import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT} import java.nio.ByteBuffer import scala.collection.mutable import scala.util.chaining.* -class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler)(using Allocator) extends Allocation: +class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler)(using Allocator, Device) extends Allocation: given VkAllocation = this + override def submitLayout[L <: Layout: LayoutBinding](layout: L): Unit = + val executions = summon[LayoutBinding[L]] + .toBindings(layout) + .map(getUnderlying) + .flatMap(_.execution.fold(Seq(_), _.toSeq)) + .filter(_.isPending) + + PendingExecution.executeAll(executions, commandPool.queue) + extension (buffer: GBinding[?]) def read(bb: ByteBuffer, offset: Int = 0): Unit = val size = bb.remaining() - getUnderlying(buffer) match - case buffer: Buffer.HostBuffer => buffer.copyTo(bb, offset) - case buffer: Buffer.DeviceBuffer => + buffer match + case VkBinding(buffer: Buffer.HostBuffer) => buffer.copyTo(bb, offset) + case binding: VkBinding[?] => + binding.materialise(commandPool.queue) val stagingBuffer = getStagingBuffer(size) - Buffer.copyBuffer(buffer, stagingBuffer, offset, 0, size, commandPool) + Buffer.copyBuffer(binding.buffer, stagingBuffer, offset, 0, size, commandPool) stagingBuffer.copyTo(bb, 0) + stagingBuffer.destroy() + case _ => throw new IllegalArgumentException(s"Tried to read from non-VkBinding $buffer") def write(bb: ByteBuffer, offset: Int = 0): Unit = val size = bb.remaining() - getUnderlying(buffer) match - case buffer: Buffer.HostBuffer => buffer.copyFrom(bb, offset) - case buffer: Buffer.DeviceBuffer => + buffer match + case VkBinding(buffer: Buffer.HostBuffer) => buffer.copyFrom(bb, offset) + case binding: VkBinding[?] => + binding.materialise(commandPool.queue) val stagingBuffer = getStagingBuffer(size) - stagingBuffer.copyFrom(bb, offset) - Buffer.copyBuffer(stagingBuffer, buffer, 0, offset, size, commandPool) + stagingBuffer.copyFrom(bb, 0) + val cb = Buffer.copyBufferCommandBuffer(stagingBuffer, binding.buffer, 0, offset, size, commandPool) + val cleanup = () => + commandPool.freeCommandBuffer(cb) + stagingBuffer.destroy() + val pe = new PendingExecution(cb, binding.execution.fold(Seq(_), _.toSeq), cleanup) + addExecution(pe) + binding.execution = Left(pe) + case _ => throw new IllegalArgumentException(s"Tried to write to non-VkBinding $buffer") extension (buffers: GBuffer.type) def apply[T <: Value: {Tag, FromExpr}](length: Int): GBuffer[T] = @@ -78,24 +100,21 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) case _ => ??? direct(bb) + private val executions = mutable.Buffer[PendingExecution]() + + def addExecution(pe: PendingExecution): Unit = + executions += pe + private val bindings = mutable.Buffer[VkUniform[?] | VkBuffer[?]]() private[cyfra] def close(): Unit = - bindings.map(getUnderlying).foreach(_.destroy()) - stagingBuffer.foreach(_.destroy()) + executions.foreach(_.destroy()) + bindings.map(getUnderlying).foreach(_.buffer.destroy()) - private var stagingBuffer: Option[Buffer.HostBuffer] = None private def getStagingBuffer(size: Int): Buffer.HostBuffer = - stagingBuffer match - case Some(buffer) if buffer.size >= size => buffer - case _ => - stagingBuffer.foreach(_.destroy()) - val newBuffer = Buffer.HostBuffer(size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT) - stagingBuffer = Some(newBuffer) - newBuffer + Buffer.HostBuffer(size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT) object VkAllocation: - private[runtime] def getUnderlying(buffer: GBinding[?]): Buffer = + private[runtime] def getUnderlying(buffer: GBinding[?]): VkBinding[?] = buffer match - case buffer: VkBuffer[?] => buffer.underlying - case uniform: VkUniform[?] => uniform.underlying - case _ => throw new IllegalArgumentException(s"Tried to get underlying of non-VkBinding $buffer") + case buffer: VkBinding[?] => buffer + case _ => throw new IllegalArgumentException(s"Tried to get underlying of non-VkBinding $buffer") diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala new file mode 100644 index 00000000..6283ad78 --- /dev/null +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala @@ -0,0 +1,72 @@ +package io.computenode.cyfra.runtime + +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.spirv.SpirvTypes.typeStride +import izumi.reflect.Tag +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer} +import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} +import io.computenode.cyfra.vulkan.core.Queue +import io.computenode.cyfra.vulkan.core.Device +import izumi.reflect.Tag +import io.computenode.cyfra.spirv.SpirvTypes.typeStride +import org.lwjgl.vulkan.VK10 +import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT} +import io.computenode.cyfra.dsl.Value +import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.GUniform +import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} +import izumi.reflect.Tag +import org.lwjgl.vulkan.VK10 +import org.lwjgl.vulkan.VK10.* + +import scala.collection.mutable + +sealed abstract class VkBinding[T <: Value: {Tag, FromExpr}](val buffer: Buffer): + val sizeOfT: Int = typeStride(summon[Tag[T]]) + + /** Holds either: + * 1. a single execution that writes to this buffer + * 1. multiple executions that read from this buffer + */ + var execution: Either[PendingExecution, mutable.Buffer[PendingExecution]] = Right(mutable.Buffer.empty) + + def materialise(queue: Queue)(using Device): Unit = + val (pendingExecs, runningExecs) = execution.fold(Seq(_), _.toSeq).partition(_.isPending) // TODO better handle read only executions + if pendingExecs.nonEmpty then + val fence = PendingExecution.executeAll(pendingExecs, queue) + fence.block() + PendingExecution.cleanupAll(pendingExecs) + + runningExecs.foreach(_.block()) + PendingExecution.cleanupAll(runningExecs) + +object VkBinding: + def unapply(binding: GBinding[?]): Option[Buffer] = binding match + case b: VkBinding[?] => Some(b.buffer) + case _ => None + +class VkBuffer[T <: Value: {Tag, FromExpr}] private (val length: Int, underlying: Buffer) extends VkBinding(underlying) with GBuffer[T] + +object VkBuffer: + private final val Padding = 64 + private final val UsageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT + + def apply[T <: Value: {Tag, FromExpr}](length: Int)(using Allocator): VkBuffer[T] = + val sizeOfT = typeStride(summon[Tag[T]]) + val size = (length * sizeOfT + Padding - 1) / Padding * Padding + val buffer = new Buffer.DeviceBuffer(size, UsageFlags) + new VkBuffer[T](length, buffer) + +class VkUniform[T <: Value: {Tag, FromExpr}] private (underlying: Buffer) extends VkBinding[T](underlying) with GUniform[T] + +object VkUniform: + private final val UsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT + + def apply[T <: Value: {Tag, FromExpr}]()(using Allocator): VkUniform[T] = + val sizeOfT = typeStride(summon[Tag[T]]) + val buffer = new Buffer.DeviceBuffer(sizeOfT, UsageFlags) + new VkUniform[T](buffer) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala deleted file mode 100644 index cda73868..00000000 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBuffer.scala +++ /dev/null @@ -1,23 +0,0 @@ -package io.computenode.cyfra.runtime - -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Value.FromExpr -import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer} -import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} -import izumi.reflect.Tag -import io.computenode.cyfra.spirv.SpirvTypes.typeStride -import org.lwjgl.vulkan.VK10 -import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT} - -class VkBuffer[T <: Value: {Tag, FromExpr}] private (var length: Int, val underlying: Buffer) extends GBuffer[T]: - val sizeOfT: Int = typeStride(summon[Tag[T]]) - -object VkBuffer: - private final val Padding = 64 - private final val UsageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT - - def apply[T <: Value: {Tag, FromExpr}](length: Int)(using Allocator): VkBuffer[T] = - val sizeOfT = typeStride(summon[Tag[T]]) - val size = (length * sizeOfT + Padding - 1) / Padding * Padding - val buffer = new Buffer.DeviceBuffer(size, UsageFlags) - new VkBuffer[T](length, buffer) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala deleted file mode 100644 index f8c75da7..00000000 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkUniform.scala +++ /dev/null @@ -1,21 +0,0 @@ -package io.computenode.cyfra.runtime - -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Value.FromExpr -import io.computenode.cyfra.dsl.binding.GUniform -import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} -import izumi.reflect.Tag -import org.lwjgl.vulkan.VK10 -import org.lwjgl.vulkan.VK10.* - -class VkUniform[T <: Value: {Tag, FromExpr}] private (val underlying: Buffer) extends GUniform[T]: - val sizeOfT: Int = 4 - -object VkUniform: - private final val UsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | - VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT - - def apply[T <: Value: {Tag, FromExpr}]()(using Allocator): VkUniform[T] = - val sizeOfT = 4 // typeStride(summon[Tag[T]]) - val buffer = new Buffer.DeviceBuffer(sizeOfT, UsageFlags) - new VkUniform[T](buffer) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala index 9c8c99c6..67d612fe 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala @@ -17,7 +17,6 @@ import scala.jdk.CollectionConverters.* private[cyfra] object VulkanContext: val ValidationLayer: String = "VK_LAYER_KHRONOS_validation" private val ValidationLayers: Boolean = System.getProperty("io.computenode.cyfra.vulkan.validation", "false").toBoolean - if Configuration.STACK_SIZE.get() < 100 then logger.warn(s"Small stack size. Increase with org.lwjgl.system.stackSize") private[cyfra] class VulkanContext: private val instance: Instance = new Instance(ValidationLayers) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala index 3db65668..11d21e1a 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/CommandPool.scala @@ -39,35 +39,18 @@ private[cyfra] abstract class CommandPool private (flags: Int, val queue: Queue) check(vkAllocateCommandBuffers(device.get, allocateInfo, pointerBuffer), "Failed to allocate command buffers") 0 until n map (i => pointerBuffer.get(i)) map (new VkCommandBuffer(_, device.get)) - def executeCommand(block: VkCommandBuffer => Unit): Unit = - val commandBuffer = beginSingleTimeCommands() - block(commandBuffer) - endSingleTimeCommands(commandBuffer).block().destroy() - freeCommandBuffer(commandBuffer) - - private def beginSingleTimeCommands(): VkCommandBuffer = - pushStack: stack => - val commandBuffer = this.createCommandBuffer() - - val beginInfo = VkCommandBufferBeginInfo - .calloc(stack) - .sType$Default() - .flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) + def recordSingleTimeCommand(block: VkCommandBuffer => Unit): VkCommandBuffer = pushStack: stack => + val commandBuffer = createCommandBuffer() - check(vkBeginCommandBuffer(commandBuffer, beginInfo), "Failed to begin single time command buffer") - commandBuffer + val beginInfo = VkCommandBufferBeginInfo + .calloc(stack) + .sType$Default() + .flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) - private def endSingleTimeCommands(commandBuffer: VkCommandBuffer): Fence = - pushStack: stack => - vkEndCommandBuffer(commandBuffer) - val pointerBuffer = stack.callocPointer(1).put(0, commandBuffer) - val submitInfo = VkSubmitInfo - .calloc(stack) - .sType$Default() - .pCommandBuffers(pointerBuffer) - val fence = Fence() - check(vkQueueSubmit(queue.get, submitInfo, fence.get), "Failed to submit single time command buffer") - fence + check(vkBeginCommandBuffer(commandBuffer, beginInfo), "Failed to begin single time command buffer") + block(commandBuffer) + check(vkEndCommandBuffer(commandBuffer), "Failed to end single time command buffer") + commandBuffer def freeCommandBuffer(commandBuffer: VkCommandBuffer*): Unit = pushStack: stack => diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala index 04034b1c..2e86ef68 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Semaphore.scala @@ -9,7 +9,7 @@ import org.lwjgl.vulkan.VkSemaphoreCreateInfo /** @author * MarconZet Created 30.10.2019 */ -private[cyfra] class Semaphore(using device: Device) extends VulkanObjectHandle: +private[cyfra] class Semaphore()(using device: Device) extends VulkanObjectHandle: protected val handle: Long = pushStack: stack => val semaphoreCreateInfo = VkSemaphoreCreateInfo .calloc(stack) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala index 963aa1cd..c1f34b40 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/memory/Buffer.scala @@ -1,13 +1,14 @@ package io.computenode.cyfra.vulkan.memory import io.computenode.cyfra.vulkan.command.{CommandPool, Fence} +import io.computenode.cyfra.vulkan.core.Device import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObjectHandle import org.lwjgl.system.MemoryUtil.* import org.lwjgl.util.vma.Vma.* import org.lwjgl.util.vma.VmaAllocationCreateInfo import org.lwjgl.vulkan.VK10.* -import org.lwjgl.vulkan.{VkBufferCopy, VkBufferCreateInfo} +import org.lwjgl.vulkan.{VkBufferCopy, VkBufferCreateInfo, VkCommandBuffer, VkSubmitInfo} import java.nio.ByteBuffer @@ -61,8 +62,22 @@ object Buffer: def copyFrom(src: ByteBuffer, dstOffset: Int): Unit = pushStack: stack => vmaCopyMemoryToAllocation(allocator.get, src, allocation, dstOffset) - def copyBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool): Unit = - commandPool.executeCommand: commandBuffer => + def copyBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool)(using Device): Unit = pushStack: + stack => + val cb = copyBufferCommandBuffer(src, dst, srcOffset, dstOffset, bytes, commandPool) + + val pCB = stack.callocPointer(1).put(0, cb) + val submitInfo = VkSubmitInfo + .calloc(stack) + .sType$Default() + .pCommandBuffers(pCB) + + val fence = Fence() + check(vkQueueSubmit(commandPool.queue.get, submitInfo, fence.get), "Failed to submit single time command buffer") + fence.block().destroy() + + def copyBufferCommandBuffer(src: Buffer, dst: Buffer, srcOffset: Int, dstOffset: Int, bytes: Int, commandPool: CommandPool): VkCommandBuffer = + commandPool.recordSingleTimeCommand: commandBuffer => pushStack: stack => val copyRegion = VkBufferCopy .calloc(1, stack) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala index 3ec34726..50d3baf7 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/util/VulkanObject.scala @@ -6,6 +6,7 @@ package io.computenode.cyfra.vulkan.util private[cyfra] abstract class VulkanObject[T]: protected val handle: T private var alive: Boolean = true + def isAlive: Boolean = alive def get: T = if !alive then throw new IllegalStateException() From 4eb491ea5369a8b2a710ee7d19b283003212c62b Mon Sep 17 00:00:00 2001 From: Szymon Date: Thu, 11 Sep 2025 22:52:12 +0200 Subject: [PATCH 53/59] Progres on porting GFunc --- .../cyfra/core/GBufferRegion.scala | 2 +- .../io/computenode/cyfra/core/GCodec.scala | 37 ++++---- .../cyfra/core/archive/GFunction.scala | 93 ++++++++++++++++--- .../cyfra/core/layout/LayoutStruct.scala | 34 ++++++- .../cyfra/dsl/binding/GBinding.scala | 2 +- .../cyfra/dsl/collections/GArray2D.scala | 5 +- .../cyfra/e2e/dsl/GStructE2eTest.scala | 5 +- .../cyfra/e2e/fs2interop/Fs2Tests.scala | 47 +--------- .../computenode/cyfra/fs2interop/GPipe.scala | 13 +-- .../cyfra/fs2interop/GPipeLegacy.scala | 39 -------- .../cyfra/runtime/PendingExecution.scala | 4 +- .../cyfra/runtime/VkAllocation.scala | 1 - .../computenode/cyfra/runtime/VkBinding.scala | 5 +- .../cyfra/vulkan/command/Fence.scala | 2 +- 14 files changed, 151 insertions(+), 138 deletions(-) rename cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala => cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala (67%) delete mode 100644 cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipeLegacy.scala diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala index b80bc679..5d613a56 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala @@ -36,7 +36,7 @@ object GBufferRegion: // noinspection ScalaRedundantCast val steps: Seq[(Allocation => Layout => Layout, LayoutBinding[Layout])] = Seq.unfold(region: GBufferRegion[?, ?]): - case AllocRegion => None + case AllocRegion() => None case MapRegion(req, f) => Some(((f.asInstanceOf[Allocation => Layout => Layout], req.resAllocBinding.asInstanceOf[LayoutBinding[Layout]]), req)) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala similarity index 67% rename from cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala rename to cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala index b148a53b..fe059872 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/Bridge.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala @@ -1,21 +1,21 @@ // scala -package io.computenode.cyfra.fs2interop +package io.computenode.cyfra.core -import io.computenode.cyfra.core.archive.mem.GMem.fRGBA +import io.computenode.cyfra.core.archive.mem.GMem.{fRGBA, totalStride} import io.computenode.cyfra.dsl.* -import fs2.* +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} +import izumi.reflect.Tag import java.nio.{ByteBuffer, ByteOrder} -import izumi.reflect.Tag import scala.reflect.ClassTag -trait Bridge[CyfraType <: Value: FromExpr: Tag, ScalaType: ClassTag]: - def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[ScalaType]): ByteBuffer +trait GCodec[CyfraType <: Value: {FromExpr, Tag}, ScalaType: ClassTag]: + def toByteBuffer(inBuf: ByteBuffer, arr: Array[ScalaType]): ByteBuffer def fromByteBuffer(outBuf: ByteBuffer, arr: Array[ScalaType]): Array[ScalaType] -object Bridge: - given Bridge[Int32, Int]: - def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[Int]): ByteBuffer = +object GCodec: + given GCodec[Int32, Int]: + def toByteBuffer(inBuf: ByteBuffer, chunk: Array[Int]): ByteBuffer = inBuf.clear().order(ByteOrder.nativeOrder()) val ib = inBuf.asIntBuffer() ib.put(chunk.toArray[Int]) @@ -27,8 +27,8 @@ object Bridge: outBuf.rewind() arr - given Bridge[Float32, Float]: - def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[Float]): ByteBuffer = + given GCodec[Float32, Float]: + def toByteBuffer(inBuf: ByteBuffer, chunk: Array[Float]): ByteBuffer = inBuf.clear().order(ByteOrder.nativeOrder()) val fb = inBuf.asFloatBuffer() fb.put(chunk.toArray[Float]) @@ -40,11 +40,10 @@ object Bridge: outBuf.rewind() arr - given Bridge[Vec4[Float32], fRGBA]: - def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[fRGBA]): ByteBuffer = + given GCodec[Vec4[Float32], fRGBA]: + def toByteBuffer(inBuf: ByteBuffer, arr: Array[fRGBA]): ByteBuffer = inBuf.clear().order(ByteOrder.nativeOrder()) - val vecs = chunk.toArray[fRGBA] - vecs.foreach: + arr.foreach: case (x, y, z, a) => inBuf.putFloat(x) inBuf.putFloat(y) @@ -59,10 +58,10 @@ object Bridge: outBuf.rewind() arr - given Bridge[GBoolean, Boolean]: - def toByteBuffer(inBuf: ByteBuffer, chunk: Chunk[Boolean]): ByteBuffer = - inBuf.put(chunk.toArray.asInstanceOf[Array[Byte]]).flip() + given GCodec[GBoolean, Boolean]: + def toByteBuffer(inBuf: ByteBuffer, arr: Array[Boolean]): ByteBuffer = + inBuf.put(arr.asInstanceOf[Array[Byte]]).flip() inBuf def fromByteBuffer(outBuf: ByteBuffer, arr: Array[Boolean]): Array[Boolean] = outBuf.get(arr.asInstanceOf[Array[Byte]]).flip() - arr \ No newline at end of file + arr diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala index c5613bb7..2798508c 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala @@ -1,28 +1,99 @@ package io.computenode.cyfra.core.archive +import io.computenode.cyfra.core.{CyfraRuntime, GBufferRegion, GCodec, GProgram} +import io.computenode.cyfra.core.GBufferRegion.* +import io.computenode.cyfra.core.GProgram.StaticDispatch import io.computenode.cyfra.core.archive.GFunction +import io.computenode.cyfra.core.archive.GFunction.{GFunctionLayout, GFunctionParams} +import io.computenode.cyfra.core.layout.{Layout, LayoutBinding, LayoutStruct} import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.binding.{GBuffer, GUniform} import io.computenode.cyfra.dsl.collections.{GArray, GArray2D} +import io.computenode.cyfra.dsl.gio.GIO import io.computenode.cyfra.dsl.struct.* import io.computenode.cyfra.dsl.{*, given} - +import io.computenode.cyfra.spirv.SpirvTypes.typeStride +import io.computenode.cyfra.spirv.compilers.SpirvProgramCompiler.totalStride import izumi.reflect.Tag +import org.lwjgl.BufferUtils + +import scala.reflect.ClassTag + -case class GFunction[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: (G, Int32, GArray[H]) => R)( - implicit context: GContext, +case class GFunction[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( + underlying: GProgram[GFunctionParams, GFunctionLayout[G, H, R]] ): - def arrayInputs: List[Tag[?]] = List(summon[Tag[H]]) - def arrayOutputs: List[Tag[?]] = List(summon[Tag[R]]) - val pipeline: Nothing = ??? + def run[HS, GS, RS : ClassTag] (input: Seq[HS], g: GS)( + using gCodec: GCodec[G, GS], + hCodec: GCodec[H, HS], + rCodec: GCodec[R, RS], + runtime: CyfraRuntime + ): Seq[RS] = + + val inTypeSize = typeStride(Tag.apply[H]) + val outTypeSize = typeStride(Tag.apply[R]) + val uniformStride = totalStride(summon[GStructSchema[G]]) + val params = GFunctionParams(size = input.size) + + val in = BufferUtils.createByteBuffer(inTypeSize * input.size) + val out = BufferUtils.createByteBuffer(outTypeSize * input.size) + val uniform = BufferUtils.createByteBuffer(uniformStride) + + GBufferRegion.allocate[GFunctionLayout[G, H, R]] + .map: layout => + underlying.execute(params, layout) + .runUnsafe( + init = GFunctionLayout( + in = GBuffer[H](in), + out = GBuffer[R](outTypeSize * input.size), + uniform = GUniform[G](uniform), + ), + onDone = layout => + layout.out.read(out) + ) + val resultArray = Array.ofDim[RS](input.size) + rCodec.fromByteBuffer(out, resultArray).toSeq + + object GFunction: - def apply[H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: H => R)(using context: GContext): GFunction[GStruct.Empty, H, R] = - new GFunction[GStruct.Empty, H, R]((_, index: Int32, gArray: GArray[H]) => fn(gArray.at(index))) - + case class GFunctionParams( + size: Int + ) + + case class GFunctionLayout[G <: GStruct[G], H <: Value, R <: Value]( + in: GBuffer[H], + out: GBuffer[R], + uniform: GUniform[G] + ) extends Layout + + def apply[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: (G, Int32, GBuffer[H]) => R): GFunction[G, H, R] = + val body = (layout: GFunctionLayout[G, H, R]) => + val g = layout.uniform.read + val result = fn(g, GIO.invocationId, layout.in) + layout.out.write(GIO.invocationId, result) + + summon[LayoutStruct[GFunctionLayout[G, H, R]]] + + GFunction( + underlying = GProgram.apply[GFunctionParams, GFunctionLayout[G, H, R]]( + layout = (p: GFunctionParams) => GFunctionLayout[G, H, R]( + in = GBuffer[H](p.size), + out = GBuffer[R](p.size), + uniform = GUniform[G](), + ), + dispatch = (l, p) => StaticDispatch((p.size + 255) / 256, 1, 1), + workgroupSize = (256, 1, 1), + )(body) + ) + + def apply[H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: H => R): GFunction[GStruct.Empty, H, R] = + GFunction[GStruct.Empty, H, R]((g: GStruct.Empty, index: Int32, a: GBuffer[H]) => fn(a.read(index))) + def from2D[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( width: Int, - )(fn: (G, (Int32, Int32), GArray2D[H]) => R)(using context: GContext): GFunction[G, H, R] = - GFunction[G, H, R]((g: G, index: Int32, a: GArray[H]) => + )(fn: (G, (Int32, Int32), GArray2D[H]) => R): GFunction[G, H, R] = + GFunction[G, H, R]((g: G, index: Int32, a: GBuffer[H]) => val x: Int32 = index mod width val y: Int32 = index / width val arr = GArray2D(width, a) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala index 76d8ffa8..69327f73 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala @@ -36,7 +36,18 @@ object LayoutStruct: report.errorAndAbort("LayoutStruct can only be derived for case classes with GBinding elements") val valueTypes = fieldTypes.map: ftype => - (ftype, ftype.typeArgs.headOption.getOrElse(report.errorAndAbort("GBuffer must have a value type"))) + ftype match + case AppliedType(_, args) if args.nonEmpty => + val valueType = args.head + // Ensure we're working with the original type parameter, not the instance type + val resolvedType = valueType match + case tr if tr.typeSymbol.isTypeParam => + // Find the corresponding type parameter from the original class + tpe.typeArgs.find(_.typeSymbol.name == tr.typeSymbol.name).getOrElse(tr) + case tr => tr + (ftype, resolvedType) + case _ => + report.errorAndAbort("GBinding must have a value type") // summon izumi tags val typeGivens = valueTypes.map: @@ -48,10 +59,10 @@ object LayoutStruct: farg.asType, Expr.summon[Tag[t]] match case Some(tagExpr) => tagExpr - case None => report.errorAndAbort(s"Cannot summon Tag for type ${tpe.show}"), + case None => report.errorAndAbort(s"Cannot summon Tag for type ${farg.show}"), Expr.summon[FromExpr[t]] match case Some(fromExpr) => fromExpr - case None => report.errorAndAbort(s"Cannot summon FromExpr for type ${tpe.show}"), + case None => report.errorAndAbort(s"Cannot summon FromExpr for type ${farg.show}"), ) val buffers = typeGivens.zipWithIndex.map: @@ -70,8 +81,21 @@ object LayoutStruct: } val constructor = sym.primaryConstructor - - val layoutInstance = Apply(Select(New(TypeIdent(sym)), constructor), buffers.map(_.asTerm)) + report.info(s"Constructor: ${constructor.fullName} with params ${constructor.paramSymss.flatten.map(_.name).mkString(", ")}") + + val typeArgs = tpe.typeArgs + + val layoutInstance = + if (typeArgs.isEmpty) then + Apply(Select(New(TypeIdent(sym)), constructor), buffers.map(_.asTerm)) + else + Apply( + TypeApply( + Select(New(TypeIdent(sym)), constructor), + typeArgs.map(arg => TypeTree.of(using arg.asType)) + ), + buffers.map(_.asTerm) + ) val layoutRef = layoutInstance.asExprOf[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala index ce003c87..27f25d04 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/binding/GBinding.scala @@ -23,7 +23,7 @@ trait GUniform[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}] extends GBinding def read: T = fromExprEval(ReadUniform(this)) def write(value: T): GIO[Empty] = WriteUniform(this, value) - + def schema = summon[GStructSchema[T]] object GUniform: diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala index e532eea2..9671e288 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray2D.scala @@ -6,8 +6,9 @@ import io.computenode.cyfra.dsl.algebra.ScalarAlgebra.{*, given} import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag import io.computenode.cyfra.dsl.Value.FromExpr +import io.computenode.cyfra.dsl.binding.GBuffer // todo temporary -class GArray2D[T <: Value: {Tag, FromExpr}](width: Int, val arr: GArray[T]): +class GArray2D[T <: Value: {Tag, FromExpr}](width: Int, val arr: GBuffer[T]): def at(x: Int32, y: Int32)(using Source): T = - arr.at(y * width + x) + arr.read(y * width + x) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala index 20e15843..bfc88e0e 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala @@ -2,6 +2,7 @@ package io.computenode.cyfra.e2e.dsl import io.computenode.cyfra.core.archive.* import io.computenode.cyfra.core.archive.mem.* +import io.computenode.cyfra.dsl.binding.GBuffer import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} @@ -19,7 +20,7 @@ class GStructE2eTest extends munit.FunSuite: test("GStruct passed as uniform"): UniformContext.withUniform(custom1): val gf: GFunction[Custom, Float32, Float32] = GFunction: - case (Custom(f, v), index, gArray) => v.*(f).dot(v) + gArray.at(index) * f + case (Custom(f, v), index: Int32, gBuff: GBuffer[Float32]) => v.*(f).dot(v) + gBuff.read(index) * f val inArr = (0 to 255).map(_.toFloat).toArray val gmem = FloatMem(inArr) @@ -34,7 +35,7 @@ class GStructE2eTest extends munit.FunSuite: test("GStruct of GStructs".ignore): UniformContext.withUniform(nested): val gf: GFunction[Nested, Float32, Float32] = GFunction: - case (Nested(Custom(f1, v1), Custom(f2, v2)), index, gArray) => + case (Nested(Custom(f1, v1), Custom(f2, v2)), index, gArray: GBuffer[Float32]) => v1.*(f2).dot(v2) + gArray.at(index) * f1 val inArr = (0 to 255).map(_.toFloat).toArray diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala index 289426ec..e5c2667f 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala @@ -6,7 +6,6 @@ import GMem.fRGBA import io.computenode.cyfra.dsl.{*, given} import algebra.VectorAlgebra import io.computenode.cyfra.fs2interop.* -import Bridge.given import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.runtime.VkCyfraRuntime import fs2.{io as fs2io, *} @@ -68,48 +67,4 @@ class Fs2Tests extends munit.FunSuite: result .zip(expected) .foreach: (res, exp) => - assert(res == exp, s"Expected $exp, got $res") - -class Fs2LegacyTests extends munit.FunSuite: - given gc: GContext = GContext() - import GPipeLegacy.* - - test("fs2 Float stream (legacy)"): - val inSeq = (0 to 255).map(_.toFloat) - val inStream = Stream.emits(inSeq) - val outStream = inStream.gPipeFloat(_ + 1f).toList - val expected = inStream.map(_ + 1f).toList - outStream - .zip(expected) - .foreach: (res, exp) => - assert(Math.abs(res - exp) < 0.001f, s"Expected $exp but got $res") - - test("fs2 Int stream (legacy)"): - val inSeq = 0 to 255 - val inStream = Stream.emits(inSeq) - val outStream = inStream.gPipeInt(_ + 1).toList - val expected = inStream.map(_ + 1).toList - outStream - .zip(expected) - .foreach: (res, exp) => - assert(res == exp, s"Expected $exp but got $res") - - test("fs2 Vec4Float stream (legacy)"): - val k = -2.1f - val f = (1.2f, 2.3f, 3.4f, 4.5f) - val v = VectorAlgebra.vec4.tupled(f) - - val inSeq: Seq[fRGBA] = (0 to 1023) - .map(_.toFloat) - .grouped(4) - .map: - case Seq(a, b, c, d) => (a, b, c, d) - .toSeq - val inStream = Stream.emits(inSeq) - val outStream = inStream.gPipeVec4(vec => (-vec).*(k).+(v)).toList - val expected = inStream.map(vec => vec.neg.scl(k).add(f)).toList - - outStream - .zip(expected) - .foreach: (res, exp) => - assert(res.close(exp)(0.001f), s"Expected $exp but got $res") + assert(res == exp, s"Expected $exp, got $res") \ No newline at end of file diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 0efefce1..f75ac208 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -1,6 +1,6 @@ package io.computenode.cyfra.fs2interop -import io.computenode.cyfra.core.{Allocation, layout} +import io.computenode.cyfra.core.{Allocation, layout, GCodec} import layout.Layout import io.computenode.cyfra.core.{CyfraRuntime, GBufferRegion, GExecution, GProgram} import io.computenode.cyfra.dsl.{*, given} @@ -13,6 +13,7 @@ import struct.GStruct import GStruct.Empty import Empty.given import fs2.* + import java.nio.ByteBuffer import org.lwjgl.BufferUtils import izumi.reflect.Tag @@ -22,7 +23,7 @@ import scala.reflect.ClassTag object GPipe: def map[F[_], C1 <: Value: {FromExpr, Tag}, C2 <: Value: {FromExpr, Tag}, S1: ClassTag, S2: ClassTag]( f: C1 => C2, - )(using cr: CyfraRuntime, bridge1: Bridge[C1, S1], bridge2: Bridge[C2, S2]): Pipe[F, S1, S2] = + )(using cr: CyfraRuntime, bridge1: GCodec[C1, S1], bridge2: GCodec[C2, S2]): Pipe[F, S1, S2] = (stream: Stream[F, S1]) => case class Params(inSize: Int) case class PLayout(in: GBuffer[C1], out: GBuffer[C2]) extends Layout @@ -58,7 +59,7 @@ object GPipe: stream .chunkN(params.inSize) .flatMap: chunk => - bridge1.toByteBuffer(inBuf, chunk) + bridge1.toByteBuffer(inBuf, chunk.toArray) region.runUnsafe(init = PLayout( in = GBuffer[C1](inBuf), out = GBuffer[C2](outBuf)), @@ -68,10 +69,10 @@ object GPipe: Stream.emits(bridge2.fromByteBuffer(outBuf, new Array[S2](params.inSize))) // Overload for convenient single type version - def map[F[_], C <: Value: FromExpr: Tag, S: ClassTag](f: C => C)(using CyfraRuntime, Bridge[C, S]): Pipe[F, S, S] = + def map[F[_], C <: Value: FromExpr: Tag, S: ClassTag](f: C => C)(using CyfraRuntime, GCodec[C, S]): Pipe[F, S, S] = map[F, C, C, S, S](f) - def filter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: Bridge[C, S]): Pipe[F, S, S] = + def filter[F[_], C <: Value: FromExpr: Tag, S: ClassTag](pred: C => GBoolean)(using cr: CyfraRuntime, bridge: GCodec[C, S]): Pipe[F, S, S] = (stream: Stream[F, S]) => val chunkInSize = 256 @@ -220,7 +221,7 @@ object GPipe: stream .chunkN(chunkInSize) .flatMap: chunk => - bridge.toByteBuffer(predBuf, chunk) + bridge.toByteBuffer(predBuf, chunk.toArray) region.runUnsafe( init = FilterLayout(in = GBuffer[C](predBuf), scan = GBuffer[Int32](filterParams.inSize), out = GBuffer[C](filterParams.inSize)), onDone = layout => { diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipeLegacy.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipeLegacy.scala deleted file mode 100644 index 78d36209..00000000 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipeLegacy.scala +++ /dev/null @@ -1,39 +0,0 @@ -package io.computenode.cyfra.fs2interop - -import io.computenode.cyfra.core.archive.*, mem.*, GMem.fRGBA -import io.computenode.cyfra.dsl.{*, given} -import struct.GStruct, GStruct.Empty, Empty.given - -import fs2.* - -// legacy stuff working with GFunction -object GPipeLegacy: - extension (stream: Stream[Pure, Float]) - def gPipeFloat(fn: Float32 => Float32)(using GContext): Stream[Pure, Float] = - val gf: GFunction[Empty, Float32, Float32] = GFunction(fn) - stream - .chunkMin(256) - .flatMap: chunk => - val gmem = FloatMem(chunk.toArray) - val res = gmem.map(gf).asInstanceOf[FloatMem].toArray - Stream.emits(res) - - extension (stream: Stream[Pure, Int]) - def gPipeInt(fn: Int32 => Int32)(using GContext): Stream[Pure, Int] = - val gf: GFunction[Empty, Int32, Int32] = GFunction(fn) - stream - .chunkMin(256) - .flatMap: chunk => - val gmem = IntMem(chunk.toArray) - val res = gmem.map(gf).asInstanceOf[IntMem].toArray - Stream.emits(res) - - extension (stream: Stream[Pure, fRGBA]) - def gPipeVec4(fn: Vec4[Float32] => Vec4[Float32])(using GContext): Stream[Pure, fRGBA] = - val gf: GFunction[Empty, Vec4[Float32], Vec4[Float32]] = GFunction(fn) - stream - .chunkMin(256) - .flatMap: chunk => - val gmem = Vec4FloatMem(chunk.toArray) - val res = gmem.map(gf).asInstanceOf[Vec4FloatMem].toArray - Stream.emits(res) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala index 1fe09725..9ed42d7d 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/PendingExecution.scala @@ -21,8 +21,8 @@ class PendingExecution(protected val handle: VkCommandBuffer, val dependencies: private var fence: Option[Fence] = None def isPending: Boolean = fence.isEmpty - def isRunning: Boolean = fence.exists(!_.isSignaled) - def isFinished: Boolean = fence.exists(_.isSignaled) + def isRunning: Boolean = fence.exists(f => f.isAlive && !f.isSignaled) + def isFinished: Boolean = fence.exists(f => !f.isAlive || f.isSignaled) def block(): Unit = fence.foreach(_.block()) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index f7935491..4a3d3024 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -91,7 +91,6 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) private def direct[T <: GStruct[?]: {Tag, FromExpr, GStructSchema}](buff: ByteBuffer): GUniform[T] = GUniform[T](buff) - def getInitProgramLayout: GProgram.InitProgramLayout = new GProgram.InitProgramLayout: extension (uniforms: GUniform.type) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala index 6283ad78..00c2d280 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkBinding.scala @@ -17,6 +17,7 @@ import org.lwjgl.vulkan.VK10.{VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_BUFFER_USAG import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.GUniform +import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} import io.computenode.cyfra.vulkan.memory.{Allocator, Buffer} import izumi.reflect.Tag import org.lwjgl.vulkan.VK10 @@ -60,13 +61,13 @@ object VkBuffer: val buffer = new Buffer.DeviceBuffer(size, UsageFlags) new VkBuffer[T](length, buffer) -class VkUniform[T <: Value: {Tag, FromExpr}] private (underlying: Buffer) extends VkBinding[T](underlying) with GUniform[T] +class VkUniform[T <: GStruct[_]: {Tag, FromExpr, GStructSchema}] private (underlying: Buffer) extends VkBinding[T](underlying) with GUniform[T] object VkUniform: private final val UsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT - def apply[T <: Value: {Tag, FromExpr}]()(using Allocator): VkUniform[T] = + def apply[T <: GStruct[_]: {Tag, FromExpr, GStructSchema}]()(using Allocator): VkUniform[T] = val sizeOfT = typeStride(summon[Tag[T]]) val buffer = new Buffer.DeviceBuffer(sizeOfT, UsageFlags) new VkUniform[T](buffer) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala index 630fa924..7664a3c6 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala @@ -19,7 +19,7 @@ private[cyfra] class Fence(flags: Int = 0)(using device: Device) extends VulkanO val pFence = stack.callocLong(1) check(vkCreateFence(device.get, fenceInfo, null, pFence), "Failed to create fence") - pFence.get(), + pFence.get() ) override def close(): Unit = From 763c3a510ae0c8320397ae517981781a9841bc2e Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Mon, 15 Sep 2025 00:43:23 +0200 Subject: [PATCH 54/59] Old samples work now --- .../io/computenode/cyfra/core/GCodec.scala | 83 ++- .../computenode/cyfra/core/GExecution.scala | 1 - .../cyfra/core/archive/Executable.scala | 9 - .../cyfra/core/archive/GContext.scala | 73 --- .../cyfra/core/archive/GFunction.scala | 38 +- .../cyfra/core/archive/UniformContext.scala | 13 - .../cyfra/core/archive/mem/FloatMem.scala | 27 - .../cyfra/core/archive/mem/GMem.scala | 52 -- .../cyfra/core/archive/mem/IntMem.scala | 27 - .../cyfra/core/archive/mem/RamGMem.scala | 9 - .../cyfra/core/archive/mem/Vec4FloatMem.scala | 33 -- .../io/computenode/cyfra/dsl/Expression.scala | 8 +- .../io/computenode/cyfra/dsl/Value.scala | 3 +- .../cyfra/dsl/struct/GStruct.scala | 4 +- .../cyfra/e2e/RuntimeEnduranceTest.scala | 1 - .../cyfra/e2e/SpirvRuntimeEnduranceTest.scala | 1 - .../cyfra/e2e/dsl/ArithmeticsE2eTest.scala | 18 +- .../cyfra/e2e/dsl/FunctionsE2eTest.scala | 15 +- .../cyfra/e2e/dsl/GStructE2eTest.scala | 53 +- .../cyfra/e2e/dsl/GseqE2eTest.scala | 14 +- .../cyfra/e2e/dsl/WhenE2eTest.scala | 11 +- .../cyfra/e2e/fs2interop/Fs2Tests.scala | 2 - .../cyfra/e2e/juliaset/JuliaSet.scala | 15 +- .../cyfra/samples/TestingStuff.scala | 5 +- .../cyfra/samples/oldsamples/Raytracing.scala | 535 ------------------ .../cyfra/samples/slides/1sample.scala | 17 - .../cyfra/samples/slides/2simpleray.scala | 44 -- .../cyfra/samples/slides/3rays.scala | 153 ----- .../cyfra/samples/slides/4random.scala | 10 +- .../animation/AnimatedFunctionRenderer.scala | 12 +- .../foton/animation/AnimationRenderer.scala | 1 - .../cyfra/foton/rt/ImageRtRenderer.scala | 17 +- .../cyfra/foton/rt/RtRenderer.scala | 3 - .../rt/animation/AnimationRtRenderer.scala | 17 +- 34 files changed, 202 insertions(+), 1122 deletions(-) delete mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/Executable.scala delete mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala delete mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/UniformContext.scala delete mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/FloatMem.scala delete mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/GMem.scala delete mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/IntMem.scala delete mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/RamGMem.scala delete mode 100644 cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/Vec4FloatMem.scala delete mode 100644 cyfra-examples/src/main/scala/io/computenode/cyfra/samples/oldsamples/Raytracing.scala delete mode 100644 cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/1sample.scala delete mode 100644 cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/2simpleray.scala delete mode 100644 cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/3rays.scala diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala index fe059872..a686e9ff 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala @@ -1,9 +1,11 @@ // scala package io.computenode.cyfra.core -import io.computenode.cyfra.core.archive.mem.GMem.{fRGBA, totalStride} import io.computenode.cyfra.dsl.* -import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} +import io.computenode.cyfra.dsl.macros.Source +import io.computenode.cyfra.dsl.struct.GStruct.ComposeStruct +import io.computenode.cyfra.dsl.struct.{GStruct, GStructConstructor, GStructSchema} +import io.computenode.cyfra.spirv.SpirvTypes.typeStride import izumi.reflect.Tag import java.nio.{ByteBuffer, ByteOrder} @@ -12,8 +14,19 @@ import scala.reflect.ClassTag trait GCodec[CyfraType <: Value: {FromExpr, Tag}, ScalaType: ClassTag]: def toByteBuffer(inBuf: ByteBuffer, arr: Array[ScalaType]): ByteBuffer def fromByteBuffer(outBuf: ByteBuffer, arr: Array[ScalaType]): Array[ScalaType] + def fromByteBufferUnchecked(outBuf: ByteBuffer, arr: Array[Any]): Array[ScalaType] = + fromByteBuffer(outBuf, arr.asInstanceOf[Array[ScalaType]]) object GCodec: + + def totalStride(gs: GStructSchema[?]): Int = gs.fields.map: + case (_, fromExpr, t) if t <:< gs.gStructTag => + val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] + totalStride(constructor.schema) + case (_, _, t) => + typeStride(t) + .sum + given GCodec[Int32, Int]: def toByteBuffer(inBuf: ByteBuffer, chunk: Array[Int]): ByteBuffer = inBuf.clear().order(ByteOrder.nativeOrder()) @@ -43,12 +56,8 @@ object GCodec: given GCodec[Vec4[Float32], fRGBA]: def toByteBuffer(inBuf: ByteBuffer, arr: Array[fRGBA]): ByteBuffer = inBuf.clear().order(ByteOrder.nativeOrder()) - arr.foreach: - case (x, y, z, a) => - inBuf.putFloat(x) - inBuf.putFloat(y) - inBuf.putFloat(z) - inBuf.putFloat(a) + arr.foreach: tuple => + writePrimitive(inBuf, tuple) inBuf.flip() inBuf @@ -65,3 +74,61 @@ object GCodec: def fromByteBuffer(outBuf: ByteBuffer, arr: Array[Boolean]): Array[Boolean] = outBuf.get(arr.asInstanceOf[Array[Byte]]).flip() arr + + given [T <: GStruct[T]: {GStructSchema as schema, Tag, ClassTag}]: GCodec[T, T] with + def toByteBuffer(inBuf: ByteBuffer, arr: Array[T]): ByteBuffer = + inBuf.clear().order(ByteOrder.nativeOrder()) + for + struct <- arr + field <- struct.productIterator + do + writeConstPrimitive(inBuf, field.asInstanceOf[Value]) + inBuf.flip() + inBuf + def fromByteBuffer(outBuf: ByteBuffer, arr: Array[T]): Array[T] = + val stride = totalStride(schema) + val nElems = outBuf.remaining() / stride + for _ <- 0 to nElems do + val values = schema.fields.map[Value] { case (_, fromExpr, t) => + t match + case t if t <:< schema.gStructTag => + val constructor = fromExpr.asInstanceOf[GStructConstructor[T]] + val nestedValues = constructor.schema.fields.map { case (_, _, nt) => + readPrimitive(outBuf, nt) + } + constructor.fromExpr(ComposeStruct(nestedValues, constructor.schema)) + case _ => + readPrimitive(outBuf, t) + } + val newStruct = schema.create(values, schema.copy(dependsOn = None))(using Source("Input")) + arr.appended(newStruct) + outBuf.rewind() + arr + + private def readPrimitive(buffer: ByteBuffer, value: Tag[_]): Value = + value.tag match + case t if t =:= summon[Tag[Int]].tag => Int32(ConstInt32(buffer.getInt())) + case t if t =:= summon[Tag[Float]].tag => Float32(ConstFloat32(buffer.getFloat())) + case t if t =:= summon[Tag[Boolean]].tag => GBoolean(ConstGB(buffer.get() != 0)) + case t if t =:= summon[Tag[(Float, Float, Float, Float)]].tag => // todo other tuples + Vec4(ComposeVec4(Float32(ConstFloat32(buffer.getFloat())), Float32(ConstFloat32(buffer.getFloat())), Float32(ConstFloat32(buffer.getFloat())), Float32(ConstFloat32(buffer.getFloat())))) + case illegal => + throw new IllegalArgumentException(s"Unable to deserialize value of type $illegal") + + private def writeConstPrimitive(buff: ByteBuffer, value: Value): Unit = value.tree match + case c: Const[?] => writePrimitive(buff, c.value) + case compose: ComposeVec[_] => + compose.productIterator.foreach: v => + writeConstPrimitive(buff, v.asInstanceOf[Value]) + case illegal => + throw new IllegalArgumentException(s"Only constant Cyfra values can be serialized (got $illegal)") + + private def writePrimitive(buff: ByteBuffer, value: Any): Unit = value match + case i: Int => buff.putInt(i) + case f: Float => buff.putFloat(f) + case b: Boolean => buff.put(if b then 1.toByte else 0.toByte) + case t: Tuple => + t.productIterator.foreach(writePrimitive(buff, _)) + case illegal => + throw new IllegalArgumentException(s"Unable to serialize value $illegal of type ${illegal.getClass}") + diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala index 7ea8ccaf..9fab9d52 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GExecution.scala @@ -1,7 +1,6 @@ package io.computenode.cyfra.core import io.computenode.cyfra.core.GExecution.* -import io.computenode.cyfra.core.archive.GContext import io.computenode.cyfra.core.layout.* import io.computenode.cyfra.dsl.binding.GBuffer import io.computenode.cyfra.dsl.gio.GIO diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/Executable.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/Executable.scala deleted file mode 100644 index 68e0b273..00000000 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/Executable.scala +++ /dev/null @@ -1,9 +0,0 @@ -package io.computenode.cyfra.core.archive - -import io.computenode.cyfra.core.archive.mem.{GMem, RamGMem} -import io.computenode.cyfra.dsl.Value - -import scala.concurrent.Future - -trait Executable[H <: Value, R <: Value]: - def execute(input: GMem[H], output: RamGMem[R, ?]): Future[Unit] diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala deleted file mode 100644 index 7b141690..00000000 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GContext.scala +++ /dev/null @@ -1,73 +0,0 @@ -package io.computenode.cyfra.core.archive - -import io.computenode.cyfra.core.archive.mem.GMem.totalStride -import io.computenode.cyfra.core.archive.mem.{FloatMem, GMem, IntMem, Vec4FloatMem} -import io.computenode.cyfra.core.archive.{GFunction, UniformContext} -import io.computenode.cyfra.dsl.Value -import io.computenode.cyfra.dsl.Value.{Float32, FromExpr, Int32, Vec4} -import io.computenode.cyfra.dsl.struct.* -import io.computenode.cyfra.spirv.SpirvTypes.typeStride -import io.computenode.cyfra.spirv.compilers.DSLCompiler -import io.computenode.cyfra.spirvtools.SpirvToolsRunner - -import izumi.reflect.Tag -import org.lwjgl.system.Configuration - -import java.util.concurrent.Executors -import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} - -class GContext(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()): - Configuration.STACK_SIZE.set(1024) // fix lwjgl stack size - - val vkContext = ??? - - implicit val ec: ExecutionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(16)) - - def compile[G <: GStruct[G]: {Tag, GStructSchema}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( - function: GFunction[G, H, R], - ): Nothing = ??? -// val uniformStructSchema = summon[GStructSchema[G]] -// val uniformStruct = uniformStructSchema.fromTree(UniformStructRef) -// val tree = function.fn -// .apply(uniformStruct, WorkerIndex, GArray[H](0)) -// -// val optimizedShaderCode = -// spirvToolsRunner.processShaderCodeWithSpirvTools(DSLCompiler.compile(tree, function.arrayInputs, function.arrayOutputs, uniformStructSchema)) -// -// val inOut = 0 to 1 map (Binding(_, InputBufferSize(typeStride(summon[Tag[H]])))) -// val uniform = Option.when(uniformStructSchema.fields.nonEmpty)(Binding(2, UniformSize(totalStride(uniformStructSchema)))) -// val layoutInfo = LayoutInfo(Seq(LayoutSet(0, inOut ++ uniform))) -// -// val shader = Shader(optimizedShaderCode, org.joml.Vector3i(256, 1, 1), layoutInfo, "main", vkContext.device) -// ComputePipeline(shader, vkContext) - - def execute[G <: GStruct[G]: {Tag, GStructSchema}, H <: Value, R <: Value](mem: GMem[H], fn: GFunction[G, H, R])(using - uniformContext: UniformContext[G], - ): GMem[R] = ??? -// val isUniformEmpty = uniformContext.uniform.schema.fields.isEmpty -// val actions = Map(LayoutLocation(0, 0) -> BufferAction.LoadTo, LayoutLocation(0, 1) -> BufferAction.LoadFrom) ++ -// ( -// if isUniformEmpty then Map.empty -// else Map(LayoutLocation(0, 2) -> BufferAction.LoadTo) -// ) -// val sequence = ComputationSequence(Seq(Compute(fn.pipeline, actions)), Seq.empty) -// val executor = new SequenceExecutor(sequence, vkContext) -// -// val data = mem.toReadOnlyBuffer -// val inData = -// if isUniformEmpty then Seq(data) -// else Seq(data, GMem.serializeUniform(uniformContext.uniform)) -// val out = executor.execute(inData, mem.size) -// executor.destroy() -// -// val outTags = fn.arrayOutputs -// assert(outTags.size == 1) -// -// outTags.head match -// case t if t == Tag[Float32] => -// new FloatMem(mem.size, out.head).asInstanceOf[GMem[R]] -// case t if t == Tag[Int32] => -// new IntMem(mem.size, out.head).asInstanceOf[GMem[R]] -// case t if t == Tag[Vec4[Float32]] => -// new Vec4FloatMem(mem.size, out.head).asInstanceOf[GMem[R]] -// case _ => assert(false, "Supported output types are Float32 and Vec4[Float32]") diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala index 2798508c..0d559284 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala @@ -18,17 +18,18 @@ import izumi.reflect.Tag import org.lwjgl.BufferUtils import scala.reflect.ClassTag - +import io.computenode.cyfra.core.GCodec.{*, given} +import io.computenode.cyfra.dsl.struct.GStruct.Empty case class GFunction[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( underlying: GProgram[GFunctionParams, GFunctionLayout[G, H, R]] ): - def run[HS, GS, RS : ClassTag] (input: Seq[HS], g: GS)( + def run[GS : ClassTag, HS, RS : ClassTag] (input: Array[HS], g: GS)( using gCodec: GCodec[G, GS], hCodec: GCodec[H, HS], rCodec: GCodec[R, RS], runtime: CyfraRuntime - ): Seq[RS] = + ): Array[RS] = val inTypeSize = typeStride(Tag.apply[H]) val outTypeSize = typeStride(Tag.apply[R]) @@ -36,8 +37,10 @@ case class GFunction[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, Fr val params = GFunctionParams(size = input.size) val in = BufferUtils.createByteBuffer(inTypeSize * input.size) + hCodec.toByteBuffer(in, input) val out = BufferUtils.createByteBuffer(outTypeSize * input.size) val uniform = BufferUtils.createByteBuffer(uniformStride) + gCodec.toByteBuffer(uniform, Array(g)) GBufferRegion.allocate[GFunctionLayout[G, H, R]] .map: layout => @@ -45,16 +48,14 @@ case class GFunction[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, Fr .runUnsafe( init = GFunctionLayout( in = GBuffer[H](in), - out = GBuffer[R](outTypeSize * input.size), + out = GBuffer[R](input.size), uniform = GUniform[G](uniform), ), onDone = layout => layout.out.read(out) ) val resultArray = Array.ofDim[RS](input.size) - rCodec.fromByteBuffer(out, resultArray).toSeq - - + rCodec.fromByteBuffer(out, resultArray) object GFunction: case class GFunctionParams( @@ -67,13 +68,16 @@ object GFunction: uniform: GUniform[G] ) extends Layout - def apply[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: (G, Int32, GBuffer[H]) => R): GFunction[G, H, R] = + def forEachIndex[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: (G, Int32, GBuffer[H]) => R): GFunction[G, H, R] = val body = (layout: GFunctionLayout[G, H, R]) => val g = layout.uniform.read val result = fn(g, GIO.invocationId, layout.in) - layout.out.write(GIO.invocationId, result) - - summon[LayoutStruct[GFunctionLayout[G, H, R]]] + for + _ <- layout.out.write(GIO.invocationId, result) + yield Empty() + + val inTypeSize = typeStride(Tag.apply[H]) + val outTypeSize = typeStride(Tag.apply[R]) GFunction( underlying = GProgram.apply[GFunctionParams, GFunctionLayout[G, H, R]]( @@ -88,14 +92,22 @@ object GFunction: ) def apply[H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: H => R): GFunction[GStruct.Empty, H, R] = - GFunction[GStruct.Empty, H, R]((g: GStruct.Empty, index: Int32, a: GBuffer[H]) => fn(a.read(index))) + GFunction.forEachIndex[GStruct.Empty, H, R]((g: GStruct.Empty, index: Int32, a: GBuffer[H]) => fn(a.read(index))) def from2D[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( width: Int, )(fn: (G, (Int32, Int32), GArray2D[H]) => R): GFunction[G, H, R] = - GFunction[G, H, R]((g: G, index: Int32, a: GBuffer[H]) => + GFunction.forEachIndex[G, H, R]((g: G, index: Int32, a: GBuffer[H]) => val x: Int32 = index mod width val y: Int32 = index / width val arr = GArray2D(width, a) fn(g, (x, y), arr), ) + + extension [H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](gf: GFunction[GStruct.Empty, H, R]) + def run[HS, RS : ClassTag](input: Array[HS])( + using hCodec: GCodec[H, HS], + rCodec: GCodec[R, RS], + runtime: CyfraRuntime + ): Array[RS] = + gf.run(input, GStruct.Empty()) \ No newline at end of file diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/UniformContext.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/UniformContext.scala deleted file mode 100644 index 093698ae..00000000 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/UniformContext.scala +++ /dev/null @@ -1,13 +0,0 @@ -package io.computenode.cyfra.core.archive - -import io.computenode.cyfra.core.archive.UniformContext -import io.computenode.cyfra.dsl.struct.* -import io.computenode.cyfra.dsl.struct.GStruct.Empty -import izumi.reflect.Tag - -class UniformContext[G <: GStruct[G]: {Tag, GStructSchema}](val uniform: G) - -object UniformContext: - def withUniform[G <: GStruct[G]: {Tag, GStructSchema}, T](uniform: G)(fn: UniformContext[G] ?=> T): T = - fn(using UniformContext(uniform)) - given empty: UniformContext[Empty] = new UniformContext(Empty()) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/FloatMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/FloatMem.scala deleted file mode 100644 index 2e51f2ee..00000000 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/FloatMem.scala +++ /dev/null @@ -1,27 +0,0 @@ -package io.computenode.cyfra.core.archive.mem - -import io.computenode.cyfra.dsl.Value.Float32 -import org.lwjgl.BufferUtils - -import java.nio.ByteBuffer - -class FloatMem(val size: Int, protected val data: ByteBuffer) extends RamGMem[Float32, Float]: - def toArray: Array[Float] = - val res = data.asFloatBuffer() - val result = new Array[Float](size) - res.get(result) - result - -object FloatMem: - val FloatSize = 4 - - def apply(floats: Array[Float]): FloatMem = - val size = floats.length - val data = BufferUtils.createByteBuffer(size * FloatSize) - data.asFloatBuffer().put(floats) - data.rewind() - new FloatMem(size, data) - - def apply(size: Int): FloatMem = - val data = BufferUtils.createByteBuffer(size * FloatSize) - new FloatMem(size, data) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/GMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/GMem.scala deleted file mode 100644 index 41961aa4..00000000 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/GMem.scala +++ /dev/null @@ -1,52 +0,0 @@ -package io.computenode.cyfra.core.archive.mem - -import io.computenode.cyfra.core.archive.{GContext, GFunction, UniformContext} -import io.computenode.cyfra.dsl.Value.FromExpr -import io.computenode.cyfra.dsl.struct.* -import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.spirv.SpirvTypes.typeStride -import izumi.reflect.Tag -import org.lwjgl.BufferUtils - -import java.nio.ByteBuffer - -trait GMem[H <: Value]: - def size: Int - def toReadOnlyBuffer: ByteBuffer - def map[G <: GStruct[G]: {Tag, GStructSchema}, R <: Value: {FromExpr, Tag}]( - fn: GFunction[G, H, R], - )(using context: GContext, uc: UniformContext[G]): GMem[R] = - context.execute(this, fn) - -object GMem: - type fRGBA = (Float, Float, Float, Float) - - def totalStride(gs: GStructSchema[?]): Int = gs.fields.map { - case (_, fromExpr, t) if t <:< gs.gStructTag => - val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] - totalStride(constructor.schema) - case (_, _, t) => - typeStride(t) - }.sum - - def serializeUniform(g: GStruct[?]): ByteBuffer = - val data = BufferUtils.createByteBuffer(totalStride(g.schema)) - g.productIterator.foreach: - case Int32(ConstInt32(i)) => data.putInt(i) - case Float32(ConstFloat32(f)) => data.putFloat(f) - case Vec4(ComposeVec4(Float32(ConstFloat32(x)), Float32(ConstFloat32(y)), Float32(ConstFloat32(z)), Float32(ConstFloat32(a)))) => - data.putFloat(x) - data.putFloat(y) - data.putFloat(z) - data.putFloat(a) - case Vec3(ComposeVec3(Float32(ConstFloat32(x)), Float32(ConstFloat32(y)), Float32(ConstFloat32(z)))) => - data.putFloat(x) - data.putFloat(y) - data.putFloat(z) - case Vec2(ComposeVec2(Float32(ConstFloat32(x)), Float32(ConstFloat32(y)))) => - data.putFloat(x) - data.putFloat(y) - case illegal => - throw new IllegalArgumentException(s"Uniform must be constructed from constants (got field $illegal)") - data.rewind() - data diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/IntMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/IntMem.scala deleted file mode 100644 index ee9e61e8..00000000 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/IntMem.scala +++ /dev/null @@ -1,27 +0,0 @@ -package io.computenode.cyfra.core.archive.mem - -import io.computenode.cyfra.dsl.Value.Int32 -import org.lwjgl.BufferUtils - -import java.nio.ByteBuffer - -class IntMem(val size: Int, protected val data: ByteBuffer) extends RamGMem[Int32, Int]: - def toArray: Array[Int] = - val res = data.asIntBuffer() - val result = new Array[Int](size) - res.get(result) - result - -object IntMem: - val IntSize = 4 - - def apply(ints: Array[Int]): IntMem = - val size = ints.length - val data = BufferUtils.createByteBuffer(size * IntSize) - data.asIntBuffer().put(ints) - data.rewind() - new IntMem(size, data) - - def apply(size: Int): IntMem = - val data = BufferUtils.createByteBuffer(size * IntSize) - new IntMem(size, data) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/RamGMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/RamGMem.scala deleted file mode 100644 index a136d7d4..00000000 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/RamGMem.scala +++ /dev/null @@ -1,9 +0,0 @@ -package io.computenode.cyfra.core.archive.mem - -import io.computenode.cyfra.dsl.Value - -import java.nio.ByteBuffer - -trait RamGMem[T <: Value, R] extends GMem[T]: - protected val data: ByteBuffer - def toReadOnlyBuffer: ByteBuffer = data.asReadOnlyBuffer() diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/Vec4FloatMem.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/Vec4FloatMem.scala deleted file mode 100644 index 0fdb63cb..00000000 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/mem/Vec4FloatMem.scala +++ /dev/null @@ -1,33 +0,0 @@ -package io.computenode.cyfra.core.archive.mem - -import io.computenode.cyfra.core.archive.mem.GMem.fRGBA -import io.computenode.cyfra.dsl.Value.{Float32, Vec4} -import org.lwjgl.BufferUtils - -import java.nio.ByteBuffer - -class Vec4FloatMem(val size: Int, protected val data: ByteBuffer) extends RamGMem[Vec4[Float32], fRGBA]: - def toArray: Array[fRGBA] = - val res = data.asFloatBuffer() - val result = new Array[fRGBA](size) - for i <- 0 until size do result(i) = (res.get(), res.get(), res.get(), res.get()) - result - -object Vec4FloatMem: - val Vec4FloatSize = 16 - - def apply(vecs: Array[fRGBA]): Vec4FloatMem = - val size = vecs.length - val data = BufferUtils.createByteBuffer(size * Vec4FloatSize) - vecs.foreach { case (x, y, z, a) => - data.putFloat(x) - data.putFloat(y) - data.putFloat(z) - data.putFloat(a) - } - data.rewind() - new Vec4FloatMem(size, data) - - def apply(size: Int): Vec4FloatMem = - val data = BufferUtils.createByteBuffer(size * Vec4FloatSize) - new Vec4FloatMem(size, data) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala index ef723217..7d52eb5e 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Expression.scala @@ -101,9 +101,11 @@ object Expression: case class ConstUInt32(value: Int) extends Const[UInt32] case class ConstGB(value: Boolean) extends Const[GBoolean] - case class ComposeVec2[T <: Scalar: Tag](a: T, b: T) extends Expression[Vec2[T]] - case class ComposeVec3[T <: Scalar: Tag](a: T, b: T, c: T) extends Expression[Vec3[T]] - case class ComposeVec4[T <: Scalar: Tag](a: T, b: T, c: T, d: T) extends Expression[Vec4[T]] + trait ComposeVec[T <: Vec[?]: Tag] extends Expression[T] + + case class ComposeVec2[T <: Scalar: Tag](a: T, b: T) extends ComposeVec[Vec2[T]] + case class ComposeVec3[T <: Scalar: Tag](a: T, b: T, c: T) extends ComposeVec[Vec3[T]] + case class ComposeVec4[T <: Scalar: Tag](a: T, b: T, c: T, d: T) extends ComposeVec[Vec4[T]] case class ExtFunctionCall[R <: Value: Tag](fn: FunctionName, args: List[Value]) extends Expression[R] case class FunctionCall[R <: Value: Tag](fn: FnIdentifier, body: Scope[R], args: List[Value]) extends E[R] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala index 985357e7..1e8a0e92 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/Value.scala @@ -1,6 +1,5 @@ package io.computenode.cyfra.dsl -import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Expression.{E, E as T} import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag @@ -56,3 +55,5 @@ object Value: case class Vec4[T <: Value](tree: E[Vec4[T]])(using val source: Source) extends Vec[T] given [T <: Scalar]: FromExpr[Vec4[T]] with def fromExpr(f: E[Vec4[T]])(using Source) = Vec4(f) + + type fRGBA = (Float, Float, Float, Float) diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala index f9f6b383..38a642ee 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/struct/GStruct.scala @@ -2,7 +2,7 @@ package io.computenode.cyfra.dsl.struct import io.computenode.cyfra.* import io.computenode.cyfra.dsl.Expression.* -import io.computenode.cyfra.dsl.{Expression, Value} +import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.macros.Source import izumi.reflect.Tag @@ -21,7 +21,7 @@ abstract class GStruct[T <: GStruct[T]: {Tag, GStructSchema}] extends Value with override def source: Source = _name object GStruct: - case class Empty() extends GStruct[Empty] + case class Empty(_placeholder: Int32 = 0) extends GStruct[Empty] object Empty: given GStructSchema[Empty] = GStructSchema.derived diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala index dec27507..2a36c7c2 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala @@ -1,6 +1,5 @@ package io.computenode.cyfra.e2e -import io.computenode.cyfra.core.archive.GContext import io.computenode.cyfra.core.layout.* import io.computenode.cyfra.core.{GBufferRegion, GExecution, GProgram} import io.computenode.cyfra.dsl.Value.{GBoolean, Int32} diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala index 95833a22..3a69f09f 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala @@ -1,6 +1,5 @@ package io.computenode.cyfra.e2e -import io.computenode.cyfra.core.archive.GContext import io.computenode.cyfra.core.layout.* import io.computenode.cyfra.core.{GBufferRegion, GExecution, GProgram} import io.computenode.cyfra.dsl.Value.{GBoolean, Int32} diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala index 78843776..26ab573c 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala @@ -1,23 +1,23 @@ package io.computenode.cyfra.e2e.dsl +import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.* -import io.computenode.cyfra.core.archive.mem.GMem.fRGBA import io.computenode.cyfra.dsl.algebra.VectorAlgebra import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.runtime.VkCyfraRuntime +import io.computenode.cyfra.core.GCodec.{*, given} class ArithmeticsE2eTest extends munit.FunSuite: - given gc: GContext = GContext() - + given CyfraRuntime = VkCyfraRuntime() + test("Float32 arithmetics"): val gf: GFunction[GStruct.Empty, Float32, Float32] = GFunction: fl => (fl + 1.2f) * (fl - 3.4f) / 5.6f // We need to use multiples of 256 for Vulkan buffer alignment. val inArr = (0 to 255).map(_.toFloat).toArray - val gmem = FloatMem(inArr) - val result = gmem.map(gf).asInstanceOf[FloatMem].toArray + val result: Array[Float] = gf.run(inArr) val expected = inArr.map(f => (f + 1.2f) * (f - 3.4f) / 5.6f) result @@ -30,8 +30,7 @@ class ArithmeticsE2eTest extends munit.FunSuite: ((n + 2) * (n - 3) / 5).mod(7) val inArr = (0 to 255).toArray - val gmem = IntMem(inArr) - val result = gmem.map(gf).asInstanceOf[IntMem].toArray + val result: Array[Int] = gf.run(inArr) // With negative values and mod, Scala and Vulkan behave differently val expected = inArr.map: n => @@ -63,8 +62,7 @@ class ArithmeticsE2eTest extends munit.FunSuite: case Seq(a, b, c, d) => (a, b, c, d) .toArray - val gmem = Vec4FloatMem(inArr) - val result = gmem.map(gf).asInstanceOf[FloatMem].toArray + val result: Array[Float] = gf.run(inArr) extension (f: fRGBA) def neg = (-f._1, -f._2, -f._3, -f._4) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala index 990906e8..057ecddc 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala @@ -1,14 +1,15 @@ package io.computenode.cyfra.e2e.dsl +import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.* -import io.computenode.cyfra.core.archive.mem.GMem.fRGBA import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.runtime.VkCyfraRuntime +import io.computenode.cyfra.core.GCodec.{*, given} class FunctionsE2eTest extends munit.FunSuite: - given gc: GContext = GContext() - + given CyfraRuntime = VkCyfraRuntime() + test("Functions"): val gf: GFunction[GStruct.Empty, Float32, Float32] = GFunction: f => val res1 = pow(sqrt(exp(sin(cos(tan(f))))), 2f) @@ -16,8 +17,7 @@ class FunctionsE2eTest extends munit.FunSuite: abs(min(res1, res2) - max(res1, res2)) val inArr = (0 to 255).map(_.toFloat).toArray - val gmem = FloatMem(inArr) - val result = gmem.map(gf).asInstanceOf[FloatMem].toArray + val result: Array[Float] = gf.run(inArr) val expected = inArr.map: f => val res1 = math.pow(math.sqrt(math.exp(math.sin(math.cos(math.tan(f))))), 2) @@ -42,8 +42,7 @@ class FunctionsE2eTest extends munit.FunSuite: v5.dot(v1) val inArr = (0 to 255).map(_.toFloat).toArray - val gmem = FloatMem(inArr) - val result = gmem.map(gf).asInstanceOf[FloatMem].toArray + val result: Array[Float] = gf.run(inArr) extension (f: fRGBA) def neg: fRGBA = (-f._1, -f._2, -f._3, -f._4) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala index bfc88e0e..750085fe 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GStructE2eTest.scala @@ -1,13 +1,17 @@ package io.computenode.cyfra.e2e.dsl +import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.* import io.computenode.cyfra.dsl.binding.GBuffer import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.runtime.VkCyfraRuntime +import io.computenode.cyfra.core.GCodec.{*, given} class GStructE2eTest extends munit.FunSuite: + given CyfraRuntime = VkCyfraRuntime() + case class Custom(f: Float32, v: Vec4[Float32]) extends GStruct[Custom] val custom1 = Custom(2f, (1f, 2f, 3f, 4f)) val custom2 = Custom(-0.5f, (-0.5f, -1.5f, -2.5f, -3.5f)) @@ -15,38 +19,32 @@ class GStructE2eTest extends munit.FunSuite: case class Nested(c1: Custom, c2: Custom) extends GStruct[Nested] val nested = Nested(custom1, custom2) - given gc: GContext = GContext() - test("GStruct passed as uniform"): - UniformContext.withUniform(custom1): - val gf: GFunction[Custom, Float32, Float32] = GFunction: - case (Custom(f, v), index: Int32, gBuff: GBuffer[Float32]) => v.*(f).dot(v) + gBuff.read(index) * f + val gf: GFunction[Custom, Float32, Float32] = GFunction.forEachIndex: + case (Custom(f, v), index: Int32, buff: GBuffer[Float32]) => v.*(f).dot(v) + buff.read(index) * f - val inArr = (0 to 255).map(_.toFloat).toArray - val gmem = FloatMem(inArr) - val result = gmem.map(gf).asInstanceOf[FloatMem].toArray + val inArr = (0 to 255).map(_.toFloat).toArray + val result: Array[Float] = gf.run(inArr, custom1) - val expected = inArr.map(f => 2f * f + 60f) - result - .zip(expected) - .foreach: (res, exp) => - assert(Math.abs(res - exp) < 0.001f, s"Expected $exp but got $res") + val expected = inArr.map(f => 2f * f + 60f) + result + .zip(expected) + .foreach: (res, exp) => + assert(Math.abs(res - exp) < 0.001f, s"Expected $exp but got $res") test("GStruct of GStructs".ignore): - UniformContext.withUniform(nested): - val gf: GFunction[Nested, Float32, Float32] = GFunction: - case (Nested(Custom(f1, v1), Custom(f2, v2)), index, gArray: GBuffer[Float32]) => - v1.*(f2).dot(v2) + gArray.at(index) * f1 + val gf: GFunction[Nested, Float32, Float32] = GFunction.forEachIndex[Nested, Float32, Float32]: + case (Nested(Custom(f1, v1), Custom(f2, v2)), index: Int32, buff: GBuffer[Float32]) => + v1.*(f2).dot(v2) + buff.read(index) * f1 - val inArr = (0 to 255).map(_.toFloat).toArray - val gmem = FloatMem(inArr) - val result = gmem.map(gf).asInstanceOf[FloatMem].toArray + val inArr = (0 to 255).map(_.toFloat).toArray + val result: Array[Float] = gf.run(inArr, nested) - val expected = inArr.map(f => 2f * f + 12.5f) - result - .zip(expected) - .foreach: (res, exp) => - assert(Math.abs(res - exp) < 0.001f, s"Expected $exp but got $res") + val expected = inArr.map(f => 2f * f + 12.5f) + result + .zip(expected) + .foreach: (res, exp) => + assert(Math.abs(res - exp) < 0.001f, s"Expected $exp but got $res") test("GSeq of GStructs"): val gf: GFunction[GStruct.Empty, Float32, Float32] = GFunction: fl => @@ -56,8 +54,7 @@ class GStructE2eTest extends munit.FunSuite: .fold[Float32](0f, (f, c) => f + c.f * (c.v.w + c.v.x + c.v.y + c.v.z)) + fl val inArr = (0 to 255).map(_.toFloat).toArray - val gmem = FloatMem(inArr) - val result = gmem.map(gf).asInstanceOf[FloatMem].toArray + val result: Array[Float] = gf.run(inArr) val expected = inArr.map(f => f + 420f) result diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala index 318201b1..9844c7f9 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala @@ -1,14 +1,16 @@ package io.computenode.cyfra.e2e.dsl +import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.* import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.runtime.VkCyfraRuntime +import io.computenode.cyfra.core.GCodec.{*, given} class GseqE2eTest extends munit.FunSuite: - given gc: GContext = GContext() - + given CyfraRuntime = VkCyfraRuntime() + test("GSeq gen limit map fold"): val gf: GFunction[GStruct.Empty, Float32, Float32] = GFunction: f => GSeq @@ -18,8 +20,7 @@ class GseqE2eTest extends munit.FunSuite: .fold[Float32](0f, _ + _) val inArr = (0 to 255).map(_.toFloat).toArray - val gmem = FloatMem(inArr) - val result = gmem.map(gf).asInstanceOf[FloatMem].toArray + val result: Array[Float] = gf.run(inArr) val expected = inArr.map(f => 10 * f + 65.0f) result @@ -36,8 +37,7 @@ class GseqE2eTest extends munit.FunSuite: .count val inArr = (0 to 255).toArray - val gmem = IntMem(inArr) - val result = gmem.map(gf).asInstanceOf[IntMem].toArray + val result: Array[Int] = gf.run(inArr) val expected = inArr.map: n => List diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/WhenE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/WhenE2eTest.scala index 416f9148..ce202128 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/WhenE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/WhenE2eTest.scala @@ -1,12 +1,14 @@ package io.computenode.cyfra.e2e.dsl -import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.* +import io.computenode.cyfra.core.CyfraRuntime +import io.computenode.cyfra.core.archive.GFunction import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} +import io.computenode.cyfra.runtime.VkCyfraRuntime +import io.computenode.cyfra.core.GCodec.{*, given} class WhenE2eTest extends munit.FunSuite: - given gc: GContext = GContext() + given CyfraRuntime = VkCyfraRuntime() test("when elseWhen otherwise"): val oneHundred = 100.0f @@ -17,8 +19,7 @@ class WhenE2eTest extends munit.FunSuite: .otherwise(2.0f) val inArr: Array[Float] = (0 to 255).map(_.toFloat).toArray - val gmem = FloatMem(inArr) - val result = gmem.map(gf).asInstanceOf[FloatMem].toArray + val result: Array[Float] = gf.run(inArr) val expected = inArr.map: f => if f <= oneHundred then 0.0f else if f <= twoHundred then 1.0f else 2.0f diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala index e5c2667f..367a3066 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala @@ -1,8 +1,6 @@ package io.computenode.cyfra.e2e.fs2interop import io.computenode.cyfra.core.archive.* -import mem.* -import GMem.fRGBA import io.computenode.cyfra.dsl.{*, given} import algebra.VectorAlgebra import io.computenode.cyfra.fs2interop.* diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala index df9b0191..b0d70672 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/juliaset/JuliaSet.scala @@ -2,12 +2,14 @@ package io.computenode.cyfra.e2e.juliaset import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.* +import io.computenode.cyfra.core.GCodec.{*, given} +import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.control.Pure.pure import io.computenode.cyfra.dsl.struct.GStruct.Empty import io.computenode.cyfra.e2e.ImageTests -import io.computenode.cyfra.core.archive.mem.Vec4FloatMem -import io.computenode.cyfra.core.archive.{GContext, GFunction} +import io.computenode.cyfra.core.archive.GFunction +import io.computenode.cyfra.runtime.VkCyfraRuntime import io.computenode.cyfra.spirvtools.* import io.computenode.cyfra.spirvtools.SpirvTool.{Param, ToFile} import io.computenode.cyfra.utility.ImageUtility @@ -21,7 +23,7 @@ import scala.concurrent.ExecutionContext.Implicits class JuliaSet extends FunSuite: given ExecutionContext = Implicits.global - def runJuliaSet(referenceImgName: String)(using GContext): Unit = + def runJuliaSet(referenceImgName: String)(using CyfraRuntime): Unit = val dim = 4096 val max = 1 val RECURSION_LIMIT = 1000 @@ -65,18 +67,19 @@ class JuliaSet extends FunSuite: .otherwise: (8f / 255f, 22f / 255f, 104f / 255f, 1.0f) - val r = Vec4FloatMem(dim * dim).map(function).asInstanceOf[Vec4FloatMem].toArray + val vec4arr = Array.ofDim[fRGBA](dim * dim) + val r: Array[fRGBA] = function.run(vec4arr, Empty()) val outputTemp = File.createTempFile("julia", ".png") ImageUtility.renderToImage(r, dim, outputTemp.toPath) val referenceImage = getClass.getResource(referenceImgName) ImageTests.assertImagesEquals(outputTemp, new File(referenceImage.getPath)) test("Render julia set"): - given GContext = new GContext + given CyfraRuntime = VkCyfraRuntime() runJuliaSet("/julia.png") test("Render julia set optimized"): - given GContext = new GContext( + given CyfraRuntime = new VkCyfraRuntime( SpirvToolsRunner( validator = SpirvValidator.Enable(throwOnFail = true), optimizer = SpirvOptimizer.Enable(toolOutput = ToFile(Paths.get("output/optimized.spv")), settings = Seq(Param("-O"))), diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index e431b719..ecea9250 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -1,6 +1,5 @@ package io.computenode.cyfra.samples -import io.computenode.cyfra.core.archive.GContext import io.computenode.cyfra.core.layout.* import io.computenode.cyfra.core.{GBufferRegion, GExecution, GProgram} import io.computenode.cyfra.dsl.Value.{GBoolean, Int32} @@ -19,9 +18,7 @@ import java.util.concurrent.atomic.AtomicInteger import scala.collection.parallel.CollectionConverters.given object TestingStuff: - - given GContext = GContext() - + // === Emit program === case class EmitProgramParams(inSize: Int, emitN: Int) diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/oldsamples/Raytracing.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/oldsamples/Raytracing.scala deleted file mode 100644 index ab35810e..00000000 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/oldsamples/Raytracing.scala +++ /dev/null @@ -1,535 +0,0 @@ -package io.computenode.cyfra.samples.oldsamples - -import io.computenode.cyfra.dsl.collections.GSeq -import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.Vec4FloatMem -import io.computenode.cyfra.utility.ImageUtility - -import java.nio.file.Paths -import scala.annotation.tailrec -import scala.collection.mutable -import scala.concurrent.ExecutionContext -import scala.concurrent.ExecutionContext.Implicits - -given GContext = new GContext() -given ExecutionContext = Implicits.global - -/** Raytracing example - */ - -@main -def main = - - val dim = 2048 - val minRayHitTime = 0.01f - val rayPosNormalNudge = 0.01f - val superFar = 1000.0f - val fovDeg = 60 - val fovRad = fovDeg * math.Pi.toFloat / 180.0f - val maxBounces = 8 - val pixelIterationsPerFrame = 1000 - val bgColor = (0.2f, 0.2f, 0.2f) - val exposure = 1f - - case class Random[T <: Value](value: T, nextSeed: UInt32) - - def lessThan(f: Vec3[Float32], f2: Float32): Vec3[Float32] = - (when(f.x < f2)(1.0f).otherwise(0.0f), when(f.y < f2)(1.0f).otherwise(0.0f), when(f.z < f2)(1.0f).otherwise(0.0f)) - - def linearToSRGB(rgb: Vec3[Float32]): Vec3[Float32] = - val clampedRgb = vclamp(rgb, 0.0f, 1.0f) - mix(pow(clampedRgb, vec3(1.0f / 2.4f)) * 1.055f - vec3(0.055f), clampedRgb * 12.92f, lessThan(clampedRgb, 0.0031308f)) - - def SRGBToLinear(rgb: Vec3[Float32]): Vec3[Float32] = - val clampedRgb = vclamp(rgb, 0.0f, 1.0f) - mix(pow((clampedRgb + vec3(0.055f)) * (1.0f / 1.055f), vec3(2.4f)), clampedRgb * (1.0f / 12.92f), lessThan(clampedRgb, 0.04045f)) - - def ACESFilm(x: Vec3[Float32]): Vec3[Float32] = - val a = 2.51f - val b = 0.03f - val c = 2.43f - val d = 0.59f - val e = 0.14f - vclamp((x mulV (x * a + vec3(b))) divV (x mulV (x * c + vec3(d)) + vec3(e)), 0.0f, 1.0f) - - case class RayHitInfo( - dist: Float32, - normal: Vec3[Float32], - albedo: Vec3[Float32], - emissive: Vec3[Float32], - percentSpecular: Float32 = 0f, - roughness: Float32 = 0f, - specularColor: Vec3[Float32] = vec3(0f), - indexOfRefraction: Float32 = 1.0f, - refractionChance: Float32 = 0f, - refractionRoughness: Float32 = 0f, - refractionColor: Vec3[Float32] = vec3(0f), - fromInside: GBoolean = false, - ) extends GStruct[RayHitInfo] - - case class Sphere( - center: Vec3[Float32], - radius: Float32, - color: Vec3[Float32], - emissive: Vec3[Float32], - percentSpecular: Float32 = 0f, - roughness: Float32 = 0f, - specularColor: Vec3[Float32] = vec3(0f), - indexOfRefraction: Float32 = 1f, - refractionChance: Float32 = 0f, - refractionRoughness: Float32 = 0f, - refractionColor: Vec3[Float32] = vec3(0f), - ) extends GStruct[Sphere] - - case class Quad( - a: Vec3[Float32], - b: Vec3[Float32], - c: Vec3[Float32], - d: Vec3[Float32], - color: Vec3[Float32], - emissive: Vec3[Float32], - percentSpecular: Float32 = 0f, - roughness: Float32 = 0f, - specularColor: Vec3[Float32] = vec3(0f), - indexOfRefraction: Float32 = 1f, - refractionChance: Float32 = 0f, - refractionRoughness: Float32 = 0f, - refractionColor: Vec3[Float32] = vec3(0f), - ) extends GStruct[Quad] - - case class RayTraceState( - rayPos: Vec3[Float32], - rayDir: Vec3[Float32], - color: Vec3[Float32], - throughput: Vec3[Float32], - rngState: UInt32, - finished: GBoolean = false, - ) extends GStruct[RayTraceState] - - val sceneTranslation = vec4(0f, 0f, 10f, 0f) - // 7 is cool - val rd = scala.util.Random(3) - - def scalaTwoSpheresIntersect(sphereA: (Float, Float, Float), radiusA: Float, sphereB: (Float, Float, Float), radiusB: Float): Boolean = - val dist = Math.sqrt( - (sphereA._1 - sphereB._1) * - (sphereA._1 - sphereB._1) + - (sphereA._2 - sphereB._2) * - (sphereA._2 - sphereB._2) + - (sphereA._3 - sphereB._3) * - (sphereA._3 - sphereB._3), - ) - dist < radiusA + radiusB - - val existingSpheres = mutable.Set.empty[((Float, Float, Float), Float)] - @tailrec - def randomSphere(iter: Int = 0): Sphere = - if iter > 1000 then throw new Exception("Could not find a non-intersecting sphere") - def nextFloatAny = rd.nextFloat() * 2f - 1f - - def nextFloatPos = rd.nextFloat() - - val center = (nextFloatAny * 10, nextFloatAny * 10, nextFloatPos * 10 + 8f) - val radius = nextFloatPos + 1.5f - if existingSpheres.exists(s => scalaTwoSpheresIntersect(s._1, s._2, center, radius)) then randomSphere(iter + 1) - else - existingSpheres.add((center, radius)) - def color = (nextFloatPos * 0.5f + 0.5f, nextFloatPos * 0.5f + 0.5f, nextFloatPos * 0.5f + 0.5f) - val emissive = (0f, 0f, 0f) - Sphere( - center, - radius, - color, - emissive, - 0.45f, - 0.1f, - (nextFloatPos + 0.2f, nextFloatPos + 0.2f, nextFloatPos + 0.2f), - 1.1f, - 0.6f, - 0.1f, - (nextFloatPos, nextFloatPos, nextFloatPos), - ) - - def randomSpheres(n: Int) = List.fill(n)(randomSphere()) - - val flash = // flash - val x = -10f - val mX = -5f - val y = -10f - val mY = 0f - val z = -5f - Sphere((-7.5f, -12f, -5f), 3f, (1f, 1f, 1f), (20f, 20f, 20f)) - val spheres = (flash :: randomSpheres(20)).map(sp => sp.copy(center = sp.center + sceneTranslation.xyz)) - - val walls = List( - Quad( // back - (-15.5f, -15.5f, 25.0f), - (15.5f, -15.5f, 25.0f), - (15.5f, 15.5f, 25.0f), - (-15.5f, 15.5f, 25.0f), - (0.8f, 0.8f, 0.8f), - (0f, 0f, 0f), - ), - Quad( // right - (15f, -15.5f, 25.5f), - (15f, -15.5f, -15.5f), - (15f, 15.5f, -15.5f), - (15f, 15.5f, 25.5f), - (0.0f, 0.8f, 0.0f), - (0f, 0f, 0f), - ), - Quad( // left - (-15f, -15.5f, 25.5f), - (-15f, -15.5f, -15.5f), - (-15f, 15.5f, -15.5f), - (-15f, 15.5f, 25.5f), - (0.8f, 0.0f, 0.0f), - (0f, 0f, 0f), - ), - Quad( // bottom - (-15.5f, 15f, 25.5f), - (15.5f, 15f, 25.5f), - (15.5f, 15f, -15.5f), - (-15.5f, 15f, -15.5f), - (0.8f, 0.8f, 0.8f), - (0f, 0f, 0f), - ), - Quad( // top - (-15.5f, -15f, 25.5f), - (15.5f, -15f, 25.5f), - (15.5f, -15f, -15.5f), - (-15.5f, -15f, -15.5f), - (0.8f, 0.8f, 0.8f), - (0f, 0f, 0f), - ), - Quad( // front - (-15.5f, -15.5f, -15.5f), - (15.5f, -15.5f, -15.5f), - (15.5f, 15.5f, -15.5f), - (-15.5f, 15.5f, -15.5f), - (0.8f, 0.8f, 0.8f), - (0f, 0f, 0f), - ), - Quad( // light - (-2.5f, -14.95f, 17.5f), - (2.5f, -14.95f, 17.5f), - (2.5f, -14.95f, 12.5f), - (-2.5f, -14.95f, 12.5f), - (1f, 1f, 1f), - (20f, 18f, 14f), - ), - ).map(quad => - quad.copy( - a = quad.a + sceneTranslation.xyz, - b = quad.b + sceneTranslation.xyz, - c = quad.c + sceneTranslation.xyz, - d = quad.d + sceneTranslation.xyz, - ), - ) - - case class RaytracingIteration(frame: Int32) extends GStruct[RaytracingIteration] - - def function(): GFunction[RaytracingIteration, Vec4[Float32], Vec4[Float32]] = GFunction.from2D(dim): - case (RaytracingIteration(frame), (xi: Int32, yi: Int32), lastFrame) => - def wangHash(seed: UInt32): UInt32 = - val s1 = (seed ^ 61) ^ (seed >> 16) - val s2 = s1 * 9 - val s3 = s2 ^ (s2 >> 4) - val s4 = s3 * 0x27d4eb2d - s4 ^ (s4 >> 15) - - def randomFloat(seed: UInt32): Random[Float32] = - val nextSeed = wangHash(seed) - val f = nextSeed.asFloat / 4294967296.0f - Random(f, nextSeed) - - def randomVector(seed: UInt32): Random[Vec3[Float32]] = - val Random(z, seed1) = randomFloat(seed) - val z2 = z * 2.0f - 1.0f - val Random(a, seed2) = randomFloat(seed1) - val a2 = a * 2.0f * math.Pi.toFloat - val r = sqrt(1.0f - z2 * z2) - val x = r * cos(a2) - val y = r * sin(a2) - Random((x, y, z2), seed2) - - def scalarTriple(u: Vec3[Float32], v: Vec3[Float32], w: Vec3[Float32]): Float32 = (u cross v) dot w - - def testQuadTrace(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo, quad: Quad): RayHitInfo = - val normal = normalize((quad.c - quad.a) cross (quad.c - quad.b)) - val fixedQuad = - when((normal dot rayDir) > 0f): - Quad(quad.d, quad.c, quad.b, quad.a, quad.color, quad.emissive) - .otherwise: - quad - - val fixedNormal = when((normal dot rayDir) > 0f)(-normal).otherwise(normal) - val p = rayPos - val q = rayPos + rayDir - val pq = q - p - val pa = fixedQuad.a - p - val pb = fixedQuad.b - p - val pc = fixedQuad.c - p - val m = pc cross pq - val v = pa dot m - - def checkHit(intersectPoint: Vec3[Float32]): RayHitInfo = - val dist = - when(abs(rayDir.x) > 0.1f): - (intersectPoint.x - rayPos.x) / rayDir.x - .elseWhen(abs(rayDir.y) > 0.1f): - (intersectPoint.y - rayPos.y) / rayDir.y - .otherwise: - (intersectPoint.z - rayPos.z) / rayDir.z - - when(dist > minRayHitTime && dist < currentHit.dist): - RayHitInfo( - dist, - fixedNormal, - quad.color, - quad.emissive, - quad.percentSpecular, - quad.roughness, - quad.specularColor, - quad.indexOfRefraction, - quad.refractionChance, - quad.refractionRoughness, - quad.refractionColor, - ) - .otherwise: - currentHit - - when(v >= 0f): - val u = -(pb dot m) - val w = scalarTriple(pq, pb, pa) - when(u >= 0f && w >= 0f): - val denom = 1f / (u + v + w) - val uu = u * denom - val vv = v * denom - val ww = w * denom - val intersectPos = fixedQuad.a * uu + fixedQuad.b * vv + fixedQuad.c * ww - checkHit(intersectPos) - .otherwise: - currentHit - .otherwise: - val pd = fixedQuad.d - p - val u = pd dot m - val w = scalarTriple(pq, pa, pd) - when(u >= 0f && w >= 0f): - val negV = -v - val denom = 1f / (u + negV + w) - val uu = u * denom - val vv = negV * denom - val ww = w * denom - val intersectPos = fixedQuad.a * uu + fixedQuad.d * vv + fixedQuad.c * ww - checkHit(intersectPos) - .otherwise: - currentHit - - def testSphereTrace(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo, sphere: Sphere): RayHitInfo = - val toRay = rayPos - sphere.center - val b = toRay dot rayDir - val c = (toRay dot toRay) - (sphere.radius * sphere.radius) - val notHit = currentHit - when(c > 0f && b > 0f): - notHit - .otherwise: - val discr = b * b - c - when(discr > 0f): - val initDist = -b - sqrt(discr) - val fromInside = initDist < 0f - val dist = when(fromInside)(-b + sqrt(discr)).otherwise(initDist) - when(dist > minRayHitTime && dist < currentHit.dist): - val normal = normalize((rayPos + rayDir * dist - sphere.center) * when(fromInside)(-1f).otherwise(1f)) - RayHitInfo( - dist, - normal, - sphere.color, - sphere.emissive, - sphere.percentSpecular, - sphere.roughness, - sphere.specularColor, - sphere.indexOfRefraction, - sphere.refractionChance, - sphere.refractionRoughness, - sphere.refractionColor, - fromInside, - ) - .otherwise: - notHit - .otherwise: - notHit - - def testScene(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo): RayHitInfo = - - val spheresHit = GSeq - .of(spheres) - .fold( - currentHit, - { case (hit, sphere) => - testSphereTrace(rayPos, rayDir, hit, sphere) - }, - ) - - GSeq.of(walls).fold(spheresHit, (hit, wall) => testQuadTrace(rayPos, rayDir, hit, wall)) - - def fresnelReflectAmount(n1: Float32, n2: Float32, normal: Vec3[Float32], incident: Vec3[Float32], f0: Float32, f90: Float32): Float32 = - val r0 = ((n1 - n2) / (n1 + n2)) * ((n1 - n2) / (n1 + n2)) - val cosX = -(normal dot incident) - when(n1 > n2): - val n = n1 / n2 - val sinT2 = n * n * (1f - cosX * cosX) - when(sinT2 > 1f): - f90 - .otherwise: - val cosX2 = sqrt(1.0f - sinT2) - val x = 1.0f - cosX2 - val ret = r0 + ((1.0f - r0) * x * x * x * x * x) - mix(f0, f90, ret) - .otherwise: - val x = 1.0f - cosX - val ret = r0 + ((1.0f - r0) * x * x * x * x * x) - mix(f0, f90, ret) - - val MaxBounces = 8 - def getColorForRay(startRayPos: Vec3[Float32], startRayDir: Vec3[Float32], initRngState: UInt32): RayTraceState = - val initState = RayTraceState(startRayPos, startRayDir, (0f, 0f, 0f), (1f, 1f, 1f), initRngState) - GSeq - .gen[RayTraceState]( - first = initState, - next = - case state @ RayTraceState(rayPos, rayDir, color, throughput, rngState, _) => - val noHit = RayHitInfo(superFar, (0f, 0f, 0f), (0f, 0f, 0f), (0f, 0f, 0f)) - val testResult = testScene(rayPos, rayDir, noHit) - when(testResult.dist < superFar): - val throughput2 = when(testResult.fromInside): - throughput mulV exp[Vec3[Float32]](-testResult.refractionColor * testResult.dist) - .otherwise: - throughput - - val specularChance = when(testResult.percentSpecular > 0.0f): - fresnelReflectAmount( - when(testResult.fromInside)(testResult.indexOfRefraction).otherwise(1.0f), - when(!testResult.fromInside)(testResult.indexOfRefraction).otherwise(1.0f), - rayDir, - testResult.normal, - testResult.percentSpecular, - 1.0f, - ) - .otherwise: - 0f - - val refractionChance = when(specularChance > 0.0f): - testResult.refractionChance * ((1.0f - specularChance) / (1.0f - testResult.percentSpecular)) - .otherwise: - testResult.refractionChance - - val Random(rayRoll, nextRngState1) = randomFloat(rngState) - val doSpecular = when(specularChance > 0.0f && rayRoll < specularChance): - 1.0f - .otherwise: - 0.0f - - val doRefraction = when(refractionChance > 0.0f && doSpecular === 0.0f && rayRoll < specularChance + refractionChance): - 1.0f - .otherwise: - 0.0f - - val rayProbability = when(doSpecular === 1.0f): - specularChance - .elseWhen(doRefraction === 1.0f): - refractionChance - .otherwise: - 1.0f - (specularChance + refractionChance) - - val rayProbabilityCorrected = max(rayProbability, 0.01f) - - val nextRayPos = when(doRefraction === 1.0f): - (rayPos + rayDir * testResult.dist) - (testResult.normal * rayPosNormalNudge) - .otherwise: - (rayPos + rayDir * testResult.dist) + (testResult.normal * rayPosNormalNudge) - - val Random(randomVec1, nextRngState2) = randomVector(nextRngState1) - val diffuseRayDir = normalize(testResult.normal + randomVec1) - val specularRayDirPerfect = reflect(rayDir, testResult.normal) - val specularRayDir = normalize(mix(specularRayDirPerfect, diffuseRayDir, testResult.roughness * testResult.roughness)) - - val Random(randomVec2, nextRngState3) = randomVector(nextRngState2) - val refractionRayDirPerfect = - refract( - rayDir, - testResult.normal, - when(testResult.fromInside)(testResult.indexOfRefraction).otherwise(1.0f / testResult.indexOfRefraction), - ) - val refractionRayDir = - normalize( - mix( - refractionRayDirPerfect, - normalize(-testResult.normal + randomVec2), - testResult.refractionRoughness * testResult.refractionRoughness, - ), - ) - - val rayDirSpecular = mix(diffuseRayDir, specularRayDir, doSpecular) - val rayDirRefracted = mix(rayDirSpecular, refractionRayDir, doRefraction) - - val nextColor = (throughput2 mulV testResult.emissive) addV color - - val nextThroughput = when(doRefraction === 0.0f): - throughput2 mulV mix[Vec3[Float32]](testResult.albedo, testResult.specularColor, doSpecular) - .otherwise: - throughput2 - - val throughputRayProb = nextThroughput * (1.0f / rayProbabilityCorrected) - - RayTraceState(nextRayPos, rayDirRefracted, nextColor, throughputRayProb, nextRngState3) - .otherwise: - RayTraceState(rayPos, rayDir, color, throughput, rngState, true), - ) - .limit(MaxBounces) - .takeWhile(!_.finished) - .lastOr(initState) - - val rngState = xi * 1973 + yi * 9277 + frame * 26699 | 1 - case class RenderIteration(color: Vec3[Float32], rngState: UInt32) extends GStruct[RenderIteration] - val color = - GSeq - .gen( - first = RenderIteration((0f, 0f, 0f), rngState.unsigned), - next = { case RenderIteration(_, rngState) => - val Random(wiggleX, rngState1) = randomFloat(rngState) - val Random(wiggleY, rngState2) = randomFloat(rngState1) - val x = ((xi.asFloat + wiggleX) / dim.toFloat) * 2f - 1f - val y = ((yi.asFloat + wiggleY) / dim.toFloat) * 2f - 1f - val xy = (x, y) - - val rayPosition = (0f, 0f, 0f) - val cameraDist = 1.0f / tan(fovDeg * 0.6f * math.Pi.toFloat / 180.0f) - val rayTarget = (x, y, cameraDist) - - val rayDir = normalize(rayTarget - rayPosition) - val rtResult = getColorForRay(rayPosition, rayDir, rngState) - val withBg = vclamp(rtResult.color + (SRGBToLinear(bgColor) mulV rtResult.throughput), 0.0f, 20.0f) - RenderIteration(withBg, rtResult.rngState) - }, - ) - .limit(pixelIterationsPerFrame) - .fold((0f, 0f, 0f), { case (acc, RenderIteration(color, _)) => acc + (color * (1.0f / pixelIterationsPerFrame.toFloat)) }) - - when(frame === 0): - (color, 1.0f) - .otherwise: - mix(lastFrame.at(xi, yi), (color, 1.0f), vec4(1.0f / (frame.asFloat + 1f))) - - val initialMem = Array.fill(dim * dim)((0.5f, 0.5f, 0.5f, 0.5f)) - val renders = 100 - val code = function() - List.range(0, renders).foldLeft(initialMem) { case (mem, i) => - UniformContext.withUniform(RaytracingIteration(i)): - val newMem = Vec4FloatMem(mem).map(code).asInstanceOf[Vec4FloatMem].toArray - ImageUtility.renderToImage(newMem, dim, Paths.get(s"generated.png")) - println(s"Finished render $i") - newMem - } diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/1sample.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/1sample.scala deleted file mode 100644 index 16121da4..00000000 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/1sample.scala +++ /dev/null @@ -1,17 +0,0 @@ -package io.computenode.cyfra.samples.slides - -import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.FloatMem - -given GContext = new GContext() - -@main -def sample() = - val gpuFunction = GFunction: (value: Float32) => - value * 2f - - val data = FloatMem((1 to 128).map(_.toFloat).toArray) - - val result = data.map(gpuFunction).asInstanceOf[FloatMem].toArray - println(result.mkString(", ")) diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/2simpleray.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/2simpleray.scala deleted file mode 100644 index 145fe5e6..00000000 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/2simpleray.scala +++ /dev/null @@ -1,44 +0,0 @@ -package io.computenode.cyfra.samples.slides - -import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.dsl.struct.GStruct.Empty -import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.Vec4FloatMem -import io.computenode.cyfra.utility.ImageUtility - -import java.nio.file.Paths - -@main -def simpleRay() = - val dim = 1024 - val fovDeg = 60 - - case class Sphere(center: Vec3[Float32], radius: Float32, color: Vec3[Float32], emissive: Vec3[Float32]) extends GStruct[Sphere] - - def getColorForRay(rayPos: Vec3[Float32], rayDirection: Vec3[Float32]): Vec4[Float32] = - val sphereCenter = (0f, 0.5f, 3f) - val sphereRadius = 1f - val toRay = rayPos - sphereCenter - val b = toRay dot rayDirection - val c = (toRay dot toRay) - (sphereRadius * sphereRadius) - when((c < 0f || b < 0f) && b * b - c > 0f): - (1f, 1f, 1f, 1f) - .otherwise: - (0f, 0f, 0f, 1f) - - val raytracing: GFunction[Empty, Vec4[Float32], Vec4[Float32]] = GFunction.from2D(dim): - case (_, (xi: Int32, yi: Int32), _) => - val x = (xi.asFloat / dim.toFloat) * 2f - 1f - val y = (yi.asFloat / dim.toFloat) * 2f - 1f - - val rayPosition = (0f, 0f, 0f) - val cameraDist = 1.0f / tan(fovDeg * 0.6f * math.Pi.toFloat / 180.0f) - val rayTarget = (x, y, cameraDist) - - val rayDir = normalize(rayTarget - rayPosition) - getColorForRay(rayPosition, rayDir) - - val mem = Vec4FloatMem(Array.fill(dim * dim)((0f, 0f, 0f, 0f))) - val result = mem.map(raytracing).asInstanceOf[Vec4FloatMem].toArray - ImageUtility.renderToImage(result, dim, Paths.get(s"generated2.png")) diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/3rays.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/3rays.scala deleted file mode 100644 index 49ff0d46..00000000 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/3rays.scala +++ /dev/null @@ -1,153 +0,0 @@ -package io.computenode.cyfra.samples.slides - -import io.computenode.cyfra.* -import io.computenode.cyfra.dsl.collections.GSeq -import io.computenode.cyfra.dsl.{*, given} -import io.computenode.cyfra.dsl.struct.GStruct -import io.computenode.cyfra.dsl.struct.GStruct.Empty -import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.Vec4FloatMem -import io.computenode.cyfra.utility.ImageUtility - -import java.nio.file.Paths - -@main -def rays() = - val raysPerPixel = 10 - val dim = 1024 - val fovDeg = 60 - val minRayHitTime = 0.01f - val superFar = 999f - val maxBounces = 10 - val rayPosNudge = 0.001f - - def scalarTriple(u: Vec3[Float32], v: Vec3[Float32], w: Vec3[Float32]): Float32 = (u cross v) dot w - - case class Sphere(center: Vec3[Float32], radius: Float32, color: Vec3[Float32], emissive: Vec3[Float32]) extends GStruct[Sphere] - - case class Quad(a: Vec3[Float32], b: Vec3[Float32], c: Vec3[Float32], d: Vec3[Float32], color: Vec3[Float32], emissive: Vec3[Float32]) - extends GStruct[Quad] - - case class RayHitInfo(dist: Float32, normal: Vec3[Float32], albedo: Vec3[Float32], emissive: Vec3[Float32]) extends GStruct[RayHitInfo] - - case class RayTraceState(rayPos: Vec3[Float32], rayDir: Vec3[Float32], color: Vec3[Float32], throughput: Vec3[Float32], finished: GBoolean = false) - extends GStruct[RayTraceState] - - def testSphereTrace(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo, sphere: Sphere): RayHitInfo = - val toRay = rayPos - sphere.center - val b = toRay dot rayDir - val c = (toRay dot toRay) - (sphere.radius * sphere.radius) - val notHit = currentHit - when(c > 0f && b > 0f): - notHit - .otherwise: - val discr = b * b - c - when(discr > 0f): - val initDist = -b - sqrt(discr) - val fromInside = initDist < 0f - val dist = when(fromInside)(-b + sqrt(discr)).otherwise(initDist) - when(dist > minRayHitTime && dist < currentHit.dist): - val normal = normalize(rayPos + rayDir * dist - sphere.center) - RayHitInfo(dist, normal, sphere.color, sphere.emissive) - .otherwise: - notHit - .otherwise: - notHit - - def testQuadTrace(rayPos: Vec3[Float32], rayDir: Vec3[Float32], currentHit: RayHitInfo, quad: Quad): RayHitInfo = - val normal = normalize((quad.c - quad.a) cross (quad.c - quad.b)) - val fixedQuad = when((normal dot rayDir) > 0f): - Quad(quad.d, quad.c, quad.b, quad.a, quad.color, quad.emissive) - .otherwise: - quad - val fixedNormal = when((normal dot rayDir) > 0f)(-normal).otherwise(normal) - val p = rayPos - val q = rayPos + rayDir - val pq = q - p - val pa = fixedQuad.a - p - val pb = fixedQuad.b - p - val pc = fixedQuad.c - p - val m = pc cross pq - val v = pa dot m - - def checkHit(intersectPoint: Vec3[Float32]): RayHitInfo = - val dist = when(abs(rayDir.x) > 0.1f): - (intersectPoint.x - rayPos.x) / rayDir.x - .elseWhen(abs(rayDir.y) > 0.1f): - (intersectPoint.y - rayPos.y) / rayDir.y - .otherwise: - (intersectPoint.z - rayPos.z) / rayDir.z - - when(dist > minRayHitTime && dist < currentHit.dist): - RayHitInfo(dist, fixedNormal, quad.color, quad.emissive) - .otherwise: - currentHit - - when(v >= 0f): - val u = -(pb dot m) - val w = scalarTriple(pq, pb, pa) - when(u >= 0f && w >= 0f): - val denom = 1f / (u + v + w) - val uu = u * denom - val vv = v * denom - val ww = w * denom - val intersectPos = fixedQuad.a * uu + fixedQuad.b * vv + fixedQuad.c * ww - checkHit(intersectPos) - .otherwise: - currentHit - .otherwise: - val pd = fixedQuad.d - p - val u = pd dot m - val w = scalarTriple(pq, pa, pd) - when(u >= 0f && w >= 0f): - val negV = -v - val denom = 1f / (u + negV + w) - val uu = u * denom - val vv = negV * denom - val ww = w * denom - val intersectPos = fixedQuad.a * uu + fixedQuad.d * vv + fixedQuad.c * ww - checkHit(intersectPos) - .otherwise: - currentHit - - val sphere = Sphere(center = (1.5f, 1.5f, 4f), radius = 0.5f, color = (1f, 1f, 1f), emissive = (3f, 3f, 3f)) - - val backWall = Quad(a = (-2f, -2f, 5f), b = (2f, -2f, 5f), c = (2f, 2f, 5f), d = (-2f, 2f, 5f), color = (0f, 1f, 1f), emissive = (0f, 0f, 0f)) - - def getColorForRay(rayPos: Vec3[Float32], rayDirection: Vec3[Float32]): Vec4[Float32] = - GSeq - .gen[RayTraceState]( - first = RayTraceState(rayPos = rayPos, rayDir = rayDirection, color = (0f, 0f, 0f), throughput = (1f, 1f, 1f)), - next = { case state @ RayTraceState(rayPos, rayDir, color, throughput, _) => - val noHit = RayHitInfo(1000f, (0f, 0f, 0f), (0f, 0f, 0f), (0f, 0f, 0f)) - val sphereHit = testSphereTrace(rayPos, rayDir, noHit, sphere) - val wallHit = testQuadTrace(rayPos, rayDir, sphereHit, backWall) - RayTraceState( - rayPos = rayPos + rayDir * wallHit.dist + wallHit.normal * rayPosNudge, - rayDir = reflect(rayDir, wallHit.normal), - color = color + wallHit.emissive mulV throughput, - throughput = throughput mulV wallHit.albedo, - finished = wallHit.dist > superFar, - ) - }, - ) - .limit(maxBounces) - .takeWhile(!_.finished) - .map(state => (state.color, 1f)) - .lastOr((0f, 0f, 0f, 1f)) - - val raytracing: GFunction[Empty, Vec4[Float32], Vec4[Float32]] = GFunction.from2D(dim): - case (_, (xi: Int32, yi: Int32), _) => - val x = (xi.asFloat / dim.toFloat) * 2f - 1f - val y = (yi.asFloat / dim.toFloat) * 2f - 1f - - val rayPosition = (0f, 0f, 0f) - val cameraDist = 1.0f / tan(fovDeg * 0.6f * math.Pi.toFloat / 180.0f) - val rayTarget = (x, y, cameraDist) - - val rayDir = normalize(rayTarget - rayPosition) - getColorForRay(rayPosition, rayDir) - - val mem = Vec4FloatMem(Array.fill(dim * dim)((0f, 0f, 0f, 0f))) - val result = mem.map(raytracing).asInstanceOf[Vec4FloatMem].toArray - ImageUtility.renderToImage(result, dim, Paths.get(s"generated3.png")) diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/4random.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/4random.scala index bac16f3b..8d3488a7 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/4random.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/slides/4random.scala @@ -1,11 +1,12 @@ package io.computenode.cyfra.samples.slides +import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.dsl.collections.GSeq import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.struct.GStruct.Empty import io.computenode.cyfra.core.archive.* -import io.computenode.cyfra.core.archive.mem.Vec4FloatMem +import io.computenode.cyfra.runtime.VkCyfraRuntime import io.computenode.cyfra.utility.ImageUtility import java.nio.file.Paths @@ -36,6 +37,9 @@ def randomVector(seed: UInt32): Random[Vec3[Float32]] = @main def randomRays() = + + given CyfraRuntime = VkCyfraRuntime() + val raysPerPixel = 10 val dim = 1024 val fovDeg = 80 @@ -202,6 +206,6 @@ def randomRays() = .fold((0f, 0f, 0f), { case (acc, RenderIteration(color, _)) => acc + (color * (1.0f / pixelIterationsPerFrame.toFloat)) }) (color, 1f) - val mem = Vec4FloatMem(Array.fill(dim * dim)((0f, 0f, 0f, 0f))) - val result = mem.map(raytracing).asInstanceOf[Vec4FloatMem].toArray + val mem = Array.fill(dim * dim)((0f, 0f, 0f, 0f)) + val result: Array[fRGBA] = raytracing.run(mem) ImageUtility.renderToImage(result, dim, Paths.get(s"generated4.png")) diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala index 1e18cd28..49a5feed 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimatedFunctionRenderer.scala @@ -1,14 +1,14 @@ package io.computenode.cyfra.foton.animation import io.computenode.cyfra +import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.animation.AnimatedFunctionRenderer.{AnimationIteration, RenderFn} import io.computenode.cyfra.foton.animation.AnimationFunctions.AnimationInstant -import io.computenode.cyfra.core.archive.mem.GMem.fRGBA -import io.computenode.cyfra.core.archive.mem.Vec4FloatMem -import io.computenode.cyfra.core.archive.{GContext, GFunction, UniformContext} +import io.computenode.cyfra.core.archive.GFunction +import io.computenode.cyfra.runtime.VkCyfraRuntime import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContext.Implicits @@ -16,15 +16,13 @@ import scala.concurrent.ExecutionContext.Implicits class AnimatedFunctionRenderer(params: AnimatedFunctionRenderer.Parameters) extends AnimationRenderer[AnimatedFunction, AnimatedFunctionRenderer.RenderFn](params): - given GContext = new GContext() + given CyfraRuntime = new VkCyfraRuntime() given ExecutionContext = Implicits.global override protected def renderFrame(scene: AnimatedFunction, time: Float32, fn: RenderFn): Array[fRGBA] = val mem = Array.fill(params.width * params.height)((0.5f, 0.5f, 0.5f, 0.5f)) - UniformContext.withUniform(AnimationIteration(time)): - val fmem = Vec4FloatMem(mem) - fmem.map(fn).asInstanceOf[Vec4FloatMem].toArray + fn.run(mem, AnimationIteration(time)) override protected def renderFunction(scene: AnimatedFunction): RenderFn = GFunction.from2D(params.width): diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala index 9a262e95..015be533 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/animation/AnimationRenderer.scala @@ -4,7 +4,6 @@ import io.computenode.cyfra import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.core.archive.GFunction -import io.computenode.cyfra.core.archive.mem.GMem.fRGBA import io.computenode.cyfra.utility.ImageUtility import io.computenode.cyfra.utility.Units.Milliseconds import io.computenode.cyfra.utility.Utility.timed diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala index 8f4d2b70..8a77c384 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala @@ -2,13 +2,13 @@ package io.computenode.cyfra.foton.rt import io.computenode.cyfra import io.computenode.cyfra.* +import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.rt.ImageRtRenderer.RaytracingIteration -import io.computenode.cyfra.core.archive.mem.GMem.fRGBA -import io.computenode.cyfra.core.archive.mem.Vec4FloatMem -import io.computenode.cyfra.core.archive.{GFunction, UniformContext} +import io.computenode.cyfra.core.archive.GFunction +import io.computenode.cyfra.runtime.VkCyfraRuntime import io.computenode.cyfra.utility.ImageUtility import io.computenode.cyfra.utility.Utility.timed @@ -16,6 +16,8 @@ import java.nio.file.Path class ImageRtRenderer(params: ImageRtRenderer.Parameters) extends RtRenderer(params): + given CyfraRuntime = VkCyfraRuntime() + def renderToFile(scene: Scene, destinationPath: Path): Unit = val images = render(scene) for image <- images do ImageUtility.renderToImage(image, params.width, params.height, destinationPath) @@ -26,12 +28,11 @@ class ImageRtRenderer(params: ImageRtRenderer.Parameters) extends RtRenderer(par private def render(scene: Scene, fn: GFunction[RaytracingIteration, Vec4[Float32], Vec4[Float32]]): LazyList[Array[fRGBA]] = val initialMem = Array.fill(params.width * params.height)((0.5f, 0.5f, 0.5f, 0.5f)) LazyList - .iterate((initialMem, 0), params.iterations + 1) { case (mem, render) => - UniformContext.withUniform(RaytracingIteration(render)): - val fmem = Vec4FloatMem(mem) - val result = timed(s"Rendered iteration $render")(fmem.map(fn).asInstanceOf[Vec4FloatMem].toArray) + .iterate((initialMem, 0), params.iterations + 1): + case (mem, render) => + val result: Array[fRGBA] = timed(s"Render iteration $render"): + fn.run(mem, RaytracingIteration(render)) (result, render + 1) - } .drop(1) .map(_._1) diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala index b59765b1..de38af62 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/RtRenderer.scala @@ -10,15 +10,12 @@ import io.computenode.cyfra.dsl.library.Random import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.rt.RtRenderer.RayHitInfo -import io.computenode.cyfra.core.archive.GContext import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContext.Implicits class RtRenderer(params: RtRenderer.Parameters): - given GContext = new GContext() - given ExecutionContext = Implicits.global private case class RayTraceState( diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala index c339bec9..ee6e77ac 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala @@ -1,29 +1,30 @@ package io.computenode.cyfra.foton.rt.animation import io.computenode.cyfra +import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.dsl.Value.* import io.computenode.cyfra.dsl.struct.GStruct import io.computenode.cyfra.dsl.{*, given} import io.computenode.cyfra.foton.animation.AnimationRenderer import io.computenode.cyfra.foton.rt.RtRenderer import io.computenode.cyfra.foton.rt.animation.AnimationRtRenderer.RaytracingIteration -import io.computenode.cyfra.core.archive.mem.GMem.fRGBA -import io.computenode.cyfra.core.archive.mem.Vec4FloatMem -import io.computenode.cyfra.core.archive.{GFunction, UniformContext} +import io.computenode.cyfra.core.archive.GFunction +import io.computenode.cyfra.runtime.VkCyfraRuntime class AnimationRtRenderer(params: AnimationRtRenderer.Parameters) extends RtRenderer(params) with AnimationRenderer[AnimatedScene, AnimationRtRenderer.RenderFn](params): + + given CyfraRuntime = VkCyfraRuntime() protected def renderFrame(scene: AnimatedScene, time: Float32, fn: GFunction[RaytracingIteration, Vec4[Float32], Vec4[Float32]]): Array[fRGBA] = val initialMem = Array.fill(params.width * params.height)((0.5f, 0.5f, 0.5f, 0.5f)) List - .iterate((initialMem, 0), params.iterations + 1) { case (mem, render) => - UniformContext.withUniform(RaytracingIteration(render, time)): - val fmem = Vec4FloatMem(mem) - val result = fmem.map(fn).asInstanceOf[Vec4FloatMem].toArray + .iterate((initialMem, 0), params.iterations + 1): + case (mem, render) => + val result: Array[fRGBA] = fn.run(mem, RaytracingIteration(render, time)) (result, render + 1) - } + .map(_._1) .last From bc26f581729e35f1f6dab028d9d20382979c3bc5 Mon Sep 17 00:00:00 2001 From: MarconZet <25779550+MarconZet@users.noreply.github.com> Date: Sun, 21 Sep 2025 18:30:15 +0200 Subject: [PATCH 55/59] change instance creation^ --- .../cyfra/e2e/fs2interop/Fs2Tests.scala | 21 ++-- .../cyfra/samples/TestingStuff.scala | 37 +++--- .../computenode/cyfra/fs2interop/GPipe.scala | 29 ++--- .../cyfra/vulkan/VulkanContext.scala | 16 +-- .../vulkan/core/DebugMessengerCallback.scala | 58 +++++++++ ...llback.scala => DebugReportCallback.scala} | 46 ++++--- .../cyfra/vulkan/core/Device.scala | 1 - .../cyfra/vulkan/core/Instance.scala | 112 +++++------------- 8 files changed, 152 insertions(+), 168 deletions(-) create mode 100644 cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugMessengerCallback.scala rename cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/{DebugCallback.scala => DebugReportCallback.scala} (56%) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala index 367a3066..6c6e5b14 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/fs2interop/Fs2Tests.scala @@ -6,9 +6,10 @@ import algebra.VectorAlgebra import io.computenode.cyfra.fs2interop.* import io.computenode.cyfra.core.CyfraRuntime import io.computenode.cyfra.runtime.VkCyfraRuntime -import fs2.{io as fs2io, *} -import _root_.io.computenode.cyfra.spirvtools.{SpirvCross, SpirvDisassembler, SpirvToolsRunner} -import _root_.io.computenode.cyfra.spirvtools.SpirvTool.ToFile +import io.computenode.cyfra.spirvtools.{SpirvCross, SpirvDisassembler, SpirvToolsRunner} +import io.computenode.cyfra.spirvtools.SpirvTool.ToFile + +import fs2.* import java.nio.file.Paths @@ -20,15 +21,15 @@ extension (f: fRGBA) Math.abs(f._1 - g._1) < eps && Math.abs(f._2 - g._2) < eps && Math.abs(f._3 - g._3) < eps && Math.abs(f._4 - g._4) < eps class Fs2Tests extends munit.FunSuite: - given cr: VkCyfraRuntime = VkCyfraRuntime( - spirvToolsRunner = SpirvToolsRunner( + given cr: VkCyfraRuntime = VkCyfraRuntime(spirvToolsRunner = + SpirvToolsRunner( crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))), - disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/disassembled.spv"))) - ) + disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/disassembled.spv"))), + ), ) override def afterAll(): Unit = - //cr.close() + // cr.close() super.afterAll() test("fs2 through GPipe map, just ints"): @@ -57,7 +58,7 @@ class Fs2Tests extends munit.FunSuite: test("fs2 through GPipe filter, just ints"): val n = 16 - val inSeq = (0 until n * 256) + val inSeq = 0 until n * 256 val stream = Stream.emits(inSeq) val pipe = GPipe.filter[Pure, Int32, Int](_.mod(7) === 0) val result = stream.through(pipe).compile.toList @@ -65,4 +66,4 @@ class Fs2Tests extends munit.FunSuite: result .zip(expected) .foreach: (res, exp) => - assert(res == exp, s"Expected $exp, got $res") \ No newline at end of file + assert(res == exp, s"Expected $exp, got $res") diff --git a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala index ecea9250..0e1781df 100644 --- a/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala +++ b/cyfra-examples/src/main/scala/io/computenode/cyfra/samples/TestingStuff.scala @@ -18,7 +18,7 @@ import java.util.concurrent.atomic.AtomicInteger import scala.collection.parallel.CollectionConverters.given object TestingStuff: - + // === Emit program === case class EmitProgramParams(inSize: Int, emitN: Int) @@ -53,14 +53,13 @@ object TestingStuff: case class FilterProgramUniform(filterValue: Int32) extends GStruct[FilterProgramUniform] - case class FilterProgramLayout(in: GBuffer[Int32], out: GBuffer[GBoolean], params: GUniform[FilterProgramUniform] = GUniform.fromParams) - extends Layout + case class FilterProgramLayout(in: GBuffer[Int32], out: GBuffer[Int32], params: GUniform[FilterProgramUniform] = GUniform.fromParams) extends Layout val filterProgram = GProgram[FilterProgramParams, FilterProgramLayout]( layout = params => FilterProgramLayout( in = GBuffer[Int32](params.inSize), - out = GBuffer[GBoolean](params.inSize), + out = GBuffer[Int32](params.inSize), params = GUniform(FilterProgramUniform(params.filterValue)), ), dispatch = (_, args) => GProgram.StaticDispatch((args.inSize / 128, 1, 1)), @@ -68,15 +67,16 @@ object TestingStuff: val invocId = GIO.invocationId val element = GIO.read(layout.in, invocId) val isMatch = element === layout.params.read.filterValue - GIO.write(layout.out, invocId, isMatch) + val a: Int32 = when[Int32](isMatch)(1).otherwise(0) + GIO.write(layout.out, invocId, a) // === GExecution === case class EmitFilterParams(inSize: Int, emitN: Int, filterValue: Int) - case class EmitFilterLayout(inBuffer: GBuffer[Int32], emitBuffer: GBuffer[Int32], filterBuffer: GBuffer[GBoolean]) extends Layout + case class EmitFilterLayout(inBuffer: GBuffer[Int32], emitBuffer: GBuffer[Int32], filterBuffer: GBuffer[Int32]) extends Layout - case class EmitFilterResult(out: GBuffer[GBoolean]) extends Layout + case class EmitFilterResult(out: GBuffer[Int32]) extends Layout val emitFilterExecution = GExecution[EmitFilterParams, EmitFilterLayout]() .addProgram(emitProgram)( @@ -90,11 +90,8 @@ object TestingStuff: @main def testEmit = - given runtime: VkCyfraRuntime = VkCyfraRuntime( - spirvToolsRunner = SpirvToolsRunner( - crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))) - ) - ) + given runtime: VkCyfraRuntime = + VkCyfraRuntime(spirvToolsRunner = SpirvToolsRunner(crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))))) val emitParams = EmitProgramParams(inSize = 1024, emitN = 2) @@ -110,10 +107,7 @@ object TestingStuff: val result = BufferUtils.createIntBuffer(data.length * 2) val rbb = MemoryUtil.memByteBuffer(result) region.runUnsafe( - init = EmitProgramLayout( - in = GBuffer[Int32](buffer), - out = GBuffer[Int32](data.length * 2), - ), + init = EmitProgramLayout(in = GBuffer[Int32](buffer), out = GBuffer[Int32](data.length * 2)), onDone = layout => layout.out.read(rbb), ) runtime.close() @@ -128,11 +122,11 @@ object TestingStuff: @main def test = - given runtime: VkCyfraRuntime = VkCyfraRuntime( - spirvToolsRunner = SpirvToolsRunner( + given runtime: VkCyfraRuntime = VkCyfraRuntime(spirvToolsRunner = + SpirvToolsRunner( crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))), - validator = SpirvValidator.Disable - ) + validator = SpirvValidator.Disable, + ), ) val emitFilterParams = EmitFilterParams(inSize = 1024, emitN = 2, filterValue = 42) @@ -152,7 +146,7 @@ object TestingStuff: init = EmitFilterLayout( inBuffer = GBuffer[Int32](buffer), emitBuffer = GBuffer[Int32](data.length * 2), - filterBuffer = GBuffer[GBoolean](data.length * 2), + filterBuffer = GBuffer[Int32](data.length * 2), ), onDone = layout => layout.filterBuffer.read(rbb), ) @@ -165,3 +159,4 @@ object TestingStuff: .zipWithIndex .foreach: case ((e, a), i) => assert(e == a, s"Mismatch at index $i: expected $e, got $a") + println("DONE") diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index f75ac208..90c76906 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -35,14 +35,13 @@ object GPipe: val gProg = GProgram[Params, PLayout]( layout = params => PLayout(in = GBuffer[C1](params.inSize), out = GBuffer[C2](params.inSize)), dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize / 256f).toInt, 1, 1)), - )(layout => { + ) { layout => val invocId = GIO.invocationId val element = GIO.read[C1](layout.in, invocId) val res = f(element) - for - _ <- GIO.write[C2](layout.out, invocId, res) + for _ <- GIO.write[C2](layout.out, invocId, res) yield Empty() - }) + } val execution = GExecution[Params, PLayout]() .addProgram(gProg)(params => Params(params.inSize), layout => PLayout(layout.in, layout.out)) @@ -60,12 +59,7 @@ object GPipe: .chunkN(params.inSize) .flatMap: chunk => bridge1.toByteBuffer(inBuf, chunk.toArray) - region.runUnsafe(init = PLayout( - in = GBuffer[C1](inBuf), - out = GBuffer[C2](outBuf)), - onDone = layout => - layout.out.read(outBuf) - ) + region.runUnsafe(init = PLayout(in = GBuffer[C1](inBuf), out = GBuffer[C2](outBuf)), onDone = layout => layout.out.read(outBuf)) Stream.emits(bridge2.fromByteBuffer(outBuf, new Array[S2](params.inSize))) // Overload for convenient single type version @@ -87,9 +81,7 @@ object GPipe: val invocId = GIO.invocationId val element = GIO.read[C](layout.in, invocId) val result = when(pred(element))(1: Int32).otherwise(0) - for - _ <- GIO.printf("Pred: Element %d -> %d", invocId, result) - _ <- GIO.write[Int32](layout.out, invocId, result) + for _ <- GIO.write[Int32](layout.out, invocId, result) yield Empty() // Prefix sum (inclusive), upsweep/downsweep @@ -110,9 +102,7 @@ object GPipe: val oldValue = GIO.read[Int32](layout.ints, end) val addValue = GIO.read[Int32](layout.ints, mid) val newValue = oldValue + addValue - for - _ <- GIO.printf("Upsweep: invocId %d, root %d, size %d, mid %d, end %d, oldValue %d, addValue %d, newValue %d", invocId, root, size, mid, end, oldValue, addValue, newValue) - _ <- GIO.write[Int32](layout.ints, end, newValue) + for _ <- GIO.write[Int32](layout.ints, end, newValue) yield Empty() val downsweep = GProgram[ScanParams, ScanLayout]( @@ -127,9 +117,7 @@ object GPipe: val oldValue = GIO.read[Int32](layout.ints, mid) val addValue = when(end > 0)(GIO.read[Int32](layout.ints, end)).otherwise(0) val newValue = oldValue + addValue - for - _ <- GIO.printf("Downsweep: invocId %d, end %d, mid %d, oldValue %d, addValue %d, newValue %d", invocId, end, mid, oldValue, addValue, newValue) - _ <- GIO.write[Int32](layout.ints, mid, newValue) + for _ <- GIO.write[Int32](layout.ints, mid, newValue) yield Empty() // Stitch together many upsweep / downsweep program phases recursively @@ -171,7 +159,6 @@ object GPipe: val element = GIO.read[C](layout.in, invocId) val prefixSum = GIO.read[Int32](layout.scan, invocId) for - _ <- GIO.printf("Compact: Element %d, prefix sum %d", invocId, prefixSum) _ <- GIO.when(invocId > 0): val prevScan = GIO.read[Int32](layout.scan, invocId - 1) GIO.when(prevScan < prefixSum): @@ -227,7 +214,7 @@ object GPipe: onDone = layout => { layout.scan.read(filteredCount, (filterParams.inSize - 1) * intSize) layout.out.read(compactBuf) - } + }, ) val filteredN = filteredCount.getInt(0) val arr = bridge.fromByteBuffer(compactBuf, new Array[S](filteredN)) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala index 67d612fe..eade4596 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/VulkanContext.scala @@ -1,9 +1,9 @@ package io.computenode.cyfra.vulkan import io.computenode.cyfra.utility.Logger.logger -import io.computenode.cyfra.vulkan.VulkanContext.ValidationLayers +import io.computenode.cyfra.vulkan.VulkanContext.{validation, vulkanPrintf} import io.computenode.cyfra.vulkan.command.CommandPool -import io.computenode.cyfra.vulkan.core.{DebugCallback, Device, Instance, PhysicalDevice, Queue} +import io.computenode.cyfra.vulkan.core.{DebugMessengerCallback, DebugReportCallback, Device, Instance, PhysicalDevice, Queue} import io.computenode.cyfra.vulkan.memory.{Allocator, DescriptorPool, DescriptorPoolManager, DescriptorSetManager} import org.lwjgl.system.Configuration @@ -15,12 +15,13 @@ import scala.jdk.CollectionConverters.* * MarconZet Created 13.04.2020 */ private[cyfra] object VulkanContext: - val ValidationLayer: String = "VK_LAYER_KHRONOS_validation" - private val ValidationLayers: Boolean = System.getProperty("io.computenode.cyfra.vulkan.validation", "false").toBoolean + private val validation: Boolean = System.getProperty("io.computenode.cyfra.vulkan.validation", "false").toBoolean + private val vulkanPrintf: Boolean = System.getProperty("io.computenode.cyfra.vulkan.printf", "false").toBoolean private[cyfra] class VulkanContext: - private val instance: Instance = new Instance(ValidationLayers) - private val debugCallback: Option[DebugCallback] = if ValidationLayers then Some(new DebugCallback(instance)) else None + private val instance: Instance = new Instance(validation, vulkanPrintf) + private val debugReport: Option[DebugReportCallback] = if validation then Some(new DebugReportCallback(instance)) else None + private val debugMessenger: Option[DebugMessengerCallback] = if validation & vulkanPrintf then Some(new DebugMessengerCallback(instance)) else None private val physicalDevice = new PhysicalDevice(instance) physicalDevice.assertRequirements() @@ -54,5 +55,6 @@ private[cyfra] class VulkanContext: descriptorPoolManager.destroy() allocator.destroy() device.destroy() - debugCallback.foreach(_.destroy()) + debugReport.foreach(_.destroy()) + debugMessenger.foreach(_.destroy()) instance.destroy() diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugMessengerCallback.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugMessengerCallback.scala new file mode 100644 index 00000000..ad319665 --- /dev/null +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugMessengerCallback.scala @@ -0,0 +1,58 @@ +package io.computenode.cyfra.vulkan.core + +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} +import io.computenode.cyfra.vulkan.util.VulkanObjectHandle +import org.lwjgl.BufferUtils +import org.lwjgl.system.MemoryUtil +import org.lwjgl.vulkan.EXTDebugUtils.{ + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, + vkCreateDebugUtilsMessengerEXT, + vkDestroyDebugUtilsMessengerEXT, +} +import org.lwjgl.vulkan.VK10.VK_FALSE +import org.lwjgl.vulkan.{VkDebugUtilsMessengerCallbackDataEXT, VkDebugUtilsMessengerCallbackEXT, VkDebugUtilsMessengerCreateInfoEXT} +import org.slf4j.LoggerFactory + +import java.lang.Integer.highestOneBit +import java.nio.LongBuffer + +class DebugMessengerCallback(instance: Instance) extends VulkanObjectHandle: + private val logger = LoggerFactory.getLogger("Cyfra-DebugMessenger") + + protected val handle: Long = pushStack: stack => + val callback = + new VkDebugUtilsMessengerCallbackEXT(): + override def invoke(messageSeverity: Int, messageTypes: Int, pCallbackData: Long, pUserData: Long): Int = + val message = VkDebugUtilsMessengerCallbackDataEXT.create(pCallbackData).pMessageString() + val debugMessage = message.split("\\|").last + highestOneBit(messageSeverity) match + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT => logger.error(debugMessage) + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT => logger.warn(debugMessage) + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT => logger.info(debugMessage) + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT => logger.debug(debugMessage) + case x => logger.error(s"Unexpected message severity: $messageSeverity, message: $debugMessage") + VK_FALSE + + val debugMessengerCreate = VkDebugUtilsMessengerCreateInfoEXT + .calloc(stack) + .sType$Default() + .messageSeverity( + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + ) + .messageType( + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + ) + .pfnUserCallback(callback) + + val debugMessengerBuff = stack.callocLong(1) + check(vkCreateDebugUtilsMessengerEXT(instance.get, debugMessengerCreate, null, debugMessengerBuff), "Failed to create debug messenger") + debugMessengerBuff.get() + + override protected def close(): Unit = vkDestroyDebugUtilsMessengerEXT(instance.get, handle, null) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugReportCallback.scala similarity index 56% rename from cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala rename to cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugReportCallback.scala index 3721e9b3..2e43450d 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugCallback.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/DebugReportCallback.scala @@ -1,24 +1,28 @@ package io.computenode.cyfra.vulkan.core import io.computenode.cyfra.utility.Logger.logger -import io.computenode.cyfra.vulkan.core.DebugCallback.DebugReport +import io.computenode.cyfra.vulkan.core.DebugReportCallback.DebugReport +import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.{VulkanAssertionError, VulkanObjectHandle} import org.lwjgl.BufferUtils import org.lwjgl.system.MemoryUtil.NULL import org.lwjgl.vulkan.EXTDebugReport.* import org.lwjgl.vulkan.VK10.VK_SUCCESS import org.lwjgl.vulkan.{VkDebugReportCallbackCreateInfoEXT, VkDebugReportCallbackEXT} +import org.slf4j.LoggerFactory import java.lang.Integer.highestOneBit /** @author * MarconZet Created 13.04.2020 */ -object DebugCallback: +object DebugReportCallback: val DebugReport: Int = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT -private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandle: - override protected val handle: Long = +private[cyfra] class DebugReportCallback(instance: Instance) extends VulkanObjectHandle: + private val logger = LoggerFactory.getLogger("Cyfra-DebugReport") + + protected val handle: Long = pushStack: stack => val debugCallback = new VkDebugReportCallbackEXT(): def invoke( flags: Int, @@ -32,31 +36,23 @@ private[cyfra] class DebugCallback(instance: Instance) extends VulkanObjectHandl ): Int = val decodedMessage = VkDebugReportCallbackEXT.getString(pMessage) highestOneBit(flags) match - case VK_DEBUG_REPORT_DEBUG_BIT_EXT => - logger.debug(decodedMessage) - case VK_DEBUG_REPORT_ERROR_BIT_EXT => - logger.error(decodedMessage) - case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT => - logger.warn(decodedMessage) - case VK_DEBUG_REPORT_INFORMATION_BIT_EXT => - logger.info(decodedMessage) + case VK_DEBUG_REPORT_DEBUG_BIT_EXT => logger.debug(decodedMessage) + case VK_DEBUG_REPORT_ERROR_BIT_EXT => logger.error(decodedMessage) + case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT => logger.warn(decodedMessage) + case VK_DEBUG_REPORT_INFORMATION_BIT_EXT => logger.info(decodedMessage) case x => logger.error(s"Unexpected value: x, message: $decodedMessage") 0 - setupDebugging(DebugReport, debugCallback) - - override protected def close(): Unit = - vkDestroyDebugReportCallbackEXT(instance.get, handle, null) - private def setupDebugging(flags: Int, callback: VkDebugReportCallbackEXT): Long = val dbgCreateInfo = VkDebugReportCallbackCreateInfoEXT - .create() + .calloc(stack) .sType$Default() .pNext(0) - .pfnCallback(callback) + .pfnCallback(debugCallback) .pUserData(0) - .flags(flags) - val pCallback = BufferUtils.createLongBuffer(1) - val err = vkCreateDebugReportCallbackEXT(instance.get, dbgCreateInfo, null, pCallback) - val callbackHandle = pCallback.get(0) - if err != VK_SUCCESS then throw new VulkanAssertionError("Failed to create DebugCallback", err) - callbackHandle + .flags(DebugReport) + val pCallback = stack.callocLong(1) + check(vkCreateDebugReportCallbackEXT(instance.get, dbgCreateInfo, null, pCallback), "Failed to create DebugCallback") + pCallback.get() + + override protected def close(): Unit = + vkDestroyDebugReportCallbackEXT(instance.get, handle, null) diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala index 6908fcfa..290ac699 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Device.scala @@ -1,6 +1,5 @@ package io.computenode.cyfra.vulkan.core -import io.computenode.cyfra.vulkan.VulkanContext.ValidationLayer import Device.MacOsExtension import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.{VulkanObject, VulkanObjectHandle} diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala index 2f3d3df5..f8661f6d 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/core/Instance.scala @@ -1,7 +1,7 @@ package io.computenode.cyfra.vulkan.core import io.computenode.cyfra.utility.Logger.logger -import io.computenode.cyfra.vulkan.VulkanContext.ValidationLayer +import io.computenode.cyfra.vulkan.core.Instance.ValidationLayer import io.computenode.cyfra.vulkan.util.Util.{check, pushStack} import io.computenode.cyfra.vulkan.util.VulkanObject import org.lwjgl.system.{MemoryStack, MemoryUtil} @@ -10,6 +10,7 @@ import org.lwjgl.vulkan.* import org.lwjgl.vulkan.EXTDebugReport.VK_EXT_DEBUG_REPORT_EXTENSION_NAME import org.lwjgl.vulkan.EXTLayerSettings.{VK_LAYER_SETTING_TYPE_BOOL32_EXT, VK_LAYER_SETTING_TYPE_STRING_EXT, VK_LAYER_SETTING_TYPE_UINT32_EXT} import org.lwjgl.vulkan.KHRPortabilityEnumeration.{VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME} +import org.lwjgl.vulkan.EXTLayerSettings.VK_EXT_LAYER_SETTINGS_EXTENSION_NAME import org.lwjgl.vulkan.VK10.* import org.lwjgl.vulkan.EXTValidationFeatures.* import org.lwjgl.vulkan.EXTDebugUtils.* @@ -23,12 +24,10 @@ import scala.util.chaining.* * MarconZet Created 13.04.2020 */ object Instance: - val ValidationLayersExtensions: Seq[String] = List( - VK_EXT_DEBUG_REPORT_EXTENSION_NAME, - VK_EXT_DEBUG_UTILS_EXTENSION_NAME, - VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME - ) - val MoltenVkExtensions: Seq[String] = List(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) + private val ValidationLayer: String = "VK_LAYER_KHRONOS_validation" + private val ValidationLayersExtensions: Seq[String] = + List(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) + private val MoltenVkExtensions: Seq[String] = List(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) lazy val (extensions, layers): (Seq[String], Seq[String]) = pushStack: stack => val ip = stack.ints(1) @@ -46,7 +45,7 @@ object Instance: lazy val version: Int = VK.getInstanceVersionSupported -private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObject[VkInstance]: +private[cyfra] class Instance(enableValidationLayers: Boolean, enablePrinting: Boolean) extends VulkanObject[VkInstance]: protected val handle: VkInstance = pushStack: stack => val appInfo = VkApplicationInfo @@ -75,93 +74,33 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj .ppEnabledLayerNames(ppEnabledLayerNames) if enableValidationLayers then - val layerSettings = VkLayerSettingEXT.calloc(2, stack) - layerSettings - .get(0) - .pLayerName(stack.ASCII(ValidationLayer)) - .pSettingName(stack.ASCII("validate_sync")) - .`type`(VK_LAYER_SETTING_TYPE_BOOL32_EXT) - .valueCount(1) - .pValues(MemoryUtil.memByteBuffer(stack.ints(1))) + val layerSettings = VkLayerSettingEXT.calloc(10, stack) + + setTrue(layerSettings.get(), "validate_sync", stack) + setTrue(layerSettings.get(), "gpuav_enable", stack) + setTrue(layerSettings.get(), "validate_best_practices", stack) + + if enablePrinting then + setTrue(layerSettings.get(), "printf_enable", stack) layerSettings - .get(1) + .get() .pLayerName(stack.ASCII(ValidationLayer)) .pSettingName(stack.ASCII("printf_buffer_size")) .`type`(VK_LAYER_SETTING_TYPE_UINT32_EXT) .valueCount(1) - .pValues(MemoryUtil.memByteBuffer(stack.ints(1024*1024))) + .pValues(MemoryUtil.memByteBuffer(stack.ints(1024 * 1024))) + layerSettings.flip() val layerSettingsCI = VkLayerSettingsCreateInfoEXT.calloc(stack).sType$Default().pSettings(layerSettings) - val validationFeatures = VkValidationFeaturesEXT.calloc(stack) - .sType$Default() - .pEnabledValidationFeatures(stack.ints( - VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT, - )) - .pNext(0) - - val validationFeaturesPCreate = VkValidationFeaturesEXT.calloc(stack) - .sType$Default() - .pEnabledValidationFeatures(stack.ints( - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, - )) - .pNext(0) - - layerSettingsCI.pNext(validationFeatures.address()) - pCreateInfo.pNext(layerSettingsCI.address()) - validationFeaturesPCreate.pNext(validationFeaturesPCreate.address()) + pCreateInfo.pNext(layerSettingsCI) val pInstance = stack.mallocPointer(1) check(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance") new VkInstance(pInstance.get(0), pCreateInfo) - protected val callback: Option[VkDebugUtilsMessengerCallbackEXT] = - if enableValidationLayers then Some: - new VkDebugUtilsMessengerCallbackEXT(): - override def invoke(messageSeverity: Int, messageTypes: Int, pCallbackData: Long, pUserData: Long): Int = - val message = VkDebugUtilsMessengerCallbackDataEXT.create(pCallbackData).pMessageString() - val debugMessage = "[VK DEBUG] " + message.split("\\|").last - if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0 then - logger.error(debugMessage) - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0 then - logger.warn(debugMessage) - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0 then - logger.info(debugMessage) - else - logger.debug(debugMessage) - VK_FALSE - else None - - protected val debugMessenger: Option[LongBuffer] = callback.map: c => - pushStack: stack => - val debugMessengerCreate = VkDebugUtilsMessengerCreateInfoEXT.calloc(1) - .sType$Default() - .messageSeverity( - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT - ) - .messageType( - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT - ) - .pfnUserCallback(c) - - val debugMessengerBuff = MemoryUtil.memAllocLong(1) - check(vkCreateDebugUtilsMessengerEXT( - handle, - debugMessengerCreate.get(0), - null, - debugMessengerBuff - )) - debugMessengerBuff - - lazy val enabledLayers: Seq[String] = List .empty[String] .pipe: x => @@ -171,8 +110,7 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj x else x - override protected def close(): Unit = - debugMessenger.foreach(b => vkDestroyDebugUtilsMessengerEXT(handle, b.get(0), null)) + override protected def close(): Unit = vkDestroyInstance(handle, null) private def getInstanceExtensions(stack: MemoryStack) = @@ -193,10 +131,18 @@ private[cyfra] class Instance(enableValidationLayers: Boolean) extends VulkanObj val filteredExtensions = extensions.filter(ext => availableExtensions .contains(ext) - .tap: x => // TODO detect when this extension is needed + .tap: x => // TODO better handle missing extensions if !x then logger.warn(s"Requested Vulkan instance extension '$ext' is not available"), ) val ppEnabledExtensionNames = stack.callocPointer(extensions.size) filteredExtensions.foreach(x => ppEnabledExtensionNames.put(stack.ASCII(x))) ppEnabledExtensionNames.flip() + + private def setTrue(setting: VkLayerSettingEXT, name: String, stack: MemoryStack) = + setting + .pLayerName(stack.ASCII(ValidationLayer)) + .pSettingName(stack.ASCII(name)) + .`type`(VK_LAYER_SETTING_TYPE_BOOL32_EXT) + .valueCount(1) + .pValues(MemoryUtil.memByteBuffer(stack.ints(1))) From 3172910fd3db7b53ee7157198486159f1f5fd45d Mon Sep 17 00:00:00 2001 From: MarconZet <25779550+MarconZet@users.noreply.github.com> Date: Sun, 21 Sep 2025 18:30:37 +0200 Subject: [PATCH 56/59] fomrating^ --- .../io/computenode/cyfra/spirv/Context.scala | 2 +- .../cyfra/spirv/SpirvConstants.scala | 2 +- .../cyfra/spirv/compilers/DSLCompiler.scala | 13 +- .../spirv/compilers/ExpressionCompiler.scala | 3 +- .../cyfra/spirv/compilers/GIOCompiler.scala | 78 ++++------- .../spirv/compilers/GStructCompiler.scala | 5 +- .../compilers/SpirvProgramCompiler.scala | 128 ++++++++---------- .../cyfra/core/GBufferRegion.scala | 2 +- .../io/computenode/cyfra/core/GCodec.scala | 52 +++---- .../io/computenode/cyfra/core/GProgram.scala | 4 +- .../computenode/cyfra/core/SpirvProgram.scala | 15 +- .../cyfra/core/archive/GFunction.scala | 75 ++++------ .../cyfra/core/layout/LayoutStruct.scala | 18 +-- .../cyfra/dsl/collections/GArray.scala | 1 - .../io/computenode/cyfra/dsl/gio/GIO.scala | 4 +- .../cyfra/e2e/RuntimeEnduranceTest.scala | 17 +-- .../cyfra/e2e/SpirvRuntimeEnduranceTest.scala | 23 ++-- .../cyfra/e2e/dsl/ArithmeticsE2eTest.scala | 2 +- .../cyfra/e2e/dsl/FunctionsE2eTest.scala | 2 +- .../cyfra/e2e/dsl/GseqE2eTest.scala | 2 +- .../cyfra/foton/rt/ImageRtRenderer.scala | 2 +- .../rt/animation/AnimationRtRenderer.scala | 3 +- .../cyfra/runtime/ExecutionHandler.scala | 38 +++--- .../cyfra/runtime/VkAllocation.scala | 2 +- .../cyfra/runtime/VkCyfraRuntime.scala | 8 +- .../computenode/cyfra/runtime/VkShader.scala | 3 +- .../cyfra/spirvtools/SpirvCross.scala | 2 +- .../cyfra/spirvtools/SpirvDisassembler.scala | 2 +- .../cyfra/spirvtools/SpirvOptimizer.scala | 2 +- .../cyfra/vulkan/command/Fence.scala | 2 +- 30 files changed, 237 insertions(+), 275 deletions(-) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala index 0312d9db..96490071 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/Context.scala @@ -27,7 +27,7 @@ private[cyfra] case class Context( exprNames: Map[Int, String] = Map(), names: Set[String] = Set(), functions: Map[FnIdentifier, SprivFunction] = Map(), - stringLiterals: Map[String, Int] = Map() + stringLiterals: Map[String, Int] = Map(), ): def joinNested(ctx: Context): Context = this.copy(nextResultId = ctx.nextResultId, exprNames = ctx.exprNames ++ this.exprNames, functions = ctx.functions ++ this.functions) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvConstants.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvConstants.scala index 00a3f615..ec3c4d0b 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvConstants.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/SpirvConstants.scala @@ -17,5 +17,5 @@ private[cyfra] object SpirvConstants: val GL_GLOBAL_INVOCATION_ID_REF = 5 val GL_WORKGROUP_SIZE_REF = 6 val DEBUG_PRINTF_REF = 7 - + val HEADER_REFS_TOP = 8 diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala index f5975295..8bdafb24 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/DSLCompiler.scala @@ -29,7 +29,7 @@ private[cyfra] object DSLCompiler: @tailrec private def getAllExprsFlattened(pending: List[GIO[?]], acc: List[E[?]], visitDetached: Boolean): List[E[?]] = pending match - case Nil => acc + case Nil => acc case GIO.Pure(v) :: tail => getAllExprsFlattened(tail, getAllExprsFlattened(v.tree, visitDetached) ::: acc, visitDetached) case GIO.FlatMap(v, n) :: tail => @@ -74,7 +74,7 @@ private[cyfra] object DSLCompiler: // So far only used for printf private def getAllStrings(pending: List[GIO[?]], acc: Set[String]): Set[String] = pending match - case Nil => acc + case Nil => acc case GIO.FlatMap(v, n) :: tail => getAllStrings(v :: n :: tail, acc) case GIO.Repeat(_, gio) :: tail => @@ -91,10 +91,11 @@ private[cyfra] object DSLCompiler: val (typeDefs, typedContext) = defineScalarTypes(scalarTypes, Context.initialContext) val allStrings = getAllStrings(List(bodyIo), Set.empty) val (stringDefs, ctxWithStrings) = defineStrings(allStrings.toList, typedContext) - val (buffersWithIndices, uniformsWithIndices) = bindings.zipWithIndex.partition: - case (_: GBuffer[?], _) => true - case (_: GUniform[?], _) => false - .asInstanceOf[(List[(GBuffer[?], Int)], List[(GUniform[?], Int)])] + val (buffersWithIndices, uniformsWithIndices) = bindings.zipWithIndex + .partition: + case (_: GBuffer[?], _) => true + case (_: GUniform[?], _) => false + .asInstanceOf[(List[(GBuffer[?], Int)], List[(GUniform[?], Int)])] val uniforms = uniformsWithIndices.map(_._1) val uniformSchemas = uniforms.map(_.schema) val structsInCode = diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala index c1459fcf..6e859bd3 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/ExpressionCompiler.scala @@ -306,7 +306,6 @@ private[cyfra] object ExpressionCompiler: val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (expr.treeid -> (ctx.nextResultId + 1)), nextResultId = ctx.nextResultId + 2) (instructions, updatedContext) - case when: WhenExpr[?] => compileWhen(when, ctx) @@ -327,7 +326,7 @@ private[cyfra] object ExpressionCompiler: ) val updatedContext = ctx.copy(exprRefs = ctx.exprRefs + (cs.treeid -> ctx.nextResultId), nextResultId = ctx.nextResultId + 1) (insns, updatedContext) - + case gf @ GetField(binding @ ReadUniform(uf), fieldIndex) => val insns: List[Instruction] = List( Instruction( diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala index 5d54fc2b..11adc24c 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GIOCompiler.scala @@ -9,19 +9,20 @@ import io.computenode.cyfra.spirv.SpirvConstants.{DEBUG_PRINTF_REF, TYPE_VOID_RE import io.computenode.cyfra.spirv.SpirvTypes.{GBooleanTag, Int32Tag, LInt32Tag} object GIOCompiler: - + def compileGio(gio: GIO[?], ctx: Context, acc: List[Words] = Nil): (List[Words], Context) = gio match case GIO.Pure(v) => val (insts, updatedCtx) = ExpressionCompiler.compileBlock(v.tree, ctx) (acc ::: insts, updatedCtx) - + case WriteBuffer(buffer, index, value) => val (valueInsts, ctxWithValue) = ExpressionCompiler.compileBlock(value.tree, ctx) val (indexInsts, ctxWithIndex) = ExpressionCompiler.compileBlock(index.tree, ctxWithValue) - val insns = List(Instruction( + val insns = List( + Instruction( Op.OpAccessChain, List( ResultRef(ctxWithIndex.uniformPointerMap(ctxWithIndex.valueTypeMap(buffer.tag.tag))), @@ -31,7 +32,7 @@ object GIOCompiler: ResultRef(ctxWithIndex.exprRefs(index.tree.treeid)), ), ), - Instruction(Op.OpStore, List(ResultRef(ctxWithIndex.nextResultId), ResultRef(ctxWithIndex.exprRefs(value.tree.treeid)))) + Instruction(Op.OpStore, List(ResultRef(ctxWithIndex.nextResultId), ResultRef(ctxWithIndex.exprRefs(value.tree.treeid)))), ) val updatedCtx = ctxWithIndex.copy(nextResultId = ctxWithIndex.nextResultId + 1) (acc ::: indexInsts ::: valueInsts ::: insns, updatedCtx) @@ -39,7 +40,7 @@ object GIOCompiler: case GIO.FlatMap(v, n) => val (vInsts, ctxAfterV) = compileGio(v, ctx, acc) compileGio(n, ctxAfterV, vInsts) - + case GIO.Repeat(n, f) => // Compile 'n' first (so we can use its id in the comparison) val (nInsts, ctxWithN) = ExpressionCompiler.compileBlock(n.tree, ctx) @@ -63,17 +64,14 @@ object GIOCompiler: val addId = baseId + 7 // Bind CurrentRepeatIndex to the phi result for body compilation - val bodyCtx = ctxWithN.copy( - nextResultId = baseId + 8, - exprRefs = ctxWithN.exprRefs + (CurrentRepeatIndex.treeid -> phiId) - ) - val (bodyInsts, ctxAfterBody) = compileGio(f, bodyCtx) // ← Capture the context after body compilation + val bodyCtx = ctxWithN.copy(nextResultId = baseId + 8, exprRefs = ctxWithN.exprRefs + (CurrentRepeatIndex.treeid -> phiId)) + val (bodyInsts, ctxAfterBody) = compileGio(f, bodyCtx) // ← Capture the context after body compilation // Preheader: close current block and jump to header through a dedicated block val preheader = List( Instruction(Op.OpBranch, List(ResultRef(preHeaderId))), Instruction(Op.OpLabel, List(ResultRef(preHeaderId))), - Instruction(Op.OpBranch, List(ResultRef(headerId))) + Instruction(Op.OpBranch, List(ResultRef(headerId))), ) // Header: OpPhi first, then compute condition, then OpLoopMerge and the terminating branch @@ -82,66 +80,46 @@ object GIOCompiler: // OpPhi must be first in the block Instruction( Op.OpPhi, - List( - ResultRef(intTy), ResultRef(phiId), - ResultRef(zeroId), ResultRef(preHeaderId), - ResultRef(addId), ResultRef(continueId) - ) + List(ResultRef(intTy), ResultRef(phiId), ResultRef(zeroId), ResultRef(preHeaderId), ResultRef(addId), ResultRef(continueId)), ), // cmp = (counter < n) - Instruction( - Op.OpSLessThan, - List(ResultRef(boolTy), ResultRef(cmpId), ResultRef(phiId), ResultRef(nId)) - ), + Instruction(Op.OpSLessThan, List(ResultRef(boolTy), ResultRef(cmpId), ResultRef(phiId), ResultRef(nId))), // OpLoopMerge must be the second-to-last instruction, before the terminating branch Instruction(Op.OpLoopMerge, List(ResultRef(mergeId), ResultRef(continueId), LoopControlMask.MaskNone)), - Instruction(Op.OpBranchConditional, List(ResultRef(cmpId), ResultRef(bodyId), ResultRef(mergeId))) + Instruction(Op.OpBranchConditional, List(ResultRef(cmpId), ResultRef(bodyId), ResultRef(mergeId))), ) - val bodyBlk = List( - Instruction(Op.OpLabel, List(ResultRef(bodyId))) - ) ::: bodyInsts ::: List( - Instruction(Op.OpBranch, List(ResultRef(continueId))) - ) + val bodyBlk = List(Instruction(Op.OpLabel, List(ResultRef(bodyId)))) ::: bodyInsts ::: List(Instruction(Op.OpBranch, List(ResultRef(continueId)))) val contBlk = List( Instruction(Op.OpLabel, List(ResultRef(continueId))), - Instruction( - Op.OpIAdd, - List(ResultRef(intTy), ResultRef(addId), ResultRef(phiId), ResultRef(oneId)) - ), - Instruction(Op.OpBranch, List(ResultRef(headerId))) + Instruction(Op.OpIAdd, List(ResultRef(intTy), ResultRef(addId), ResultRef(phiId), ResultRef(oneId))), + Instruction(Op.OpBranch, List(ResultRef(headerId))), ) - val mergeBlk = List( - Instruction(Op.OpLabel, List(ResultRef(mergeId))) - ) + val mergeBlk = List(Instruction(Op.OpLabel, List(ResultRef(mergeId)))) // Use the highest nextResultId to avoid ID collisions - val finalNextId = math.max(ctxAfterBody.nextResultId, addId + 1) // ← Use ctxAfterBody.nextResultId + val finalNextId = math.max(ctxAfterBody.nextResultId, addId + 1) // ← Use ctxAfterBody.nextResultId // Use ctxWithN as base to prevent loop-local values from being referenced outside val finalCtx = ctxWithN.copy(nextResultId = finalNextId) (acc ::: nInsts ::: preheader ::: header ::: bodyBlk ::: contBlk ::: mergeBlk, finalCtx) - + case GIO.Printf(format, args*) => val (argsInsts, ctxAfterArgs) = args.foldLeft((List.empty[Words], ctx)) { case ((instsAcc, cAcc), arg) => val (argInsts, cAfterArg) = ExpressionCompiler.compileBlock(arg.tree, cAcc) (instsAcc ::: argInsts, cAfterArg) } val argResults = args.map(a => ResultRef(ctxAfterArgs.exprRefs(a.tree.treeid))).toList - val printf = Instruction(Op.OpExtInst, List( - ResultRef(TYPE_VOID_REF), - ResultRef(ctxAfterArgs.nextResultId), - ResultRef(DEBUG_PRINTF_REF), - IntWord(1), - ResultRef(ctx.stringLiterals(format)), - ) ::: argResults) + val printf = Instruction( + Op.OpExtInst, + List( + ResultRef(TYPE_VOID_REF), + ResultRef(ctxAfterArgs.nextResultId), + ResultRef(DEBUG_PRINTF_REF), + IntWord(1), + ResultRef(ctx.stringLiterals(format)), + ) ::: argResults, + ) (acc ::: argsInsts ::: List(printf), ctxAfterArgs.copy(nextResultId = ctxAfterArgs.nextResultId + 1)) - - - - - - - \ No newline at end of file diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala index 2542e1f8..78683deb 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/GStructCompiler.scala @@ -37,8 +37,9 @@ private[cyfra] object GStructCompiler: structName = s"${schema.structTag.tag.shortName}_$nameSuffix" nameSuffix += 1 val structType = context.valueTypeMap(schema.structTag.tag) - val words = Instruction(Op.OpName, List(ResultRef(structType), Text(structName))) :: schema.fields.zipWithIndex.map { case ((name, _, tag), i) => - Instruction(Op.OpMemberName, List(ResultRef(structType), IntWord(i), Text(name))) + val words = Instruction(Op.OpName, List(ResultRef(structType), Text(structName))) :: schema.fields.zipWithIndex.map { + case ((name, _, tag), i) => + Instruction(Op.OpMemberName, List(ResultRef(structType), IntWord(i), Text(name))) } val updatedCtx = currCtx.copy(names = currCtx.names + structName) (wordsAcc ::: words, updatedCtx) diff --git a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala index ee523d35..e80ed296 100644 --- a/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala +++ b/cyfra-compiler/src/main/scala/io/computenode/cyfra/spirv/compilers/SpirvProgramCompiler.scala @@ -44,10 +44,7 @@ private[cyfra] object SpirvProgramCompiler: val (vars, nonVarsBody) = bubbleUpVars(body) - val end = List( - Instruction(Op.OpReturn, List()), - Instruction(Op.OpFunctionEnd, List()), - ) + val end = List(Instruction(Op.OpReturn, List()), Instruction(Op.OpFunctionEnd, List())) (init ::: vars ::: initWorkerIndex ::: nonVarsBody ::: end, codeCtx.copy(nextResultId = codeCtx.nextResultId + 1)) def getNameDecorations(ctx: Context): List[Instruction] = @@ -94,7 +91,7 @@ private[cyfra] object SpirvProgramCompiler: ) val ctxWithVoid = context.copy(voidTypeRef = TYPE_VOID_REF, voidFuncTypeRef = VOID_FUNC_TYPE_REF) (voidDef, ctxWithVoid) - + def createInvocationId(context: Context): (List[Words], Context) = val definitionInstructions = List( Instruction(Op.OpConstant, List(ResultRef(context.valueTypeMap(UInt32Tag.tag)), ResultRef(context.nextResultId + 0), IntWord(localSizeX))), @@ -120,54 +117,51 @@ private[cyfra] object SpirvProgramCompiler: def createAndInitBlocks(blocks: List[(GBuffer[?], Int)], context: Context): (List[Words], List[Words], Context) = var membersVisited = Set[Int]() var structsVisited = Set[Int]() - val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { case ((decAcc, insnAcc, ctx), (buff, binding)) => - val tpe = buff.tag - val block = ArrayBufferBlock(ctx.nextResultId, ctx.nextResultId + 1, ctx.nextResultId + 2, ctx.nextResultId + 3, binding) - - val (structDecoration, structDefinition) = if structsVisited.contains(block.structTypeRef) then - (Nil, Nil) - else - structsVisited += block.structTypeRef - ( - List( - Instruction(Op.OpMemberDecorate, List(ResultRef(block.structTypeRef), IntWord(0), Decoration.Offset, IntWord(0))), // OpMemberDecorate %BufferX 0 Offset 0 - Instruction(Op.OpDecorate, List(ResultRef(block.structTypeRef), Decoration.BufferBlock)), // OpDecorate %BufferX BufferBlock - ), - List( - Instruction(Op.OpTypeStruct, List(ResultRef(block.structTypeRef), IntWord(block.memberArrayTypeRef))), // %BufferX = OpTypeStruct %_runtimearr_X - ) - ) + val (decoration, definition, newContext) = blocks.foldLeft((List[Words](), List[Words](), context)) { + case ((decAcc, insnAcc, ctx), (buff, binding)) => + val tpe = buff.tag + val block = ArrayBufferBlock(ctx.nextResultId, ctx.nextResultId + 1, ctx.nextResultId + 2, ctx.nextResultId + 3, binding) - val (memberDecoration, memberDefinition) = if membersVisited.contains(block.memberArrayTypeRef) then - (Nil, Nil) - else - membersVisited += block.memberArrayTypeRef - ( - List( - Instruction(Op.OpDecorate, List(ResultRef(block.memberArrayTypeRef), Decoration.ArrayStride, IntWord(typeStride(tpe)))), // OpDecorate %_runtimearr_X ArrayStride [typeStride(type)] - ), - List( - Instruction(Op.OpTypeRuntimeArray, List(ResultRef(block.memberArrayTypeRef), IntWord(context.valueTypeMap(tpe.tag)))), // %_runtimearr_X = OpTypeRuntimeArray %[typeOf(tpe)] - ) - ) + val (structDecoration, structDefinition) = + if structsVisited.contains(block.structTypeRef) then (Nil, Nil) + else + structsVisited += block.structTypeRef + ( + List( + Instruction(Op.OpMemberDecorate, List(ResultRef(block.structTypeRef), IntWord(0), Decoration.Offset, IntWord(0))), // OpMemberDecorate %BufferX 0 Offset 0 + Instruction(Op.OpDecorate, List(ResultRef(block.structTypeRef), Decoration.BufferBlock)), // OpDecorate %BufferX BufferBlock + ), + List( + Instruction(Op.OpTypeStruct, List(ResultRef(block.structTypeRef), IntWord(block.memberArrayTypeRef))), // %BufferX = OpTypeStruct %_runtimearr_X + ), + ) - val decorationInstructions = memberDecoration ::: structDecoration ::: List[Words]( - Instruction(Op.OpDecorate, List(ResultRef(block.blockVarRef), Decoration.DescriptorSet, IntWord(0))), // OpDecorate %_X DescriptorSet 0 - Instruction(Op.OpDecorate, List(ResultRef(block.blockVarRef), Decoration.Binding, IntWord(block.binding))), // OpDecorate %_X Binding [binding] - ) + val (memberDecoration, memberDefinition) = + if membersVisited.contains(block.memberArrayTypeRef) then (Nil, Nil) + else + membersVisited += block.memberArrayTypeRef + ( + List( + Instruction(Op.OpDecorate, List(ResultRef(block.memberArrayTypeRef), Decoration.ArrayStride, IntWord(typeStride(tpe)))), // OpDecorate %_runtimearr_X ArrayStride [typeStride(type)] + ), + List( + Instruction(Op.OpTypeRuntimeArray, List(ResultRef(block.memberArrayTypeRef), IntWord(context.valueTypeMap(tpe.tag)))), // %_runtimearr_X = OpTypeRuntimeArray %[typeOf(tpe)] + ), + ) - val definitionInstructions = memberDefinition ::: structDefinition ::: List[Words]( - Instruction(Op.OpTypePointer, List(ResultRef(block.blockPointerRef), StorageClass.Uniform, ResultRef(block.structTypeRef))), // %_ptr_Uniform_BufferX= OpTypePointer Uniform %BufferX - Instruction(Op.OpVariable, List(ResultRef(block.blockPointerRef), ResultRef(block.blockVarRef), StorageClass.Uniform)), // %_X = OpVariable %_ptr_Uniform_X Uniform - ) + val decorationInstructions = memberDecoration ::: structDecoration ::: List[Words]( + Instruction(Op.OpDecorate, List(ResultRef(block.blockVarRef), Decoration.DescriptorSet, IntWord(0))), // OpDecorate %_X DescriptorSet 0 + Instruction(Op.OpDecorate, List(ResultRef(block.blockVarRef), Decoration.Binding, IntWord(block.binding))), // OpDecorate %_X Binding [binding] + ) - val contextWithBlock = - ctx.copy(bufferBlocks = ctx.bufferBlocks + (buff -> block)) - ( - decAcc ::: decorationInstructions, - insnAcc ::: definitionInstructions, - contextWithBlock.copy(nextResultId = contextWithBlock.nextResultId + 5), - ) + val definitionInstructions = memberDefinition ::: structDefinition ::: List[Words]( + Instruction(Op.OpTypePointer, List(ResultRef(block.blockPointerRef), StorageClass.Uniform, ResultRef(block.structTypeRef))), // %_ptr_Uniform_BufferX= OpTypePointer Uniform %BufferX + Instruction(Op.OpVariable, List(ResultRef(block.blockPointerRef), ResultRef(block.blockVarRef), StorageClass.Uniform)), // %_X = OpVariable %_ptr_Uniform_X Uniform + ) + + val contextWithBlock = + ctx.copy(bufferBlocks = ctx.bufferBlocks + (buff -> block)) + (decAcc ::: decorationInstructions, insnAcc ::: definitionInstructions, contextWithBlock.copy(nextResultId = contextWithBlock.nextResultId + 5)) } (decoration, definition, newContext) @@ -176,7 +170,7 @@ private[cyfra] object SpirvProgramCompiler: Instruction(Op.OpName, List(ResultRef(block.structTypeRef), Text(s"Buffer$tpe"))) :: Instruction(Op.OpName, List(ResultRef(block.blockVarRef), Text(s"data$tpe"))) :: Nil // todo name uniform - //context.inBufferBlocks.flatMap(namesForBlock(_, "In")) ::: context.outBufferBlocks.flatMap(namesForBlock(_, "Out")) + // context.inBufferBlocks.flatMap(namesForBlock(_, "In")) ::: context.outBufferBlocks.flatMap(namesForBlock(_, "Out")) List() def totalStride(gs: GStructSchema[?]): Int = gs.fields @@ -187,20 +181,16 @@ private[cyfra] object SpirvProgramCompiler: case (_, _, t) => typeStride(t) .sum - + def defineStrings(strings: List[String], ctx: Context): (List[Words], Context) = strings.foldLeft((List.empty[Words], ctx)): case ((insnsAcc, currentCtx), str) => - if currentCtx.stringLiterals.contains(str) then - (insnsAcc, currentCtx) + if currentCtx.stringLiterals.contains(str) then (insnsAcc, currentCtx) else val strRef = currentCtx.nextResultId - val strInsns = List( - Instruction(Op.OpString, List(ResultRef(strRef), Text(str))), - ) + val strInsns = List(Instruction(Op.OpString, List(ResultRef(strRef), Text(str)))) val newCtx = currentCtx.copy(stringLiterals = currentCtx.stringLiterals + (str -> strRef), nextResultId = currentCtx.nextResultId + 1) (insnsAcc ::: strInsns, newCtx) - def createAndInitUniformBlocks(schemas: List[(GUniform[?], Int)], ctx: Context): (List[Words], List[Words], Context) = { var decoratedOffsets = Set[Int]() @@ -212,16 +202,18 @@ private[cyfra] object SpirvProgramCompiler: if decoratedOffsets.contains(uniformStructTypeRef) then Nil else decoratedOffsets += uniformStructTypeRef - schema.fields.zipWithIndex.foldLeft[(List[Words], Int)](List.empty[Words], 0): - case ((acc, offset), ((name, fromExpr, tag), idx)) => - val stride = - if tag <:< schema.gStructTag then - val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] - totalStride(constructor.schema) - else typeStride(tag) - val offsetDecoration = Instruction(Op.OpMemberDecorate, List(ResultRef(uniformStructTypeRef), IntWord(idx), Decoration.Offset, IntWord(offset))) - (acc :+ offsetDecoration, offset + stride) - ._1 ::: List(Instruction(Op.OpDecorate, List(ResultRef(uniformStructTypeRef), Decoration.Block))) + schema.fields.zipWithIndex + .foldLeft[(List[Words], Int)](List.empty[Words], 0): + case ((acc, offset), ((name, fromExpr, tag), idx)) => + val stride = + if tag <:< schema.gStructTag then + val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] + totalStride(constructor.schema) + else typeStride(tag) + val offsetDecoration = + Instruction(Op.OpMemberDecorate, List(ResultRef(uniformStructTypeRef), IntWord(idx), Decoration.Offset, IntWord(offset))) + (acc :+ offsetDecoration, offset + stride) + ._1 ::: List(Instruction(Op.OpDecorate, List(ResultRef(uniformStructTypeRef), Decoration.Block))) val uniformPointerUniformRef = currentCtx.nextResultId val uniformPointerUniform = @@ -239,7 +231,7 @@ private[cyfra] object SpirvProgramCompiler: nextResultId = currentCtx.nextResultId + 2, uniformVarRefs = currentCtx.uniformVarRefs + (uniform -> uniformVarRef), uniformPointerMap = currentCtx.uniformPointerMap + (uniformStructTypeRef -> uniformPointerUniformRef), - bindingToStructType = currentCtx.bindingToStructType + (binding -> uniformStructTypeRef) + bindingToStructType = currentCtx.bindingToStructType + (binding -> uniformStructTypeRef), ) (newDecorations, newDefinitions, newCtx) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala index 5d613a56..cfc041cf 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GBufferRegion.scala @@ -36,7 +36,7 @@ object GBufferRegion: // noinspection ScalaRedundantCast val steps: Seq[(Allocation => Layout => Layout, LayoutBinding[Layout])] = Seq.unfold(region: GBufferRegion[?, ?]): - case AllocRegion() => None + case AllocRegion() => None case MapRegion(req, f) => Some(((f.asInstanceOf[Allocation => Layout => Layout], req.resAllocBinding.asInstanceOf[LayoutBinding[Layout]]), req)) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala index a686e9ff..9d4d4bb9 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GCodec.scala @@ -19,13 +19,14 @@ trait GCodec[CyfraType <: Value: {FromExpr, Tag}, ScalaType: ClassTag]: object GCodec: - def totalStride(gs: GStructSchema[?]): Int = gs.fields.map: - case (_, fromExpr, t) if t <:< gs.gStructTag => - val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] - totalStride(constructor.schema) - case (_, _, t) => - typeStride(t) - .sum + def totalStride(gs: GStructSchema[?]): Int = gs.fields + .map: + case (_, fromExpr, t) if t <:< gs.gStructTag => + val constructor = fromExpr.asInstanceOf[GStructConstructor[?]] + totalStride(constructor.schema) + case (_, _, t) => + typeStride(t) + .sum given GCodec[Int32, Int]: def toByteBuffer(inBuf: ByteBuffer, chunk: Array[Int]): ByteBuffer = @@ -74,15 +75,14 @@ object GCodec: def fromByteBuffer(outBuf: ByteBuffer, arr: Array[Boolean]): Array[Boolean] = outBuf.get(arr.asInstanceOf[Array[Byte]]).flip() arr - + given [T <: GStruct[T]: {GStructSchema as schema, Tag, ClassTag}]: GCodec[T, T] with def toByteBuffer(inBuf: ByteBuffer, arr: Array[T]): ByteBuffer = inBuf.clear().order(ByteOrder.nativeOrder()) for struct <- arr field <- struct.productIterator - do - writeConstPrimitive(inBuf, field.asInstanceOf[Value]) + do writeConstPrimitive(inBuf, field.asInstanceOf[Value]) inBuf.flip() inBuf def fromByteBuffer(outBuf: ByteBuffer, arr: Array[T]): Array[T] = @@ -104,31 +104,37 @@ object GCodec: arr.appended(newStruct) outBuf.rewind() arr - - private def readPrimitive(buffer: ByteBuffer, value: Tag[_]): Value = + + private def readPrimitive(buffer: ByteBuffer, value: Tag[?]): Value = value.tag match - case t if t =:= summon[Tag[Int]].tag => Int32(ConstInt32(buffer.getInt())) - case t if t =:= summon[Tag[Float]].tag => Float32(ConstFloat32(buffer.getFloat())) - case t if t =:= summon[Tag[Boolean]].tag => GBoolean(ConstGB(buffer.get() != 0)) + case t if t =:= summon[Tag[Int]].tag => Int32(ConstInt32(buffer.getInt())) + case t if t =:= summon[Tag[Float]].tag => Float32(ConstFloat32(buffer.getFloat())) + case t if t =:= summon[Tag[Boolean]].tag => GBoolean(ConstGB(buffer.get() != 0)) case t if t =:= summon[Tag[(Float, Float, Float, Float)]].tag => // todo other tuples - Vec4(ComposeVec4(Float32(ConstFloat32(buffer.getFloat())), Float32(ConstFloat32(buffer.getFloat())), Float32(ConstFloat32(buffer.getFloat())), Float32(ConstFloat32(buffer.getFloat())))) + Vec4( + ComposeVec4( + Float32(ConstFloat32(buffer.getFloat())), + Float32(ConstFloat32(buffer.getFloat())), + Float32(ConstFloat32(buffer.getFloat())), + Float32(ConstFloat32(buffer.getFloat())), + ), + ) case illegal => throw new IllegalArgumentException(s"Unable to deserialize value of type $illegal") private def writeConstPrimitive(buff: ByteBuffer, value: Value): Unit = value.tree match - case c: Const[?] => writePrimitive(buff, c.value) - case compose: ComposeVec[_] => + case c: Const[?] => writePrimitive(buff, c.value) + case compose: ComposeVec[?] => compose.productIterator.foreach: v => - writeConstPrimitive(buff, v.asInstanceOf[Value]) + writeConstPrimitive(buff, v.asInstanceOf[Value]) case illegal => throw new IllegalArgumentException(s"Only constant Cyfra values can be serialized (got $illegal)") private def writePrimitive(buff: ByteBuffer, value: Any): Unit = value match - case i: Int => buff.putInt(i) - case f: Float => buff.putFloat(f) + case i: Int => buff.putInt(i) + case f: Float => buff.putFloat(f) case b: Boolean => buff.put(if b then 1.toByte else 0.toByte) - case t: Tuple => + case t: Tuple => t.productIterator.foreach(writePrimitive(buff, _)) case illegal => throw new IllegalArgumentException(s"Unable to serialize value $illegal of type ${illegal.getClass}") - diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala index 7154e47f..fe111bfd 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala @@ -36,10 +36,10 @@ object GProgram: )(body: L => GIO[?]): GProgram[Params, L] = new GioProgram[Params, L](body, s => layout(using s), dispatch, workgroupSize) - def fromSpirvFile[Params, L <: Layout : {LayoutBinding, LayoutStruct}]( + def fromSpirvFile[Params, L <: Layout: {LayoutBinding, LayoutStruct}]( layout: InitProgramLayout ?=> Params => L, dispatch: (L, Params) => ProgramDispatch, - path: Path + path: Path, ): SpirvProgram[Params, L] = Using.resource(new FileInputStream(path.toFile)): fis => val fc = fis.getChannel diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala index f60c02e3..0cfacd43 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/SpirvProgram.scala @@ -30,17 +30,18 @@ case class SpirvProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}] priv shaderBindings: L => ShaderLayout, ) extends GProgram[Params, L]: - /** - * A hash of the shader code, entry point, workgroup size, and layout bindings. - * Layout and dispatch are not taken into account. - */ + /** A hash of the shader code, entry point, workgroup size, and layout bindings. Layout and dispatch are not taken into account. + */ lazy val shaderHash: (Long, Long) = val md = MessageDigest.getInstance("SHA-256") md.update(code) code.rewind() md.update(entryPoint.getBytes) - md.update(workgroupSize.toList - .flatMap(BigInt(_).toByteArray).toArray) + md.update( + workgroupSize.toList + .flatMap(BigInt(_).toByteArray) + .toArray, + ) val layout = shaderBindings(summon[LayoutStruct[L]].layoutRef) layout.flatten.foreach: binding => md.update(binding.binding.tag.toString.getBytes) @@ -60,7 +61,7 @@ object SpirvProgram: def apply[Params, L <: Layout: {LayoutBinding, LayoutStruct}]( layout: InitProgramLayout ?=> Params => L, dispatch: (L, Params) => ProgramDispatch, - code: ByteBuffer + code: ByteBuffer, ): SpirvProgram[Params, L] = val workgroupSize = (128, 1, 1) // TODO Extract form shader val main = "main" diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala index 0d559284..b124bed6 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/archive/GFunction.scala @@ -22,78 +22,65 @@ import io.computenode.cyfra.core.GCodec.{*, given} import io.computenode.cyfra.dsl.struct.GStruct.Empty case class GFunction[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( - underlying: GProgram[GFunctionParams, GFunctionLayout[G, H, R]] + underlying: GProgram[GFunctionParams, GFunctionLayout[G, H, R]], ): - def run[GS : ClassTag, HS, RS : ClassTag] (input: Array[HS], g: GS)( - using gCodec: GCodec[G, GS], + def run[GS: ClassTag, HS, RS: ClassTag](input: Array[HS], g: GS)(using + gCodec: GCodec[G, GS], hCodec: GCodec[H, HS], rCodec: GCodec[R, RS], - runtime: CyfraRuntime + runtime: CyfraRuntime, ): Array[RS] = - + val inTypeSize = typeStride(Tag.apply[H]) val outTypeSize = typeStride(Tag.apply[R]) val uniformStride = totalStride(summon[GStructSchema[G]]) val params = GFunctionParams(size = input.size) - + val in = BufferUtils.createByteBuffer(inTypeSize * input.size) hCodec.toByteBuffer(in, input) val out = BufferUtils.createByteBuffer(outTypeSize * input.size) val uniform = BufferUtils.createByteBuffer(uniformStride) gCodec.toByteBuffer(uniform, Array(g)) - - GBufferRegion.allocate[GFunctionLayout[G, H, R]] + + GBufferRegion + .allocate[GFunctionLayout[G, H, R]] .map: layout => underlying.execute(params, layout) .runUnsafe( - init = GFunctionLayout( - in = GBuffer[H](in), - out = GBuffer[R](input.size), - uniform = GUniform[G](uniform), - ), - onDone = layout => - layout.out.read(out) + init = GFunctionLayout(in = GBuffer[H](in), out = GBuffer[R](input.size), uniform = GUniform[G](uniform)), + onDone = layout => layout.out.read(out), ) val resultArray = Array.ofDim[RS](input.size) rCodec.fromByteBuffer(out, resultArray) object GFunction: - case class GFunctionParams( - size: Int - ) - - case class GFunctionLayout[G <: GStruct[G], H <: Value, R <: Value]( - in: GBuffer[H], - out: GBuffer[R], - uniform: GUniform[G] - ) extends Layout - - def forEachIndex[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: (G, Int32, GBuffer[H]) => R): GFunction[G, H, R] = - val body = (layout: GFunctionLayout[G, H, R]) => + case class GFunctionParams(size: Int) + + case class GFunctionLayout[G <: GStruct[G], H <: Value, R <: Value](in: GBuffer[H], out: GBuffer[R], uniform: GUniform[G]) extends Layout + + def forEachIndex[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( + fn: (G, Int32, GBuffer[H]) => R, + ): GFunction[G, H, R] = + val body = (layout: GFunctionLayout[G, H, R]) => val g = layout.uniform.read val result = fn(g, GIO.invocationId, layout.in) - for - _ <- layout.out.write(GIO.invocationId, result) + for _ <- layout.out.write(GIO.invocationId, result) yield Empty() val inTypeSize = typeStride(Tag.apply[H]) val outTypeSize = typeStride(Tag.apply[R]) - - GFunction( - underlying = GProgram.apply[GFunctionParams, GFunctionLayout[G, H, R]]( - layout = (p: GFunctionParams) => GFunctionLayout[G, H, R]( - in = GBuffer[H](p.size), - out = GBuffer[R](p.size), - uniform = GUniform[G](), - ), + + GFunction(underlying = + GProgram.apply[GFunctionParams, GFunctionLayout[G, H, R]]( + layout = (p: GFunctionParams) => GFunctionLayout[G, H, R](in = GBuffer[H](p.size), out = GBuffer[R](p.size), uniform = GUniform[G]()), dispatch = (l, p) => StaticDispatch((p.size + 255) / 256, 1, 1), workgroupSize = (256, 1, 1), - )(body) + )(body), ) - + def apply[H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](fn: H => R): GFunction[GStruct.Empty, H, R] = GFunction.forEachIndex[GStruct.Empty, H, R]((g: GStruct.Empty, index: Int32, a: GBuffer[H]) => fn(a.read(index))) - + def from2D[G <: GStruct[G]: {GStructSchema, Tag}, H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}]( width: Int, )(fn: (G, (Int32, Int32), GArray2D[H]) => R): GFunction[G, H, R] = @@ -105,9 +92,5 @@ object GFunction: ) extension [H <: Value: {Tag, FromExpr}, R <: Value: {Tag, FromExpr}](gf: GFunction[GStruct.Empty, H, R]) - def run[HS, RS : ClassTag](input: Array[HS])( - using hCodec: GCodec[H, HS], - rCodec: GCodec[R, RS], - runtime: CyfraRuntime - ): Array[RS] = - gf.run(input, GStruct.Empty()) \ No newline at end of file + def run[HS, RS: ClassTag](input: Array[HS])(using hCodec: GCodec[H, HS], rCodec: GCodec[R, RS], runtime: CyfraRuntime): Array[RS] = + gf.run(input, GStruct.Empty()) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala index 69327f73..1b460121 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/layout/LayoutStruct.scala @@ -77,7 +77,11 @@ object LayoutStruct: case Some(s) => s case None => report.errorAndAbort(s"Cannot summon GStructSchema for type") '{ - UniformRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using ${ tag.asExprOf[Tag[t]] }, ${ fromExpr.asExprOf[FromExpr[t]] }, ${ structSchema }) + UniformRef[t](${ Expr(i) }, ${ tag.asExprOf[Tag[t]] })(using + ${ tag.asExprOf[Tag[t]] }, + ${ fromExpr.asExprOf[FromExpr[t]] }, + ${ structSchema }, + ) } val constructor = sym.primaryConstructor @@ -86,16 +90,8 @@ object LayoutStruct: val typeArgs = tpe.typeArgs val layoutInstance = - if (typeArgs.isEmpty) then - Apply(Select(New(TypeIdent(sym)), constructor), buffers.map(_.asTerm)) - else - Apply( - TypeApply( - Select(New(TypeIdent(sym)), constructor), - typeArgs.map(arg => TypeTree.of(using arg.asType)) - ), - buffers.map(_.asTerm) - ) + if typeArgs.isEmpty then Apply(Select(New(TypeIdent(sym)), constructor), buffers.map(_.asTerm)) + else Apply(TypeApply(Select(New(TypeIdent(sym)), constructor), typeArgs.map(arg => TypeTree.of(using arg.asType))), buffers.map(_.asTerm)) val layoutRef = layoutInstance.asExprOf[T] diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala index 4ffc51c3..dfca871b 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/collections/GArray.scala @@ -10,4 +10,3 @@ import izumi.reflect.Tag case class GArray[T <: Value: {Tag, FromExpr}](underlying: GBuffer[T]): def at(i: Int32)(using Source): T = summon[FromExpr[T]].fromExpr(ReadBuffer(underlying, i)) - diff --git a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala index 0448fcf0..09373068 100644 --- a/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala +++ b/cyfra-dsl/src/main/scala/io/computenode/cyfra/dsl/gio/GIO.scala @@ -29,7 +29,7 @@ object GIO: // TODO repeat that collects results case class Repeat(n: Int32, f: GIO[?]) extends GIO[Empty]: override def underlying: Empty = Empty() - + case class Printf(format: String, args: Value*) extends GIO[Empty]: override def underlying: Empty = Empty() @@ -45,7 +45,7 @@ object GIO: def write[T <: Value](buffer: GBuffer[T], index: Int32, value: T): GIO[Empty] = WriteBuffer(buffer, index, value) - + def printf(format: String, args: Value*): GIO[Empty] = Printf(s"|$format", args*) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala index 2a36c7c2..d298a839 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/RuntimeEnduranceTest.scala @@ -20,7 +20,6 @@ import scala.concurrent.ExecutionContext.Implicits.global import java.util.concurrent.atomic.AtomicInteger import scala.concurrent.{Await, Future} - class RuntimeEnduranceTest extends munit.FunSuite: test("Endurance test for GExecution with multiple programs"): @@ -61,7 +60,7 @@ class RuntimeEnduranceTest extends munit.FunSuite: case class FilterProgramUniform(filterValue: Int32) extends GStruct[FilterProgramUniform] case class FilterProgramLayout(in: GBuffer[Int32], out: GBuffer[GBoolean], params: GUniform[FilterProgramUniform] = GUniform.fromParams) - extends Layout + extends Layout val filterProgram = GProgram[FilterProgramParams, FilterProgramLayout]( layout = params => @@ -174,12 +173,14 @@ class RuntimeEnduranceTest extends munit.FunSuite: ) def runEnduranceTest(nRuns: Int): Unit = - logger.info(s"Starting endurance test with ${nRuns} runs...") + logger.info(s"Starting endurance test with $nRuns runs...") - given runtime: VkCyfraRuntime = VkCyfraRuntime( - spirvToolsRunner = SpirvToolsRunner( + given runtime: VkCyfraRuntime = VkCyfraRuntime(spirvToolsRunner = + SpirvToolsRunner( crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))), - disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/dis.spvdis"))))) + disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/dis.spvdis"))), + ), + ) val bufferSize = 1280 val params = AddProgramParams(bufferSize, addA = 0, addB = 1) @@ -188,8 +189,8 @@ class RuntimeEnduranceTest extends munit.FunSuite: .map: region => execution.execute(params, region) val aInt = new AtomicInteger(0) - val runs = (1 to nRuns).map: - i => Future: + val runs = (1 to nRuns).map: i => + Future: val inBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) val wbbList = inBuffers.map(MemoryUtil.memByteBuffer) val rbbList = List.fill(5)(BufferUtils.createByteBuffer(bufferSize * 4)) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala index 3a69f09f..cca59242 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/SpirvRuntimeEnduranceTest.scala @@ -20,7 +20,6 @@ import scala.concurrent.ExecutionContext.Implicits.global import java.util.concurrent.atomic.AtomicInteger import scala.concurrent.{Await, Future} - class SpirvRuntimeEnduranceTest extends munit.FunSuite: test("Endurance test for GExecution with multiple SPIRV programs loaded from files"): @@ -46,7 +45,7 @@ class SpirvRuntimeEnduranceTest extends munit.FunSuite: args = GUniform(EmitProgramUniform(params.emitN)), ), dispatch = (_, args) => GProgram.StaticDispatch((args.inSize / 128, 1, 1)), - Paths.get(getClass.getResource("/emit.spv").toURI) + Paths.get(getClass.getResource("/emit.spv").toURI), ) // === Filter program === @@ -56,7 +55,7 @@ class SpirvRuntimeEnduranceTest extends munit.FunSuite: case class FilterProgramUniform(filterValue: Int32) extends GStruct[FilterProgramUniform] case class FilterProgramLayout(in: GBuffer[Int32], out: GBuffer[GBoolean], params: GUniform[FilterProgramUniform] = GUniform.fromParams) - extends Layout + extends Layout val filterProgram = GProgram.fromSpirvFile[FilterProgramParams, FilterProgramLayout]( layout = params => @@ -66,7 +65,7 @@ class SpirvRuntimeEnduranceTest extends munit.FunSuite: params = GUniform(FilterProgramUniform(params.filterValue)), ), dispatch = (_, args) => GProgram.StaticDispatch((args.inSize / 128, 1, 1)), - Paths.get(getClass.getResource("/filter.spv").toURI) + Paths.get(getClass.getResource("/filter.spv").toURI), ) // === GExecution === @@ -136,7 +135,7 @@ class SpirvRuntimeEnduranceTest extends munit.FunSuite: u2 = GUniform(AddProgramUniform(params.addB)), ), dispatch = (layout, args) => GProgram.StaticDispatch((args.bufferSize / 128, 1, 1)), - Paths.get(getClass.getResource("/addOne.spv").toURI) + Paths.get(getClass.getResource("/addOne.spv").toURI), ) def swap(l: AddProgramLayout): AddProgramLayout = @@ -155,12 +154,14 @@ class SpirvRuntimeEnduranceTest extends munit.FunSuite: ) def runEnduranceTest(nRuns: Int): Unit = - logger.info(s"Starting endurance test with ${nRuns} runs...") + logger.info(s"Starting endurance test with $nRuns runs...") - given runtime: VkCyfraRuntime = VkCyfraRuntime( - spirvToolsRunner = SpirvToolsRunner( + given runtime: VkCyfraRuntime = VkCyfraRuntime(spirvToolsRunner = + SpirvToolsRunner( crossCompilation = SpirvCross.Enable(toolOutput = ToFile(Paths.get("output/optimized.glsl"))), - disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/dis.spvdis"))))) + disassembler = SpirvDisassembler.Enable(toolOutput = ToFile(Paths.get("output/dis.spvdis"))), + ), + ) val bufferSize = 1280 val params = AddProgramParams(bufferSize, addA = 0, addB = 1) @@ -169,8 +170,8 @@ class SpirvRuntimeEnduranceTest extends munit.FunSuite: .map: region => execution.execute(params, region) val aInt = new AtomicInteger(0) - val runs = (1 to nRuns).map: - i => Future: + val runs = (1 to nRuns).map: i => + Future: val inBuffers = List.fill(5)(BufferUtils.createIntBuffer(bufferSize)) val wbbList = inBuffers.map(MemoryUtil.memByteBuffer) val rbbList = List.fill(5)(BufferUtils.createByteBuffer(bufferSize * 4)) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala index 26ab573c..5a54d8ee 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/ArithmeticsE2eTest.scala @@ -10,7 +10,7 @@ import io.computenode.cyfra.core.GCodec.{*, given} class ArithmeticsE2eTest extends munit.FunSuite: given CyfraRuntime = VkCyfraRuntime() - + test("Float32 arithmetics"): val gf: GFunction[GStruct.Empty, Float32, Float32] = GFunction: fl => (fl + 1.2f) * (fl - 3.4f) / 5.6f diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala index 057ecddc..4cbc71d8 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/FunctionsE2eTest.scala @@ -9,7 +9,7 @@ import io.computenode.cyfra.core.GCodec.{*, given} class FunctionsE2eTest extends munit.FunSuite: given CyfraRuntime = VkCyfraRuntime() - + test("Functions"): val gf: GFunction[GStruct.Empty, Float32, Float32] = GFunction: f => val res1 = pow(sqrt(exp(sin(cos(tan(f))))), 2f) diff --git a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala index 9844c7f9..f63f077e 100644 --- a/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala +++ b/cyfra-e2e-test/src/test/scala/io/computenode/cyfra/e2e/dsl/GseqE2eTest.scala @@ -10,7 +10,7 @@ import io.computenode.cyfra.core.GCodec.{*, given} class GseqE2eTest extends munit.FunSuite: given CyfraRuntime = VkCyfraRuntime() - + test("GSeq gen limit map fold"): val gf: GFunction[GStruct.Empty, Float32, Float32] = GFunction: f => GSeq diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala index 8a77c384..3ad661dc 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/ImageRtRenderer.scala @@ -17,7 +17,7 @@ import java.nio.file.Path class ImageRtRenderer(params: ImageRtRenderer.Parameters) extends RtRenderer(params): given CyfraRuntime = VkCyfraRuntime() - + def renderToFile(scene: Scene, destinationPath: Path): Unit = val images = render(scene) for image <- images do ImageUtility.renderToImage(image, params.width, params.height, destinationPath) diff --git a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala index ee6e77ac..19ee393b 100644 --- a/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala +++ b/cyfra-foton/src/main/scala/io/computenode/cyfra/foton/rt/animation/AnimationRtRenderer.scala @@ -14,7 +14,7 @@ import io.computenode.cyfra.runtime.VkCyfraRuntime class AnimationRtRenderer(params: AnimationRtRenderer.Parameters) extends RtRenderer(params) with AnimationRenderer[AnimatedScene, AnimationRtRenderer.RenderFn](params): - + given CyfraRuntime = VkCyfraRuntime() protected def renderFrame(scene: AnimatedScene, time: Float32, fn: GFunction[RaytracingIteration, Vec4[Float32], Vec4[Float32]]): Array[fRGBA] = @@ -24,7 +24,6 @@ class AnimationRtRenderer(params: AnimationRtRenderer.Parameters) case (mem, render) => val result: Array[fRGBA] = fn.run(mem, RaytracingIteration(render, time)) (result, render + 1) - .map(_._1) .last diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index b8926666..59001acd 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -9,7 +9,15 @@ import io.computenode.cyfra.dsl.Value import io.computenode.cyfra.dsl.Value.FromExpr import io.computenode.cyfra.dsl.binding.{GBinding, GBuffer, GUniform} import io.computenode.cyfra.dsl.struct.{GStruct, GStructSchema} -import io.computenode.cyfra.runtime.ExecutionHandler.{BindingLogicError, Dispatch, DispatchType, ExecutionBinding, ExecutionStep, PipelineBarrier, ShaderCall} +import io.computenode.cyfra.runtime.ExecutionHandler.{ + BindingLogicError, + Dispatch, + DispatchType, + ExecutionBinding, + ExecutionStep, + PipelineBarrier, + ShaderCall, +} import io.computenode.cyfra.runtime.ExecutionHandler.DispatchType.* import io.computenode.cyfra.runtime.ExecutionHandler.ExecutionBinding.{BufferBinding, UniformBinding} import io.computenode.cyfra.utility.Utility.timed @@ -150,7 +158,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte Binding(resolved, operation) val nextDispatch = dispatch match - case x: DispatchType.Direct => x + case x: DispatchType.Direct => x case DispatchType.Indirect(buffer, offset) => val base = bindingsAcc.getOrElse(buffer, mutable.Buffer.empty).toSeq val extras = callInits.getOrElse(buffer, Seq.empty) @@ -161,8 +169,10 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte ShaderCall(pipeline, nextLayout, nextDispatch, Map.empty) val mapper = summon[LayoutBinding[RL]] - val rlBindings = mapper.toBindings(rl).map: b => - finalBindingForRl.getOrElse(b, interpretBinding(b, bindingsAcc.getOrElse(b, mutable.Buffer.empty).toSeq)) + val rlBindings = mapper + .toBindings(rl) + .map: b => + finalBindingForRl.getOrElse(b, interpretBinding(b, bindingsAcc.getOrElse(b, mutable.Buffer.empty).toSeq)) val res = mapper.fromBindings(rlBindings) (res, nextSteps) @@ -250,17 +260,13 @@ object ExecutionHandler: pipeline: ComputePipeline, layout: ShaderLayout, dispatch: DispatchType, - callInits: Map[GBinding[?], Seq[GBinding[?]]] // per-program contributions + callInits: Map[GBinding[?], Seq[GBinding[?]]], // per-program contributions ) sealed trait ExecutionStep - case class Dispatch( - pipeline: ComputePipeline, - layout: ShaderLayout, - descriptorSets: Seq[DescriptorSet], - dispatch: DispatchType - ) extends ExecutionStep + case class Dispatch(pipeline: ComputePipeline, layout: ShaderLayout, descriptorSets: Seq[DescriptorSet], dispatch: DispatchType) + extends ExecutionStep case object PipelineBarrier extends ExecutionStep sealed trait DispatchType @@ -275,12 +281,10 @@ object ExecutionHandler: def apply[T <: Value: {FromExpr as fe, Tag as t}](binding: GBinding[T]): ExecutionBinding[T] & GBinding[T] = binding match // todo types are a mess here - case u: GUniform[GStruct[?]] => new UniformBinding[GStruct[?]](using - fe.asInstanceOf[FromExpr[GStruct[?]]], - t.asInstanceOf[Tag[GStruct[?]]], - u.schema.asInstanceOf - ).asInstanceOf[UniformBinding[T]] - case _: GBuffer[T] => new BufferBinding() + case u: GUniform[GStruct[?]] => + new UniformBinding[GStruct[?]](using fe.asInstanceOf[FromExpr[GStruct[?]]], t.asInstanceOf[Tag[GStruct[?]]], u.schema.asInstanceOf) + .asInstanceOf[UniformBinding[T]] + case _: GBuffer[T] => new BufferBinding() case class BindingLogicError(bindings: Seq[GBinding[?]], message: String) extends RuntimeException(s"Error in binding logic for $bindings: $message") object BindingLogicError: diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala index 4a3d3024..6f1dd91a 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkAllocation.scala @@ -72,7 +72,7 @@ class VkAllocation(commandPool: CommandPool, executionHandler: ExecutionHandler) def apply[T <: Value: {Tag, FromExpr}](length: Int): GBuffer[T] = VkBuffer[T](length).tap(bindings += _) - def apply[T <: Value : {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] = + def apply[T <: Value: {Tag, FromExpr}](buff: ByteBuffer): GBuffer[T] = val sizeOfT = typeStride(summon[Tag[T]]) val length = buff.capacity() / sizeOfT if buff.capacity() % sizeOfT != 0 then diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala index 17b90fab..0d3ecd07 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala @@ -23,13 +23,15 @@ class VkCyfraRuntime(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()) ex val spirvProgram: SpirvProgram[Params, L] = program match case p: GioProgram[Params, L] if gProgramCache.contains(p) => gProgramCache(p).asInstanceOf - case p: GioProgram[Params, L] => compile(p) + case p: GioProgram[Params, L] => compile(p) case p: SpirvProgram[Params, L] => p - case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") + case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") shaderCache.getOrElseUpdate(spirvProgram.shaderHash, VkShader(spirvProgram)).asInstanceOf[VkShader[L]] - private def compile[Params, L <: Layout: {LayoutBinding as lbinding, LayoutStruct as lstruct}](program: GioProgram[Params, L]): SpirvProgram[Params, L] = + private def compile[Params, L <: Layout: {LayoutBinding as lbinding, LayoutStruct as lstruct}]( + program: GioProgram[Params, L], + ): SpirvProgram[Params, L] = val GioProgram(_, layout, dispatch, _) = program val bindings = lbinding.toBindings(lstruct.layoutRef).toList val compiled = DSLCompiler.compile(program.body(summon[LayoutStruct[L]].layoutRef), bindings) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala index d2209fe1..492266e9 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkShader.scala @@ -17,7 +17,7 @@ case class VkShader[L](underlying: ComputePipeline, shaderBindings: L => ShaderL object VkShader: def apply[P, L <: Layout: {LayoutBinding, LayoutStruct}](program: SpirvProgram[P, L])(using Device): VkShader[L] = - val SpirvProgram(layout, dispatch, _workgroupSize, code, entryPoint, shaderBindings) = program + val SpirvProgram(layout, dispatch, _workgroupSize, code, entryPoint, shaderBindings) = program val shaderLayout = shaderBindings(summon[LayoutStruct[L]].layoutRef) val sets = shaderLayout.map: set => @@ -31,4 +31,3 @@ object VkShader: val pipeline = ComputePipeline(code, entryPoint, LayoutInfo(sets)) VkShader(pipeline, shaderBindings) - diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala index 991fda38..4042b629 100644 --- a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvCross.scala @@ -19,7 +19,7 @@ object SpirvCross extends SpirvTool("spirv-cross"): None case Right(crossCompiledCode) => toolOutput match - case Ignore => + case Ignore => case toFile @ SpirvTool.ToFile(_, _) => toFile.write(crossCompiledCode) logger.debug(s"Saved cross compiled shader code in ${toFile.filePath}.") diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala index 67730961..4579db8a 100644 --- a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvDisassembler.scala @@ -18,7 +18,7 @@ object SpirvDisassembler extends SpirvTool("spirv-dis"): None case Right(disassembledShader) => toolOutput match - case Ignore => + case Ignore => case toFile @ SpirvTool.ToFile(_, _) => toFile.write(disassembledShader) logger.debug(s"Saved disassembled shader code in ${toFile.filePath}.") diff --git a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala index 509e763c..922d5346 100644 --- a/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala +++ b/cyfra-spirv-tools/src/main/scala/io/computenode/cyfra/spirvtools/SpirvOptimizer.scala @@ -19,7 +19,7 @@ object SpirvOptimizer extends SpirvTool("spirv-opt"): None case Right(optimizedShaderCode) => toolOutput match - case SpirvTool.Ignore => + case SpirvTool.Ignore => case toFile @ SpirvTool.ToFile(_, _) => toFile.write(optimizedShaderCode) logger.debug(s"Saved optimized shader code in ${toFile.filePath}.") diff --git a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala index 7664a3c6..630fa924 100644 --- a/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala +++ b/cyfra-vulkan/src/main/scala/io/computenode/cyfra/vulkan/command/Fence.scala @@ -19,7 +19,7 @@ private[cyfra] class Fence(flags: Int = 0)(using device: Device) extends VulkanO val pFence = stack.callocLong(1) check(vkCreateFence(device.get, fenceInfo, null, pFence), "Failed to create fence") - pFence.get() + pFence.get(), ) override def close(): Unit = From 1f7a5267bd9d27e8719ef754f000516e91ce5f0a Mon Sep 17 00:00:00 2001 From: MarconZet <25779550+MarconZet@users.noreply.github.com> Date: Sun, 21 Sep 2025 19:39:17 +0200 Subject: [PATCH 57/59] fixed filter^ --- .../io/computenode/cyfra/core/GProgram.scala | 2 +- .../computenode/cyfra/fs2interop/GPipe.scala | 15 +++-- .../cyfra/runtime/ExecutionHandler.scala | 64 ++++++------------- 3 files changed, 28 insertions(+), 53 deletions(-) diff --git a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala index fe111bfd..ffd87858 100644 --- a/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala +++ b/cyfra-core/src/main/scala/io/computenode/cyfra/core/GProgram.scala @@ -20,7 +20,7 @@ trait GProgram[Params, L <: Layout: {LayoutBinding, LayoutStruct}] extends GExec val layout: InitProgramLayout => Params => L val dispatch: (L, Params) => ProgramDispatch val workgroupSize: WorkDimensions - def layoutStruct = summon[LayoutStruct[L]] + def layoutStruct: LayoutStruct[L] = summon[LayoutStruct[L]] object GProgram: type WorkDimensions = (Int, Int, Int) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index 90c76906..a111a7a8 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -87,10 +87,11 @@ object GPipe: // Prefix sum (inclusive), upsweep/downsweep case class ScanParams(inSize: Int, intervalSize: Int) case class ScanArgs(intervalSize: Int32) extends GStruct[ScanArgs] - case class ScanLayout(ints: GBuffer[Int32], intervalSize: GUniform[ScanArgs] = GUniform.fromParams) extends Layout + case class ScanLayout(ints: GBuffer[Int32]) extends Layout + case class ScanProgramLayout(ints: GBuffer[Int32], intervalSize: GUniform[ScanArgs] = GUniform.fromParams) extends Layout - val upsweep = GProgram[ScanParams, ScanLayout]( - layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), + val upsweep = GProgram[ScanParams, ScanProgramLayout]( + layout = params => ScanProgramLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize.toFloat / params.intervalSize / 256).toInt, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read @@ -105,8 +106,8 @@ object GPipe: for _ <- GIO.write[Int32](layout.ints, end, newValue) yield Empty() - val downsweep = GProgram[ScanParams, ScanLayout]( - layout = params => ScanLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), + val downsweep = GProgram[ScanParams, ScanProgramLayout]( + layout = params => ScanProgramLayout(ints = GBuffer[Int32](params.inSize), intervalSize = GUniform(ScanArgs(params.intervalSize))), dispatch = (layout, params) => GProgram.StaticDispatch((Math.ceil(params.inSize.toFloat / params.intervalSize / 256).toInt, 1, 1)), ): layout => val ScanArgs(size) = layout.intervalSize.read @@ -129,7 +130,7 @@ object GPipe: ): GExecution[ScanParams, ScanLayout, ScanLayout] = if intervalSize > inSize then exec else - val newExec = exec.addProgram(upsweep)(params => ScanParams(inSize, intervalSize), layout => layout) + val newExec = exec.addProgram(upsweep)(params => ScanParams(inSize, intervalSize), layout => ScanProgramLayout(layout.ints)) upsweepPhases(newExec, inSize, intervalSize * 2) @annotation.tailrec @@ -140,7 +141,7 @@ object GPipe: ): GExecution[ScanParams, ScanLayout, ScanLayout] = if intervalSize < 2 then exec else - val newExec = exec.addProgram(downsweep)(params => ScanParams(inSize, intervalSize), layout => layout) + val newExec = exec.addProgram(downsweep)(params => ScanParams(inSize, intervalSize), layout => ScanProgramLayout(layout.ints)) downsweepPhases(newExec, inSize, intervalSize / 2) val initExec = GExecution[ScanParams, ScanLayout]() // no program diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala index 59001acd..7f2c6cff 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/ExecutionHandler.scala @@ -46,7 +46,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte val (result, shaderCalls) = interpret(execution, params, layout) val descriptorSets = shaderCalls.map: - case ShaderCall(pipeline, layout, _, _) => + case ShaderCall(pipeline, layout, _) => pipeline.pipelineLayout.sets .map(dsManager.allocate) .zip(layout) @@ -58,7 +58,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte val dispatches: Seq[Dispatch] = shaderCalls .zip(descriptorSets) .map: - case (ShaderCall(pipeline, layout, dispatch, _), sets) => + case (ShaderCall(pipeline, layout, dispatch), sets) => Dispatch(pipeline, layout, sets, dispatch) val (executeSteps, _) = dispatches.foldLeft((Seq.empty[ExecutionStep], Set.empty[GBinding[?]])): @@ -94,7 +94,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte case x: ExecutionBinding[?] => x case x: GBinding[?] => val e = ExecutionBinding(x)(using x.fromExpr, x.tag) - bindingsAcc.put(e, mutable.Buffer(x)) // store only base contribution here + bindingsAcc.put(e, mutable.Buffer(x)) e mapper.fromBindings(res) @@ -128,53 +128,33 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte val layoutInit = val initProgram: InitProgramLayout = summon[VkAllocation].getInitProgramLayout program.layout(initProgram)(params) - - val callInits: Map[GBinding[?], Seq[GBinding[?]]] = - lb - .toBindings(layout) - .zip(lb.toBindings(layoutInit)) - .groupMap(_._1)(_._2) - + lb.toBindings(layout) + .zip(lb.toBindings(layoutInit)) + .foreach: + case (binding, initBinding) => + bindingsAcc(binding).append(initBinding) val dispatch = program.dispatch(layout, params) match case GProgram.DynamicDispatch(buffer, offset) => DispatchType.Indirect(buffer, offset) case GProgram.StaticDispatch(size) => DispatchType.Direct(size._1, size._2, size._3) // noinspection ScalaRedundantCast - (layout.asInstanceOf[RL], Seq(ShaderCall(shader.underlying, shader.shaderBindings(layout), dispatch, callInits))) + (layout.asInstanceOf[RL], Seq(ShaderCall(shader.underlying, shader.shaderBindings(layout), dispatch))) case _ => ??? val (rl, steps) = interpretImpl(execution, params, mockBindings(layout)) - - val finalBindingForRl: mutable.Map[GBinding[?], GBinding[?]] = mutable.Map.empty + val bingingToVk = bindingsAcc.map(x => (x._1, interpretBinding(x._1, x._2.toSeq))) val nextSteps = steps.map: - case ShaderCall(pipeline, layout, dispatch, callInits) => + case ShaderCall(pipeline, layout, dispatch) => val nextLayout = layout.map: _.map: - case Binding(binding, operation) => - val base = bindingsAcc.getOrElse(binding, mutable.Buffer.empty).toSeq - val extras = callInits.getOrElse(binding, Seq.empty) - val resolved = interpretBinding(binding, base ++ extras) - finalBindingForRl.update(binding, resolved) - Binding(resolved, operation) - + case Binding(binding, operation) => Binding(bingingToVk(binding), operation) val nextDispatch = dispatch match - case x: DispatchType.Direct => x - case DispatchType.Indirect(buffer, offset) => - val base = bindingsAcc.getOrElse(buffer, mutable.Buffer.empty).toSeq - val extras = callInits.getOrElse(buffer, Seq.empty) - val resolved = interpretBinding(buffer, base ++ extras) - finalBindingForRl.update(buffer, resolved) - DispatchType.Indirect(resolved, offset) - - ShaderCall(pipeline, nextLayout, nextDispatch, Map.empty) + case x: Direct => x + case Indirect(buffer, offset) => Indirect(bingingToVk(buffer), offset) + ShaderCall(pipeline, nextLayout, nextDispatch) val mapper = summon[LayoutBinding[RL]] - val rlBindings = mapper - .toBindings(rl) - .map: b => - finalBindingForRl.getOrElse(b, interpretBinding(b, bindingsAcc.getOrElse(b, mutable.Buffer.empty).toSeq)) - val res = mapper.fromBindings(rlBindings) - + val res = mapper.fromBindings(mapper.toBindings(rl).map(bingingToVk.apply)) (res, nextSteps) private def interpretBinding(binding: GBinding[?], bindings: Seq[GBinding[?]])(using VkAllocation): GBinding[?] = @@ -207,7 +187,7 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte case _: GUniform.ParamUniform[?] => false case x => throw BindingLogicError(x, "Unsupported binding type") if allocations.size > 1 then throw BindingLogicError(allocations, "Multiple allocations for uniform") - allocations.headOption.getOrElse(throw new IllegalStateException("Uniform never allocated")) + allocations.headOption.getOrElse(throw new BindingLogicError(Seq(), "Uniform never allocated")) case x => throw new IllegalArgumentException(s"Binding of type ${x.getClass.getName} should not be here") private def recordCommandBuffer(steps: Seq[ExecutionStep]): VkCommandBuffer = pushStack: stack => @@ -256,19 +236,13 @@ class ExecutionHandler(runtime: VkCyfraRuntime, threadContext: VulkanThreadConte .distinct object ExecutionHandler: - case class ShaderCall( - pipeline: ComputePipeline, - layout: ShaderLayout, - dispatch: DispatchType, - callInits: Map[GBinding[?], Seq[GBinding[?]]], // per-program contributions - ) + case class ShaderCall(pipeline: ComputePipeline, layout: ShaderLayout, dispatch: DispatchType) sealed trait ExecutionStep - case class Dispatch(pipeline: ComputePipeline, layout: ShaderLayout, descriptorSets: Seq[DescriptorSet], dispatch: DispatchType) extends ExecutionStep - case object PipelineBarrier extends ExecutionStep + sealed trait DispatchType object DispatchType: case class Direct(x: Int, y: Int, z: Int) extends DispatchType From 76ff1ebb71d72b6eff6ddb804dc6bcb1e37c5ee9 Mon Sep 17 00:00:00 2001 From: Szymon Date: Sun, 19 Oct 2025 18:16:52 +0200 Subject: [PATCH 58/59] Fix cache --- .../src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala | 1 - .../scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala index a111a7a8..0aef22d3 100644 --- a/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala +++ b/cyfra-fs2/src/main/scala/io/computenode/cyfra/fs2interop/GPipe.scala @@ -219,5 +219,4 @@ object GPipe: ) val filteredN = filteredCount.getInt(0) val arr = bridge.fromByteBuffer(compactBuf, new Array[S](filteredN)) - println(arr) Stream.emits(arr) diff --git a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala index 0d3ecd07..2e96e221 100644 --- a/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala +++ b/cyfra-runtime/src/main/scala/io/computenode/cyfra/runtime/VkCyfraRuntime.scala @@ -22,11 +22,12 @@ class VkCyfraRuntime(spirvToolsRunner: SpirvToolsRunner = SpirvToolsRunner()) ex val spirvProgram: SpirvProgram[Params, L] = program match case p: GioProgram[Params, L] if gProgramCache.contains(p) => - gProgramCache(p).asInstanceOf + gProgramCache(p).asInstanceOf[SpirvProgram[Params, L]] case p: GioProgram[Params, L] => compile(p) case p: SpirvProgram[Params, L] => p case _ => throw new IllegalArgumentException(s"Unsupported program type: ${program.getClass.getName}") + gProgramCache.update(program, spirvProgram) shaderCache.getOrElseUpdate(spirvProgram.shaderHash, VkShader(spirvProgram)).asInstanceOf[VkShader[L]] private def compile[Params, L <: Layout: {LayoutBinding as lbinding, LayoutStruct as lstruct}]( From df5ed99e2bd780cd8d25be025b0d97454f3fe3cc Mon Sep 17 00:00:00 2001 From: spamegg Date: Tue, 11 Nov 2025 16:55:35 +0300 Subject: [PATCH 59/59] fix compile errors (tests are still broken) --- .../cyfra/interpreter/Interpreter.scala | 2 +- .../cyfra/interpreter/Simulate.scala | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala index 52e2eaf2..6b42d8b3 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Interpreter.scala @@ -55,7 +55,7 @@ object Interpreter: // can different invocations run different numbers of GIOs? val newSc = Simulate.sim(n, sc) val repeat = newSc.results.values.head.asInstanceOf[Int] - val newGios = (0 until repeat).map(i => f(i)).toList + val newGios = (0 until repeat).map(i => f).toList interpretMany(newGios ::: tail, newSc) case head :: tail => interpretMany(tail, interpretOne(head, sc)) case Nil => sc diff --git a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala index baf60707..627267d6 100644 --- a/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala +++ b/cyfra-interpreter/src/main/scala/io/computenode/cyfra/interpreter/Simulate.scala @@ -2,7 +2,7 @@ package io.computenode.cyfra.interpreter import io.computenode.cyfra.dsl.{*, given} import binding.*, macros.FnCall.FnIdentifier, control.Scope -import collections.*, GArray.GArrayElem, GSeq.{CurrentElem, AggregateElem, FoldSeq} +import collections.*, GSeq.{CurrentElem, AggregateElem, FoldSeq} import struct.*, GStruct.{ComposeStruct, GetField} import io.computenode.cyfra.spirv.BlockBuilder.buildBlock @@ -67,12 +67,12 @@ object Simulate: case FunctionCall(fn, body, args) => ??? // simFunc(fn, simScope(body), args.map(simValue)) case InvocationId => simInvocId(records) case Pass(value) => ??? - case Dynamic(source) => ??? - case e: GArrayElem[?] => simGArrayElem(e) - case e: FoldSeq[?, ?] => simFoldSeq(e) - case e: ComposeStruct[?] => simComposeStruct(e) - case e: GetField[?, ?] => simGetField(e) - case _ => throw IllegalArgumentException("sim: wrong argument") + // case Dynamic(source) => ??? + // case e: GArrayElem[?] => simGArrayElem(e) + case e: FoldSeq[?, ?] => simFoldSeq(e) + case e: ComposeStruct[?] => simComposeStruct(e) + case e: GetField[?, ?] => simGetField(e) + case _ => throw IllegalArgumentException("sim: wrong argument") private def simPhantom(e: PhantomExpression[?])(using Records): Results = e match case CurrentElem(tid: Int) => ??? @@ -212,8 +212,8 @@ object Simulate: invocId -> record.addRead(ReadUni(e.treeid, uniform, readValue)) (newResults, newRecords) - private def simGArrayElem(gElem: GArrayElem[?]): Results = gElem match - case GArrayElem(index, i) => ??? + // private def simGArrayElem(gElem: GArrayElem[?]): Results = gElem match + // case GArrayElem(index, i) => ??? private def simFoldSeq(seq: FoldSeq[?, ?]): Results = seq match case FoldSeq(zero, fn, seq) => ???

    sWZItRWoEq1{L+>-1j_ZT`2J}}-qTAFbB z{cgH;5~O$;BtaVi^J5^kYp^OY+Z7yMv`Y*3i~a(=+$c2GB28F3ir|`w$R{?qCeLxw zQ8S(DR3g~BkwpE<`-t}_)w5v|@a{PC{xkqMYkmg8oD%RKOVE7gh@z zT#id2CR2s3bAT6P?THQ8a#~xTQ2jOVIlF4k4oMc)#aJqYxX#J|IuP8W0g4shRoHmh zMuRO((IqM+Wkyr}#!{h`Jv1C=e#`(W!HEU$goL7jtdcidY9vArG|BEqE7h1lgDt@P zsfRy{zgC8s+ixAOGD^*bm^b0!MVzcveEhwEeE?kg0gW@zS;KVqocWD|gzi*auCYwP zLCc7@FE5>gZrG#~_ zgA2XO9BzNHmlfF8v{WCeZ>_2GMa%i;YyCuMEI)t#<~R}xs-@efjJ%{|Ys=D+un^U- z(iMA?h7TEOEhUu=j3p4@b~tQ`3F&~Ze!ye;D>0XD`X1??P*ioP^L5UUy8R;*(5~dWcA>ZFX1y0|KC9q7WpAaejnnfyM_yB`v zOu6zYHDl=j=M6T>78rtXbz_m<@ioi8{Fbe11_ zbXHRH@o8PRzh5a?u{tpM@frv5{|n2q9i|AXa0ThwXBeB9imG?sAmIK99CHm* zUq1>`mFxu{E=P`!b}81yXP#%^*1wBZc3dVZKp{Kw{bx7qP}=4jHl7x!x%yFZDL}f! zC{YwsG88yu(@Uhc+rpW%J#yEiry#N$oRY3@D0b)86v^f|nK;5jquY2h5DHCIy3wz} zohoBpPTb4~M@5ay>sYft;@MKZFWT>j>#?-QoN&90q}mAQeWZH6Y~p z%mSVVA|D@~_`BA*g;gqFY7HUgHumJarfKng)-gG=E*i;U#Tyfs!t2|E>(w1N`6w~b zCu?WbxGMSxV4sNcm}wQWR4Z61{@s{mD<5nL;#UnChTS!K>eHSq&x!snKB&M?dKy%U z%9S%K(Q<7ZPq`eu@fu<ZWyrvEgdIpYNWR=&v)7}T)XReoj00VjQ>^80JW=_xcYfl~nix03O! zHtB^0jTBMLg`JzRJI_oDgxRb?zcYF@EhoO9{5pE61pR6c|E~`;3);lU{D(c6CNx>s zIzaR;v+^%mcxNyo;I3E)N4`4Qmx+Y|YJ!;7#4U7301dl1ZXs$xA2PGH03qYq48^3&5q0_bpFEL^|PMZ1)~aV z&EZKw?fug0X!5)FufKpmeCp3WIhPXXcgGP(bw37U7C!}(e*-;%FWu;l$NhJjuW?pM zb>}P6j#&mX1zoukZNBz;Q74w$xjS1}MYHVjUg}`7rqJ$dn|K>v>|26?7;L|-f z9^%EZd4u3erl2fi(wcv`%z&zn0E+YH_9Y0H0ho&GaRUo6+F&aF>W{bxQp>pU`H$Xh z9~>xRR{7t5UJQ3*W~HAd3t&EYJsTF&dAay(!U9Nak)zvAXZC-0A$djR` z{dJODNG4g+4mFK9zTvG*rX*RA*9QCqple9tvFoymqHE z$yrk|x{h}p5NMT{k?q5wtTlt5sm+32c#Bx7Dl^)Rv!}sVWT0yvlIX+`Kq6_+eRIBC zqEr985fR`Fji{O01|JJl2S3#2m~W;&lka~P-8^6_5hnax9&AK$9Im~&7!PipWhV$U zd3YVJz)XKFb~EkAqi@?gYk_>5FDcmpmuJ>Dgi++cH4#35PdtYe6ZubAB4Sv@*lxVK zx*XQ?r;z}X+vyR|Sl@OH2{?kx{Gg1)cd63j2_Y6oD5op3@1=!F_;P=>32&z^_CBEr z)3%P3nnojdX5M@`iJJyF_C&6ehWP zkSN_{*;9CarSqGFOfd(7iBDO;AC-O-@oxvH8W;_!WrP#@0vv?MQ6#?*L{zJ5;O$>Y zDFf3i-vrkAY?cnw1ob^~uVDhm41crhSL;is?yzoV$*~sMK4S89Z7#HJp7xa&fy{MtwR|l~Q_i@7= zkSH1`lRnt2SM01%-JLQnABK0;qC@>pf<@xBZ{ic)Om<$UmKxvw+%NU7M7MHdjtt&D z3~1#{1@n+y8%auxxDdO@v0`GNRd|3&z!KKR6V90d#-n67mot{Af%#J0FwE|_E+e6X z2hG*&OuP2`UEJH_=bDv5K{#oNn2o*-uC5!W!j21TWA9~Nn1IddfY#Ehs3!Fe;kElZ z>-Xr#V}O+{dpHX%<*+<;}wJujGDIq7nIWCDbH9az4k+TsYEQA44_DPG~vcNf>w@nGF1i zCJ<)#wjpL_cJS^^BvVnv_R&h?*LQbV8A(!?@gJj4$V}I%I&RUo@X$}#R~n42H_F;k ztAkj6ldOoW*YsY5a6tXZQBAgM)5Oxvx~;Hkl^%jGD7cdns8xpy{AJPl`^!uIF~q2{ z1NU5P8ar#S@1o%`zJ}k5D3i}GU1`mM+EFxhKc-)>@Wj_zaA~G3y9k%c__YaK92|b> zK2v(oN&7YOCNbxuyzyV#mDH&NGlKoz`QN4dlT1$KW^Mtj;b%%?u6CrMDW+O3DtJ?z zkBO2XGq|hlSU5(D#X3i7qfq6NXtct{R zB|c4}1a(r}lXscBvn}bGsuv5u9RaPFZ#Kp7A%qcLG<#31P)`0QWidC<8hBin_$X(^ z^k#b-_ktKW+og0?KXje6h$mNG=_{ehOB~VVb9LE)MXH*OU2n`KsTvzq#!m!y4;rFu z5orz=L6Fj)agVGFGAOo?_H zG(g^^ElGqvef09UgygoWFwR=UPIP=~ed9adP$dlmNHl(P z@=8%fhTa>#fMRVvc5Zk0N{iGZI<0Y<4Z2f;ei-1l7!6JZk)#u90H_;KCMKE#}D=KY4qP)CY0aV1s`y1Fx~1`4pe+MIT&bl%{_`Ln950Ju~U^=I{q`8 zxNO_bFUH^7pS13kezcj2GWT-GUmkgM@Se-h&o?DB(J|`0a<*3*S3MkO+*%1%I)G?q zl4*hogE6F1`X`CFCq#_)2@UKYkRt*_^NjE&n_D)3I3}=Faz>uwn|;sBdr#!}B>&l3 zkk7BzlW_>of1f%|e2~YvZR8v4tjv=KX+*fehKm=fD95iS@KSi#K!f1+Ezf-UX2})@zv!Yzi(3yVv-fQp{0t$U#=*N~xq;%*T&aMK$5QKu?5~ z7ya8Rla{}pSoQFogEpb06gUFpecdyQ2+Vz)4#{TqI<02|_hy~Ca?9u#Md6TJOlWpC z$c>!LoL-<~a#jaWZXw_Qar+V!7QH3!21l4rnBx7GM$r1YR9|yL--#AC9X`{tJ%;PA z#VAMVHJP{b^5Ykel_$d-q;`eJ2Qv%QGoO}Cs7*4a-(qeA)}0#BkZ2iA=Zk8yN9_lf z;cr-)d+~LjQDa>Ihk6pg0^Up7#~4jQ@*+8D5${bZdP1rXLzNLT!>4Og^ihHK-fJi) zwtn!%#%L%Z66d%-KgR61FNOlcWJ)CjI447wu9#n+S*(Q3iCjv`Aj7O@o-Mt&l~_~O z(cX2}+j`DqQI9Og{;JS|CwuiHVKI3-+kdR&Yk!$o9@;=ni7>o@B4FuYe)=H;7Yp_< z_$8-)%+~G0RK5Dx29so-`vEGyu7`R4`ORA?|E6KppD-|&u!-t9xI1}PmK0y zC#u!eBuRjVot8hh$G2DQH>#el_Z*=~nYJ62G>>1FK$F$5x+i772f?SvOR{y6T|^+~ zRs2st5MK1ifVuKRPuf$#zz__uPdBWepqSeBqfeOU7fcBurYc{%ue*S1=xrXVR7q-2 zEPk_Ux0yC{_sAJPklx-!Im}xD-qtvr4*@@j0ck4;vL>95x&oD~kL zO2F{NlUb02ivJQpKBi<2AleQtFB;xWozarnqjng6&k_}mG^JPI9gUQJY@8pdzdemZ zxPUQsay1{XOP5);aj6WGuCdB+-;FOU{L3L@JDTH(~e zbPM8Bm8AK`1k7muJ@XuT(4ykt9oOIOo%L|qjH=UJzG!r6%-L+I{MWFB~OTA-geaPKK0bC9V{W*H+jVjCNy|gKS&XNNe$e_TRvXt$@I8iM8ELWB zqfU>BmlLIVIev0cv?uBP=|Lt0D3#`cj-o*%uA^*Jdc`>SoJ)2zF9*+2P5982Z|aWC zbP-2yE>_2V`_AL*X!=-W-;a{U@zO2LCc;Pq9R3pK)N?t<%mB4n4lU)7K|0|ZIsbnd zk35!)VFOQ{)mV63_<3lVgooH)@oUD9NV<&sdI}?gw@azT5&Z4HaJVEJi`is3a|JGl zRH@_qo~+d{3V#g03Rjz#?XcUEp1mHT0j7InvjC@+#VHKA&mTjHk?Cy(r{yAX6_sa< z%O=`dZdr5oDxGY!&Y4Jre_ncwk3X*oGlQnbO^P~aPd^l!Dmq>6Pi3bZioa}Vd?nwW zmKdloMw(4Ua*wH1GPl@IkHli}gtVJ{ZJF8PyZL48DYo=HDT2E#iM?fptGM&@mQoWW zH-2;Q&ST-LydA*Ubo=HSan@t zEuj|+ar4q3cC=<=j)F*xctD32Qv*ZFYoXyJs3@u87!+`O4024Z66;e&UC*ho8N-^= zWrEGSnkzYe)Kt4qOH zyR0#fuPhxdtp+h6l^kTXVQ>L2y8mbjJFh;TS>?DvP`uTRU z(OxOJ<|1BH9_UJ`)-kwty8zUJPx@Qc7PZ6}uel~?TB@z)TSgkKhA%wSZlhj@7~U4ZYynR;QT#KuR7`DknG-n47 z+2A>vX+#7$=~bSNvIXQKor*tud?CRZ5x`*xV8I}x0!blU0#sV04T-Q@vjI!>a&V_G z0L7OFc*-4|VfXk?`Bco@W$t@lm^0`Z%fvbUY|qo%qRB;#A20@7IgC+j%)mVF7{W$= zu6s{E(9~kyAUmX5FyvfFCu!Bj>qg1@n|b(&4`$AD?_J654VC)E0^FT!1s=fy!Xqx# zC&Z7va?(f5B&%r^kI5qM+(YbPVK|GgYTP?!{I%3$r=~?x74kW>MO( z>!E$hDaX}iw6PLkvO zKxAzG<@m{oH0{${&fi^P{|b{8<98O{o*5~yo_wa$0dncYx14YEL8-Rx%`$DirN-Z4 ztm6nRzN`yLGJ-^)JN-PD^y!zfMC?sl1aZV+fOH*tOAAS}?`4&ABM!b+AiuX56PPa) zK)44haKx_3Im8WPRfnF%+1h@l)MlM*lt$2R9+fA?c)MhaYOh}H3;Y`M$3mx`NerGOo^i$jl|0^q}q&$9lX zb9%@WFgZ01K2A2!OP*k%AnlPD6o@UUv}!i+pn6wCLG>j{6Fup>8(5}X4CWlpjuu5v z5EX0sAe7A><8_@~R53*+9=m)uReP_Pl(3loqMG7>?_PqGRw;Rf4AT%xUqC`|+N3sr zJ2LDQOhjmv2^V7#;J}MKaQ1~d-c^=W;G?OI)Jn;h?AOXbcVE{K2MS7f==1X?NTBI@ z*K=)x_j3M>uua{>)doECoJxY#z>Z~!<&OZ%3Gk|@d&qNM5n{R9KKG~-xnjF1KKpEz zzUr;#>|H@O?o=__sU@$r;OmqWq`qEOyfIwW7r%uI)>Qhwv`_KUIIUU=md!gWd6g=4 zL6&*^KRx1-A=*9_T5ZQ0SvK9Tri~l$r8vIrF<$5mJ5yLg|A<(~*Y&KBK~6y_L&n`) zt5m*XORbi<-aO6wAX4nkYK3^7y321;yw=*Tp%_#*^!8pjasU(46CX}9*`D09G-^Wu zId7#+QE%MJI#KQiV_%T}`tQuU{g)^&n#q-IQ`XW7Kk>1jb7BvH%tzRaCW)HzJ%naV zRNXjWl=1spEpg!ZZQR~#?SVX;zie%~ zRTIWi_m6%}b<3R;@S;wx<=KryB?pr|+z?qqbgIy*nPVROQ(8iPyb) z8t!=H5%*7f3fpVxg z9?<}W30Mx9(xH?os(d4IAdJGl^o;du=HS|T5m%ZB+Dl7Z=cQWAKGEKX&ts>MKrRsSzYKH3`E;CdO+6x^Xa)^`G$GrgQTwKUqMqaNuq___{3ic3812p#vtcU!u&l|v8Fl#@jt{5zBmO2LrD?ov!HS`;vBUv`` z9!9HE7BZnq>y*>{*2~xicZXB|X=x84=SXXFf&SiHH=2nkn~uvBGS3}5`z~yu9AU2R zicS(riQ{!u4}!5=jDas?bubTRX6eD-vQO&liKS`>*J;3d01II4dZt$o<&a`y4^UoA z;q;9^`J`1HS`bAmoQmOh;IM2&TMwo%mT=dV=;lEws19Lo(I)RYYN=# z8!M#?6YLS}j|W|a;GPkRklF2fH`Waei|N;?K`S>^s*vpZng%HA2b?dfsaDY4hx`Ed zW|3JJSbk5CQ!Mp8*HVk3ojWeTB`>P}NaYTiTSUrBQ(Ip$V}vMkd7~D&N%HRL#1#!` zX*?*58p~^-QCSQ^oUXev?U`5VmUP3>mai8!F#*Pw51RRE7+$0#>vj9k4X9Fi*!+33 z>dgUfKm6cdPDG8N8QdvSc7Yw3Nn(ysl!%J>9i>S#rLZ@S;1TsvKm+C` zlyqx86Qh+0EH4J)#7kyx$iJK~VBUFgI%N2m{XPC^rs&)29%i1=qR_2Y1`;E+rQ^%g zJkl2wcok$6&f%-)11s2vNkvRDJIbv_jVj-M9ed0jxMmUL9);SmP@KXIvi+~?*n&O% z-;IG|vNQ4hcjiV$s^Lw13&OyAUZ1Lx-(%Y+4<9x?zvC=)K@S-}uCJl`Ut1=e*Zz7e zGcy^e@bo_;5{a8}+da0ffk@0kn6$#40_H$#fqly#SD=7xKNKxz@hVsT+zuPrbd<}J z^9V)nU5%+`_)LPj)~4$c=y-S?%x?TOx~YCjfy$35z^#tZ^8r<`vb(9bFOuV}&A4hp z$Y9S@ZSR~WxvujDBRexBmYz294=I=e9jov7ku_wL3}hrl^$%@IMdG?zxo&fFkE5pW zTVy=84p0))VCy;yf_Fk%uR`~c4=%bNqZ@VZRnr|EUi5t-LF89k*ZP+R3}1X7z0#h{ zdp~+fe3A=i>V4eU6>j=P8P{#iEJV-dL0E~AMA-EbyajBxqNMxYUH3Z3 z1N4Ip=+Xw_3A?+nCnDEWbiONZ8FNn*2p!34I?9=#fM|0_J4qO7U!SMn5W-Bj%?Ep| zfg(ve*1=n668FirvU4fM!2g#4LO;-HC!eQNyUM%qF#t(ln@i)KcGZr&D5TkzjX zfxK(+ZjCLzT>c;~-d~fzBkqT5*5x*eFLAIu!U2B1KfqfMZ;Mq>q;T6|xi#T>>HV?} z)bS!FUB+ks=mLKP)mKe8K(EIUZYIlmj;;BE(!{7i?!u@in{*Z?nt%;sCCRj0(E3i+*Ps755{kxOgvFV2l_v9I_$R>bq0?(#gY1dWArg_*Vps_e4#;vPn;1^EZj)JEN8#mYw@%7o_>i zz;FB=HQu#vo^yAIfY{CxTK=;!N8nQc#mlvD>H-L~Qn>&)$oO2CTd~-EjPxZ ziip5DM&+P8vjt{nCD_`G{M?W&p(C`=|2L{MrJU?9C72S!y%A?SBIYjQCRpwId);Eee^+fBh!le#+YT?&4E| zV^-Gy_pDS+Cd(v+HXAZAye>W2<3Xm(uy5+WkHT40BsEaz;|}j4#`ko5DHvM{#xJ%8 zXYW*Nl%5nb(q@a~p5C@z{#CjbA>2H>@Bo~CeCYdT;#_1ZIr&!^2#-0*a?GxkA232^ zNo>?<3PfcL@Ek$HihZ@i7|H$XqXICk5`pAvC1!yMi5^x!<|Xz`D)2mw9iZ{2bQ-kwN%FN0}Gim(bH!W@k~4Z5IGrL?W2Ts^+Xt zi5g>Ts#QXenh4rodz#O#xbV56(L-LLRaK;{wvJKiSvzD%Vo=DHxt0)!QNr!(hZ4v5 zHYT%#!@Y%%TIz+b>J?h0+u*=ZdFSZ2B!_GRw=lEV-VWm4Oy3V*iLIY|3NZ zcd%tf8*{<*4P#4Ss(}CNV?-?VPkLJXcNaSAwy{Q5p|3!h;=2Q`w%T}(;wUbnIMP-R zxkZd^vm3Q|=h{5n3`5uqI}o4L9c9qS+Q?Rw zFkF8GL2YMOWi_BUjR-$vv)gzbkds5)=`Nn=!B-Gogxs7hgEQx>ucDkUOY-tIvVvI` z-eKzC3yuGG>&=cCF$!QB4~_D z@Xt(rv5rGgOUjwGW3^$2{eMJ9G;|?67AMVd(C|HwC$G+zG=lJu0%Q<@yBp5j=I+?I z|F}SP&GaixoCN{kr!^QOI;Jo8gTz0->auE&iU31BZ%6(bLa`OEjOyX)E@DC7oQK+q zU@d(zL_1&zSFs@T!vRymDW(0n#mT3orHjxvPuiSIGRSM!%3ly9uWHmofGu7OHP=nM zCShXp=a&@0WlP=yN z#k*@EXH`Vd`dPX&9mNIys5Ixk(Fd6G_R`8FwQ&IOeQN1_$1T8DiDm>WGfgKFqlNO` zvSaU2I%iHQT4NxjIoc01oUNgfE*J!}^o z)lq3A98LF{Y#>k|=&h`@mQ91iW2l15Q``f2{@9_xdvvU$gIuzTcjJ#iICX7+H7ZM; zk?CV6`0|vdmXk!c{aqo0FrPxZN4tE8adMieO&Ky0BP(Oc*ScOeNbl%4;JXWhboCxF zb{F}VI)4joAesL->zdG5x}(w3C87@-Xu;)GrtGdMyeHxi57d4sx^pl2xM#Lb|JRiO zVy38I`dc-T>L$*%F&+uBX)88jR6$vRkgLx-DQke&d#@5SaFBzx%D+W}^_mVy`IHtC zr|`%vS-BK;#me)VVn?I0jL{W9rxR~|oElCQn8XmeGGdg!y#6{6#`-$17pE`bHaF>! z%goyXZXH}^PMZQJ=4GM7Kcmd(m*hW(@|L3>$}&DGSp0=YZ-Yul8{@PAu|5n*Hb16Y zX@4}5oybaofIT(Q`8uF>Cg92zF51Ac^s@dvkpe@-Fl>pGWvD<(wQ$i|#6L{=Foyv4 zopAHQ2J2WB=Ss4#T&+39nO0bJt71QO@ox($;?ILm8C2OXa5tLQPZqaLA(oV%lYe&P zQFu0Z)u#@2S$RJ(C_bN|f$?H+iru_Y#zZd7N@GfWp&r$gUl2B5areW zeT=f;W{ZO-4faPBSa-Ga#)^NJ&d7GAy?YBNjO)YXR@}({Ez6}oH6?J^v zy%xt9hdk+ac33Ux{#<<6CoKCQsUTnno8l<=<((jYHXCB>cd>45-1)e*M^Ld_jro!4 z)l!QdT@d~yZ&d&qcoKr2u^@??Q4A>`P=1_|v3j_94eEUl5_s&N(|(Z26_hi&q2F=> zHuKCz%1^LdI@E`MnmW+eq6RzasX1DcpZ%Hp72FqqE#mt2HlS5sn!CPV$`9aOz9}_FqV}a`)r=!KjLT7T};E-OY-jJQh zx(HD2$5Qc-UbJy7Ms>RX*rk~}rByhe1!_GJW$7I4nLZ4( zFm@P!6bNn|q|h2dm%NlF)W33Otzre|1!%NTTWJ8d1kI1&C0@xh~#A;e}uM zss|Y^q5?9F)sBC`mFPWn86rS7^ipU%r5a~aNm@0&!E230-T?ssJh0(Ne$ObDnCDyN z+YTKmA2)nZH2F>m8_F8MNlSVQ$IG~(##@pdINmMYZ(T$Vq>9onepqT1A7%~mc?qik zkOI`nlz+&9&Qp#=7PZ`z`P_p}*YJfMmqJ~n{)!yTd*kr(^9I+gf!}6?#ePDxRzBX?UH_CpDi?g}LHxsPPF^oV#0w^>$lDiW zN5gHOh@4Oe$ip_ySA_FY;SiIgB`2coRYRhT!?mc9bLt4?7Qoyxod0#-5ZmeV28L9$ zPBeY|@s+&vUMC&{sKEADCs~OBPu!%;#(4&f|KxRQP6)*=7Z$VuYSGdyMz|1eZ=;8l z+q@mZ7HO7t3S8_Ly3b$`);I8fHfhftYTw>+1fw(Xr;fq~?8tYLmMzR!R#zQQ)| zv9uh|S*dG0DVtsU4gFf@*2!tPK;bKp18iTP>MDDZ^Z16+FXWoNUXk6c!olgsJ`v|e3_|8x+F*YL>=JeHqA zQLqnX_Jn>;%?zNLNDBYT$oU|>YgUh#@rS3DofwgO`}*D^pC}>O4f-fT9u6 z9Qp2n%xCN>IN2Bh(h;Dg^^};ZwVexK5;OI&VwmBwMKcP0Jwj7GN0H4=JwXxOVsq)+ zA+rkA3#8pPT2wLY-yi$V2}nj7Mn2~FBfK-MSLbvP%F&%vMN~8KuRq@Y0?{rkfV5=I zF%@6QQi%ihtHt7Na%5e#(J(vF)%Ww)=9vaBDCuR*cMDT1rzx}$0~t*mLeW%A?#6Q< zaRyB*tSuJI@>#^EkaT*pL9kv+rPg9ecsNw?I#0Idz|fc zFUm=ZU>_Nw`7>}Npfn@%^SShOrHuL8Y$DQxCs&^2_yr?W6_$117lg@LT#AmY^kK~t zfy?K4nn2Hx{;9s9vBv&eP%cyq)ubnli${>3)#6H2^Wm0xLsnC&C&AxTgPT$A6lB!+ zaSWe_fEbbd-U4`UDHV1-+(aFNT+L~ORW7)CM=WTD86*5L7PWOw0KrM}ty^j(!b9;i ztx7~x;-f&;{x|~QXWre7sY-Amyh-N#@NpZHQsDy_D{H@6IS}Y%mrX^=efchd*UHUU zB0sgqslS-WLj>in|E<4WP&pVgbjquf zkD#w#B2SZZ=+jU1an*lbZLDAkGK|Z{YAv5mUdlOUxalEB$}+NFoP{1E^<7qPu5boh zv}33)#Rp&%yK}`(Zm_j*G6lq2KxYi7AuiMO_K?o-Mug9@?%RR(8qt2g=KebTqXp`p zkJ_((Jn5TL^@!!nKKm?AQ3VVj;4rAPKAOLm-0uby%eJLAS95mv(WP-z>4s^{4}ka5 z=*~ae;wxhIA*V?rU_O~uSv&T&^lPRo^-~)A2;kj##~k~LJ7ypeZWC>Hdn&4|a}m|O zIUoldsqza~5JkqNWabT*g$i7D;OL=I+UjpL75Eea*k#@++Y1Z8U)j=b&a$O8$2Sf! zdP#S=FRk|wqc|$ln;!4uP~JR=A~UNQ%biPtdt=kznmW3t`b#`r<19M(mi~H=1Il;R zxPuIBaW1tUT1h-IvyMChQE1E!sd~~rmDg~h3LdYJB$s?*mN$mfB61=1^DoGte}C*A zEKfMqu6Ius4?>j=K05<=f~K9q)^KfVF`PkBGIbL@~ z)7zHx#-r11H+`9`WF50CeFnolx`_b0M`kIBic2i=Djfxs#h-+DwGiSaSI?N;WbnSdUPm0CBo z!a{q)BNN;E=pZo*7%8gHT5HO?9)g%{D%6$Nzgjs_+0JD~M+kXW6WbnrxaMku1r^Tf7&jb}zK?{@B%(?m%!wm3#L zzL;G)avAmK$AJ{YH6}9c#e~ya>C|-oD?Y470(qWv>zi0WVWG*tB#B_wZh!T#D3e5{ z^?oiNAjlWsfG7y|2q;QCW$5jiF8l*$MaV^E7q_vj3u6n>1tbJC!MA!`L<)y(U-f)h ztk2$5Ck7SctKsC!)%aoFL(m1}Jh1~u^awZ_zE9J?iz7cfPV0U0_`yd{UMQ1Tc8n#H zXyEd{73L%-De5U}AoLys6@AfrIqhv;Vm~F(2eT^ab{gjVhNzY$rPpYj55(cMa5g7m z$Sy!*braaX1YuR6$36UApH&MAcGQ>NP8gM>jt6hL{3G28gAyEc8=8v`F$wAdXQNC{ zQSAS;*6bk5&K?&Kz-tqaKtv^B?S_u&0q4k3*0JIl0c<98CyxWodlC;-Jqf8}iJ-pi z`sxQ5evVIAOq*2zKzrjR_#U)MI*I9oJ5d0V%=11nBM1-r9*-3eA~#*VdUq?o^wvbi z5xdI``0cPHdci)&D$g1-SggWZkOR|^XvVQAm71qcJ^b#%p3XCUhyQ7|Qa*AB_=|LO zxj@0;a%|2mTSmnCzPmU1VJt(;MBflSm*15*qrhZx{5MnqRB{Do3WPv3F1s=q43(1K z@sUOJ$9jU%&o`ywvf z9Bf+jx=eKD?}1gu3~LdXY?YS2dRRB3z!|k&V{hSmbSSB582Ty97gw%;$+It0+c)NA zBne*iBdbBv5VLL&%8lQge-KNQ%}{fvVmD$Ej#V!Qfel+q5McQvssnoz(o5f^?!9Qj zzqz9qj?cgytI1b_tvh-d-<;2aJcd{mEg@rj$&otx4!wAP)25wNKOnf2yz@p3RA?mk zUf=%npv^;`+!t$E#RNQ{`x5lP#&4vLI+c0xp3S6mYRfX^O!Nku0c1zL1M00E>anqy zLTjfaQe$!st@gyATBZJh<5N{=C>&tzRf)u8upQ_pk2x|tyN)i#`mwJkwFFLyOBaslTfPE##PD1-oRSCJu>r8&%f(LNS2`&Rn#GKTVQr7 zEbV<0Rq4*BafV@;NDl>=#QbBf! zeD<*zX->?Zf2GlJkYx*N?R>JHY}KLf?%(Wu+X6G1Wy8(yx9@UAOcvA@6I3iIJ$de3omyOsh_UdM*OsIu{0c1gU>xAEkpRu^gjoiur$hZ@h!1N>p zPfF6`pKvh?-5Z|}yeDE@QK`7C=^tV{QvJuLn~HA%Hc%U0>91Hi2J@?fbxyXx zo6gUW3DWMJb>LqVneA*gK|I+{k1Ax@G3cS5t3w8+DiA?gkM0g3IHk0szoL z`$+-HyG_}Hn=0>buZtL%xbT3KMEX!qGkvy(_aCGN0Dn6m*^((NYOx@MK9bxuoDW_| zH+EK@ZlhVL5%KL3V;Jl?M*ujAPS2#%uQj3^e-BkB6_dM)H+ZX?Bp^%Ix^zu6pjvnT zkRSD?I9AA@6rT!~-TaZO=AEPH?J~eSw9Q>3L<)mk=uxrG+!5*VPN4Cb>~Cba>PW_ zTk|J6&SoLE>6pYreHJDo3F zQv8s0YYoxPE|5_w1jr${-HoSR^{|NNAG)|2cGp4IEa3%-pDN~@3VN>Vm7a5NPjaW0 z{IXEe6wrnGvcTjnj!a~O(BeWj9%U=_`ZegX22PLlrZ7UY&qcTqoqk&@!xX02*JdAq3%O-6ubX-TQ@ML=zhF9?u_-Ml6%H;Ql9L6!3E45; zBZ2XXCRKQ6mC<78hD2Cv8UcQCk*T!_yq|}D949$Ry@YAQQcmrKqM~;qwp>6P@U5t2 zK%mCflXhN{sRJGhqPvGkBAA361C{tB??*|9SPVN@2EX{8_tr-fY|i1`Ls;R|_#i${ z-ww94hLNMKvh6m|g-(4}*6Y-q!hpZp)+(VbDXKxrht%=Pm(-{?$Fkec-^4(RME*;F zJ4`F9*m-Lq%ko;L6pkm1Ds`ZZs*oxhF%d3g{Rwp3xY?8%^`yya~H~ z*i!3ok#}HFU_94xTUDIDq5!Fa238vCBLBeAR51r)9A$b$kkAwQ@%Y%j5r)*$4~J5< zwCqbmpT50Tx7GLGX+%Z;TL=(F)ey3Q8+S6!gt&}?{;~D|=SLom21rm(eM>~c!^`P5 zx)gVIHX$+y-hyJva{MF@D%h}(Y!U5yYHaY3+bBYDm5wzleRdblWFv`BI~ObJx1E9a zI$28crS$mS5%VQmiC+I(c;vUSj}@R-OD** zy7ekiGPdtoSGgUR%)r(=9H|E6V+_uFsN+MXr42-QS%4(LW{|@0v`(nHdH{e<)H+pw z%}A!_m%=*`z^3Sp4;0<(RY~2dm{Y9*B&m?Jtf`#qmLv2j;OPpI-~H`^El!wQ0T70% zOBa>ch>LcC6S!LFjBzRSaDUF<1=x;CH&M}LS1w?uE04z2=f?sSDY1`UqfOP3cSjaC zBfkSm5~FTUX~6mc`~XM~z&qs>puSkcxQo6J;;{T!`J{)ueh#o7K$ey$I6J6c^b7kI z7+m9i?mNOo(8)O^nep#5=|-#Af3lWwLa@MH>BOJZ{Jfk?Lw- z3(lq?hde$w2uMe?j>PYoUVuh_b{Ajo329<(rCl#umK_uJN5)JDMW3GEwPRE%Z8<4e zF>pXWGk}lC$#jUw(hTgU(;qlc_1`xra~HyVp>a5n(?u?~>~=b4`Ham|U|P}|+moLC z<4fxArWd69V%MDCDrRe>!DXZ6=FF(O|cu&i-_2FYhfOY`^LcFs1|D>7vi;w=v{A$f+u;Q4efkL6%&Relgm0B;~(z z$cnNCz88DxE0bQ&gq(5ds#tpdvR=31e*Jp};^q7cqm9DulWdZpk=RrhjkV7`BiWkbYZt*Jx zRZEO@f0m8#Ee_uzrPTJVEpbQ>5Q;UHFJ?l1*q=7e$ExePnd@A$2kab9G;d~LZESI3 z^u63t=ylj8EY8tH{=?{Ha^HnNyf8SVqP7b)ZY;mhb@1K>JWr!9D>CsTPsV~DPGW%* zsf!NKUF=9JeMald;)U>9VxkmE*!vd*DSJDznGryl6omICuRYI#VXMf2Vppua$q_xL z{FLC503p`KJOCSk*kOa}RFuNf?`)k~HFok`uHp7gEDB6_t{`9hz{fPCz}r{&`PA>^ zeMV(x&g97>YKEeTey}`A+4hTU?@5MvP$%HrY#Q4-2<`z0435( zS48}s^`=twA%Z|yFSt^TyykG`XYKLQIg%htAw_5Jc!^JykrF>1%~=LN-(@7F}a@74zGb~SwD52o)n(sZ8SZ{!>XNt5mysGnK>=|_6--V>!lHkot$ z0Lu1@Ta}9V5^bx=N->Kt3>iy#FN8`neeq`(s6qN5)XNA5S)}~+4As)O{a)!cvIh1r z!BS|`ioHal-Kqc|X0OlF@x@)2+T5GKu*Tte3_;S3AbMXb(q9jE1+cxI4J7yKNe(@R zoqHE*`ko(_4i)w&PCLa4DUS4Fz<~ryLxAi(d_?@uvYHkApP($FPz!cU|4wIdTBo^>j;rsqe@89qYtF&0_#D4{(3of12z?gx9R_^Hc zoDvs49wLWqD2s%GGhNfGF-)-=d1%da{lWy4Aq#|2g`3(=cncZn1?{<vR`4WQwB51^?ayKpQmiOH@H8gFV*6$w`#0g|$U{C*uj~{_)&HJcvS0(T*K$r= zi=BR;Lkmg#qfO^ot^SS(c)mpkQL3kGv13u)3<2SZGr|%7eDrai}u`{k<_}eX@L{ z8-Jq)@ESB?L4wW|C5REY%+^C~)UlD9XU%#+iRE0-PK_-}LQ7zke!RyEU^~w0$AyH- zM|z!?QaHrshMK4iV@_&n&#}wTa1{K0c+lySNc*-=tbN%bX?2R=sqYkxit#ji#^KQ9 zay~+XvXKs^BfYQA1QjBKb|-_6QKXs70!$I2tdIJVT;ut*g*O^@T-Xjnnv*F@I#6zB zj~ks|EaKieu5985rAM$71k#PykLrQP9HQ)pA?2Jpu`wY*`p!|&SKx0NqRg;mgHQ4{ zZ$6#ec7LQ#Qw@bwLkjlCRu}W}3VP3hI{RK@;%^;Fpn-GPlA3NHHO=k3Uzc&3r-MI@6tY^BPCZNnJlgwAYFM!E=3X}o@@ipA_69$ugv~ea`0u~)zL)b{oc;Umy zZVn=>jud7JevX%1b!H7z5hRgzWXzF&Y8%2mtlVj@8~6hUpz&)28@(GT1-XQ*$VbT} zN=%4YnV$E7bTc8J~mT+v>dA#%Tvh_IskT=cn;hsV@&AeefbYA4kn6`55{V%D>}NnQKY> zV~5coA<<`f?Ay@~cEX_6K$ldm)n_%i#^`_0{w%Lrx4N$*U;w3xDG=*|NIEEHV8Chh z9KnAM=gNH%FFs5fe#Z7JAGfEfpHG@WTw*sTr*1P?^U{|ML|vT;vu|gFYNHAM$4t@7 zIW@N5PfCBUFFS@hK4tqI*pv291Ic zN0$I2W&5%@A=NQDrPT$v$sTL4Fs3~j#IEIaAYJj3d6$v1Z_w%db0&>gEA<|sCovgp z=zW5r^HvWXY9zH32Jr>DbFiaFmvJ9t?cI#ATN_2@Rs^3*feoKw;KZfHCli6%c$*X= z{L_(6BpoJyAWunzGAhIvFTnayyM}-cm9N`FKkDujewjnpPoqH~7sH>HdDyo#m{UZU z2y1hAC~41nn1gDeky)>wWU#C91uIQW+1N5)BIragrT`y;;una8dWJ##X4R>OyT)2- z2cglKQIPq!!}!(BVB1^4dbk|Tmi((*)_UTA8Ey)`;#VLmQ+SNE+D!Us&`^n~zYEt% z{N4MAe9zqDcNIVlrw2QbQ%?e7W=5tZ_PtEUAD!9))yoyWN_VsEd!3_PTz#_OW47vk z@2cv?2)fLT?slwI`ncs#)jV&Ca{MK3Xb-p;2h+wquTv$t7C7x=bZ$-nN-|FWONI9G z+%iF)fQ!@Pcc|^Z0`CJ0|DrYd!;#~<1Kjsw0rZR#IwT(3iWYF)Bcga$vQwxgVa$7Z zq9oM088o96VZlkae_p+)@<|PcACUmZnf178RP$^eIIrVTqFENlpB$qz0fZjNNC8=y z_oId_D@~)zjz2uPxwkt9K8mrF7nMsQfb#O>G%IEKzJyQMqvl-LQRJkjM!Z(ZuvGWb zy4w)^j+ikaiFaAoljI&-YIh05{pd<0sZPc6-l!r58rmvJkp%}S&ql*OOz!aZNL-xr z{s=(d9=6(!C`$y?J`S-rIqtN1ZAZJR0U6f6lOOzL9<2~Gr>e!tll z+Ss6k2yiTkVGZur{dyddIb&&3RDlDeJQYd!)KRHkEw)zZwN{di_7~Yuhu-&}csS{> zB*}kM?8$Fo{!|&*mVFOUVj_Pb<`wqaZ8nx>4rJ!kmgdt*!aFk0Hx*J6xhv80O+`US znsEu~`vVtiFA1rKXIPGC+VOa??AZ;=4ki~AfQd%TitDfC@U)gx5?Pr;9EeEA@@e2p zFE8*0g=cxAs+Qq5pX37KbFVKnEN>Qgi$^Y+29_8g=1?PT1a!1E+Q3ihJY4;LFI zy>)zR7GnNs2Sp8G*q;wOaGpT---MY5dj^3-DTHJ<)=B>9C){vTXgsre?Z1KZe<`6^ z;Z=L>I6x&9vTgoRFqLq6cZmVuIE=<0{U6o2w20W!&U*ahQ{_K(0@jjTPaim?;4e@H zkW=HG0Ub(S1K>V%n<$l0W37O&GegRN5dl(3`&zn@kJj**?J6*N`kG+6q|NG^$>GhF^#dn8?%uD}T<>+N0JfPlFLxbeh1SuvTlnFv|6syj3`da+=t*MFU+f))%?fE)hRGJcm0p1w#GDAda^LW6FuODg?X>ou3 z$c9cHQg^Wz(YzPF1Jbgi9p!3u-`40x@7TLoYx8T6>pRvtI=*B^4R5U(Z^FR6U+aeG z>L=Mz{g?}AeRv+L8G&NkoaXM4J+(_Dtmxai9BP%nLo?qu$fsdqVV%;DY~NR*Azy^C zj0f&<(d&frS`{sKD&mZ?V;#(JR&WtlS&6tR4CB7C>NfLN8U|vy~__^5WgK} zi#&y1jyJdLtI3NhU<~jWC7v8^`{xN0EPc~tmF3}=sk?hJm&`XPdWES>`<&0%NB$i2 z8dHNT&n?ydd#F3jBW@C56qJw_$M1CPr~PQ}$M|J%Nn}(-9s>=$##G1*v8(V;KoV8> zYfz-*2BEmV-=z#rE?8{068%Hbpn{)21(@8QZlBJ~yq;zX8&gq&8_W~0M(ZFE0KEER zF87B7b*y)OqdJ+}g`^W-`?Z98Z^hwW^Lnk9zt;_PEVDC=6Pl z1|z467NJh!@UoQCinD+r0s2}Z^0R_2h*HW(PE7N-7T54Z3J{B&Vjcj@e_i3#ZG0o= zSw(U|IQajKB%J{_Kp45HR_pkL-Z=BSJ*71OUfG;4ND`ZNx70;vXvL+fmo;o9?XLMejkJrO1Jgw5VP9 zpv^XdnAZI@Xwv3(ow|;#ufn74AW5`?zsM;h`O#Q@=_<3q;;N-v*Ah*E_!5_!djj># zkMgxox>l_9%Gp#}C33?9NpbIK@rNR4k{8Lt>6`c12mBTjY)!NzB2>0%n>Po{{fT5H zU&;$2h6;~qSzaGE+U}rPK*-Q00eJ0x6j zRvpaU5=>Qt4bGri`x-C6W3OtheORF2A2ZihX#7&MA)?e6@(AiW#4?$iz<4BVvn$z<^j4fA{T4)oV{2tu2TWk;dd(zKR`AO z3O(s>Uw@agcnOHhwW9^+GC#WrtcdoL9uRipa((9oGOA*a&BBa&Va&7V`a*ns?V8UB z(})7hh#@}-hUqw3{G-yd%0}Caou^D2hs)R&rTce3N1`3Z+EbPVB7Wi?dy}U){LVNb zK@TYRVd<+9Hf7NEb&voK-0{v!0flo8PLYWx^~7xdzs>EtL|Yt$=4*EuXkBKFjxjUb zv*lXyoJX+9S@eBOW^%>fzSYlK5H0Sw2D^6AdnNAz43>qdjF^l>rp9vC8devJ+FYOA zh^UcTAQH%JN`_~PJ`rA-?F^*+NhmT7b2bVi=yk@{-o9db6DG&Q(OWf%XHUS`RFTuy z!>wo-_l=QygWv%j{csHXBgd+G!lc(X#mUHlT5Gx1=%Q%_D*5={8`NF%eLq7xgK<@I zk!C{CcUe<7cv3T(&H8!HHzZnyM)3jg61dy%QHQ1GylLDY*sYJ0qH%S;F~>x8pS7Og z#TTDASCuH%th)WFmJXiE9m_jTx7VbI&*KVv>oZl-OWl|QQuoISyOxthqIaXR*xcE$ z%>%l#(w4f$+5TQ+?)2C-M+cIeLitR+A^>Tb0pym?iy#Gk60gk}zr;g2_-=1(+F){9 z$_C|SBWf_hx`qI;0lKVG>>SzrZ|~H+dGR%0f)o`C_k+gU3;)=RYI?-pB2&a4sSK8e zcFC58UlJs)2vVd5C-DG4kO^4I3eE*QwK$jYOUNf0S^cl-qQ62$>G!0CpM;K`Qw4Nf zlA5p*fMnGz&898z-c{Kaq>NZrA_R8}PW#e_5r0~jaAgV#a?WCAZ!5m6hlc^^RrT~l z%~+S4!CzK*4%5Aq1ueHMjYaK5)X07HJp3!|5JF^iYh|RKw3A1`SILD?#~+pi+0=l)s>|ET+Uxm!m}U2TySuHYkb}GnV=;PfoH@pA`pn~yQ)&QP_piuejKS;E~u7FeIY-uqZkH-|c*A7dQ z^BTm(PB)=Q;-y_`#ljj!teHJ+tuQ)@g&i8qt z>B;u$_qBMnQ}HY>@EOwC0PZ{%)*;1yw~yrcu`s>P(41?sGaC=Idf_@1%b;_6D_ybc8PS(*$Y@Rne>Uj@8yAm$Y7bTDpH#Nk4%D;0( z`RRJ>A`Ciw0hHfp0QFfFnut<+j37ZhAR`Q^>PsLd4mvR(F~MS0j519lg_EA-TPhEc zYs@qyt))5g;1M>80PQVK#X_cJrG&if@$(c~*@r{O{}P)NU!S~7#ZgpsS^TTB`l->1 zv_rI#AoMz7=H)rNPm&zN2J@LbCi$xF1BrNjcCXAq8^^Z}JrxyxeIgFK@#KH_8U6no zL?%+Jc7}pFxQr+mK`*>&EeQLX^3l+XxMhT00P%TEWa(#;%)iweYEwkk$JjkQ@{oRW zflpL}!o%O)0YMj(<48I4>N+ZldxL3fXxrG(^C+tMi~fSY5vdonB1%=jaY5ls`Gayh z@|bbWW1T))BD``=@y$y`rBsCym9R16!pd=&9QZK6qjTs=t(56N_6kwKB@@=Td` z)H4Z|uAsYVkPBj03k3)^`{xI$9X_atDN3KyCk~nv6eMMpIFQibDFJh*059>M@3NKq zZSPpK!rcJ627QKCD^gVy8%F7q_@ngA?(G+_9~)iuKmqnK6>mIxaS<)`c*#`_-2A^2 zO|N=?+vu~>wPNerq@AuhMB3rd*pd73BX~N9rZvw?TvoP{;8Kg{+gs0tYk@()@JfPQ z1HP37PMZ>hCs6eQS1p%Nwhv=vge7evwS7j)>A)o} zod~nkTZaBmY!1F826_ViweDiZ?Lgo-Z$snxjs;9E$3z{DcAqWNk#}c6Pz-lwhZt;pI`uW zz=UdA`@0^(erO5#=6aI|MWl&$9hHp6m9mbYJlVReSV(A6yW{BLp*(40*-7!9b4m7d z?jVQP*2AIZn%E$mkpl4V9gZoa!`ZemRnWY-s2y{301(X>fNmiZ92xn?P^@q2>i}>i zgObx4x6Doq-lsCXFq1wG%@>0S`|`5BUA~V%p@q03MP=#^IW!__!h%HyMbm%EFAYRf z794BlOpx`i)k%yaA&$?fk0d9fJ+nHCvz2Dr*OJ;l&KY*4kks6c!o@5>O8tlB1X3`m z6=d)rT!=5}{FZr;D@W+n+f}Df)8{GF6P93>ROss~kEyFw4*XA|BZCo9@!~#23PcLy z@^>gg@Y}G>5#Ii+31xMB`~QDELew)VS(BYQ zB_uV*zzam-0TbMpb?L$C?9G`0MYQj-s1$G$+IJxL+UTk|BsuO&HI zbLh{sGYuBwi%B#SsGdPAzUm95ds@!AAFMtK2csFdVr$xN%RW`8+7T*2KR7x}6-u)w z7S?@>CZVpjx#za%4fNW$;8$E4ZYXD5B{BOD+cwl&92l-JvTx!=Xoy5w)53`|^sgvE z1!6p?64Nw`rUZSwkNnIQ`15N}0@)nFRe%TwAMtT9vQ-*68NU0s);@?5)AcILu4}SY8RWtaX(J4NbPN0B2&gy4;tg^MJ6YA@Kc-}S6F zTRkWMh%eLmQk;xKhRSyM@%FuyNOffU<~iNQ#qT`#?$&!)=vXpPNyfVV{JH;z#4Nk()60RTiOyH3$RWd0| zmo5INV!=xNtJ%)piIT-WcoAshH<$ct0S`fC_hna%z1+sY3QCbbiDcfoQ-;5nKb8VS zZ4OKcwpXLPCOu}UG z2~+C?ELqOOYOhdHZrBagSn<^&j?o44TtNS8q2t8+zx39N27`vbOOpN$0Jr{DvM*XQ zl)Zdw-X9vhe~%|&jz1K(ouZ)iWnqt`0obPO4`wGZ7&RIZKMD&J|4XMc;z>z0*9EQ= zO6wB=rPAP}vrm+CL<52mzW~!MuCI5l{dAxFx#YzP{_I=_C@8xRxWTTXN7i$InqQhd zklU|}?VBWk9e)*`lOM?XEqLMjd6H>Uh3$95{nIPdb{>QdR<4*Cu% zl2-;LFkyU1m>yul~MbAJ9qyuHzDqBosuztY!F$o`zx(UQ@dFDXpqgW zZ$)X~tWww#%Ec}IXu8Pm4Ae(6blp1_N|d@sMVW+wWN8DF)b#_T+?@pe}|yi1_s z@)Uvgtv}D-FJzz97^JTC2NQwwECyxVphK_N>B&}}Mt&ml{7ePdlI-3kFqjn57+4Vh zORSU5j3CAbS$Gf()1c(}_!3;Cw9r^u4d?4M9s!lD2 z+U0?S+o3AhF{*KU%LctAs&H0;OW25x9cNmg21XZ4;<EG=oMf_T6ip+^I0}(*6I6-o1-uv)VT_gIQ}4z$44=bu$(R^dpZj zCbGIEtnv?l%7$cuqzWd_73?bR?9&2+@M_1KiZ_tJN+CMOl}103Hh8eD?F7l+nlpZs zV{|1o7>OvxV!M<{Yu9XwVJ!HbL;Y|x?83zPBRbjoXX0BpG5>vlzZ7ENAr&6*j_|-y z0Bt>7^s#i95i}4kZgLOeUVWWXu2CRi@;Xg4=~E@%Pp&Ab)6n}E9)#Q}(0$U6eEe4N zFsgV*xjo8nA!G{=!>^P@%iw2w*+|@?7nOM%zmYWunRH1RBrMgN=mzplGWiDbb2Ztu zfDo{{nW7DlOq_KQ>8Dw7o_>gF^ySHF1(a;r2g{@_*wX#6XYkI-OU(71L?US}%htJu4bJn=5=8jI|G8m=vZgF)YCZtC`}}_se*}=wj_})7 z&AtdJUL8*ydmqRo>13;VR#EOdKi#gV5a}7&pA+8_p!4uY-pD*D$R0cQ}BAI7gT0yEm*M;}VOq!L`L26+Uusm1#bb?rM zIeY&4Asd4kvwK#6qf909y!;K+y%Lh&KI0>;2YCL_5tqLZPeN?U_M=}B>CS*!SwdcE zyDqUbIMy+~iT@AN$KD5P_2!nDL*X<((EC%9Lk|j4oNCm5PXZxh+c;%E(8rUF(Q9ax z&+|DQo9*!1AHJyikVE<`UqtYIdbzSGRY=+Ex4$pi0VHudzhnA(f8L(-vo}k`awqgF zMRZkqI|^^gR{J~ubPpn^*k@Ral;9)*G|~)B&|~^pUXkUb9kOBg5HkKsNF{yAwoHu* z|Lby9?vv)s&{dU-_oIm-oBjnu`4uXi}U;J+? z0+nK_g&%(P%1@r34>GG%()+|}8>*k=lhV24nZ{?%VT1DDGiT;3kUs~?Vvmz|(|H)1 z<7+Ku3ZQbhJe%`#0Rr(pzt}~*aDY#(E674}>OJNQf96r@Tu0e3>J=HbNud{BhSOn+ z`_#b{B-v=f^G5@rvCiAE6b{spW2Nn=yUp>@L&L%N*b7aHN`H-rE(_A7EE_m(mtnn| z&dZx)V;}V0uJ2n^)J0{r({BDMgPh>X8EKCRt6_|coWxF@Noz3%%t%4kg{i)!x2{Bo zb<^_Wa-*I0DdgkEy)?vb=ZRe@(w_n3e;Ck+Kv%b%^pBsvmjV{vSJFwvZ_0;EM`MVp zAExW(S%NZJI}>ED*fxOpvQ^?pLerMsmvF1=098b(-Af$V>lx*seU$HLlc|4@KGER) zjMD<1K8id7uL#;BcKI(2s4&Dee)~wp&7MWaF9Lq&uCM4U0#qmf=&U9UFHl#pB}wP{ z$eVvBi2VQ1^i=^>bzRpRknZk~l#rC}kdkf$q`OPHMY^Rsq#H@;F6jp8?ru2$_Iuv{ z?%bV=wbtBYjycAdsehNlR+PkSY^CUaYr1^7kZl`b?{diyFvL7ChaiKAod3Tv(Id6= zsT)I(M`VMTp!yNNA*KG?C&vaQa`~3K?@*NKtNN#npt3H6V(npw`DX~uU~&a$+gFz{ z4iLKOCzslH^We9H2F&v+ZtS5c#Cd2t$s6?$+^fM2WE1w(zik?A*FKn6E?ML$nCoc_ zYM7V>NSTN|)DF7bewT^UakbhOIuRu!%k+i2V>R%Uy6gT*g=Y@)Oe*np31OKD${^(A zTgJ5Y$UDyBNUh1#7j!ZNet;=6Tl)j7(l#|lI87eaqI>s0!iJ9G15Xy}^7ro>o#!1^ zSNWId?-=MpU3yjec&;(tVt*4I3+yZJ_?i5oUw*m=s*v-wcxhROB_ z+xiz1{W1PN^7VwRLZ_UFq(kM~mkWCwN7(cB`>5>f1`0M|H40~4g!hsiM&67ewJy5j zkOge}Oq68{$tJ%!sxNMzH=GY%GAJN8z318_D;!UD&gaWlqR;YUMwo zZH!5OY(~9(W-dBFq7qKuF;Gnuvp~1C%J^T2BzahN%t5Z+_2xIbAYi|9 zL7?2~!Un+Y>j7kyzw>b;>=-jUrq1gPKB8F*Bey!|l82CBkwuf3RmSoXVvabm!%@QT zl6po~m{~})2&W}J(!{(8;fc5-e~R;896M%AisdzbAP_9yEDh2iX&x{x+RMWF8dz5&>Xb~rzN7|J}_lE|?C zk--4psT`;A6X&4uQJszLo&Cu{EKIc-NYY%8gHBHl6-e;tDM&{9uSODPe$dy4&Cop5 zHhgTP>xy(8(0(10aW%67Q(ofQ=O?O{is7i^t+Xj`cv!nlkDBGK2-D2(!gKU-wwr|& z&|HSUA;tY`$Kugj?}?TxvcBvyII>l^wp>EkSbwPux?w&qdiTwc1*vqz==`PmT(7S% zwZ!~$_7${(h4c0#|9t}lCDWiY>hJ=6*Q3~mMbJOrM10cYwd9u{vr&t#V@|IBz=6CH zx41n*>AXlx`_XPzJNCCL$>l=vGm20@L984`{~oDEu#&-qT_Y&d)CGMA!v5l?fhTyz zOQxpS*$pSA451M$m`oz!lJqWPAs}R^Omkrey$6fcwiYP} zeJlD*Is}6Y6^+F3GC>)B`E<6wF>$NA9vY@|dvP(?iP}a3J(g?hQyOEf?W$ik9wI!v zmTa^h&g-Wf7fBm-c;I*j{(m#}zjAc*9h{a~oc63O*)8r})@C*Uay9EU>472Sj9}VA z@f%<=Kl5#F^<0JIKnLiYe3or!G};c|aEy3hZg4TTv5|)M&(lTBJm;gIA}`!0VYK^Dfh=Ctx88rKy0qn4k~>DM z^S5M0l2eDhCXKRy&J}Mkf2SA;BDE^A`|E7no>`OAV|f&0Snw>vW^E%-yZKEUFax z9prKu>5&M1_Ko0L3pJByj=o85l65H9Kt~&I3+50{lKzqtI?C&FB z|2g;R7s(Mq1V7!j7pm0k_tnosvb zcCHKAC=`Xe+GQHZ_vf1ruvwUH0F^RtQZZk4Z6Lzx)AeV8X06S~Ky?*|Y?S!eAYQ+q zka;d$&`$)<3k7&(x0_k1oeW{Ru?%*`Wt1!E2==}K%pv?ZLZEwgj(^XR4m7F%i(goL z;eoA%m{UsFtDv(#b4^j%}I$)Fo^ky;+mKdcT|PLaLt4an>Ow z2kh&o5E0E0L>g}NO`_q#gjnoZjxTY^ruhg7ULAiCjZA>?n2SjOw9z6H5Hl}DvAr{V z+iPPNHcBQKjdBKVW=Sp%LI#2~5FetSRM9&BHaMf94ie{LUPMn0EF&gqj$JTo-996% zy#XO@9&A*X*BJEg@F@1d=J~(}5qDCud$MIbxeIy)k%Ra)?5MN=E;Fw8Pqw3@&@qEH zm!L817&U>i@sMfoFCUtRy9Ay1^?L()iQi!Xf8w$*fAww}n@2rvl=tz_Gw97yv99?kX$j&WyM7trZvW+{(eFUtIHshY{ zxcc{Bij=(QJA_IZzpnVS9wT*ds4MH18|t^c;aG(Y+e3c@YW-f6mhI~e7C=u6B3RNT zT;}~Bsf{J^AE}L-^JLU_B7AN1YE>VA8{!nX)4bL_bs5_NJ81rE1B|L!KkZnSx|zJo z7!T3tv}FEq^Ve|k*HlN@zMeTxMY!+#kylOG$L9Ihz^L#N|9;5zJNs2aIx-sdm0tvG zpDTNeeq{a|s-Z_NK;A=9P+>pP1#_1e=e+?WC#Q-(6BI6iBStWi8oz~~$LrfpD(S#$ zRbUS8ZPcZXz%kKQEpJYGE=O~B?xe;+scqqAexEGQpj!{3C-Rq&#tEEd(0?lM47P1I zV7|(&-$#md6SA!2pOc#!h<#j&=btRA0HW+$-rJjOHbLI(p+Sz~e!2e&l@=!kG|HIj z+hp1;FhxjF_-5Isp=Z=CKfT(Ct@Y#eiXn|=DztM_NYdF9BK0iP2sUE_8oPQNx^DJC zIkHvZCkq^%Fx~dIfAZcK4_`f>g0s!_3Jv^Q&=uR__RGt^vnm$rVR4S2^@%J0YO29o zB>F+)E$+vxt=9U4jTxoBLEF$|e%oZY&vI;Z_{Y+33-F-NH9o;Kfx4%BRPN6VGoVd5 z7oMZbjlzB1NoX?LuNfI#CVkrH(#TnfU1L0mGJs@v!vjzlNwx)rM^ZRO(t5T@@rvmP za#L=LiE(sDDY+K8h3(_u78AWt%aPO-eBK@(y`U+0MLt$2vV*2iwvuiGv%*a40TSi_NfxrKiHk$$Z_0Ao9ma8m3}!ryDr_j-V|V{ zV!~4(#FfRz?=XUR84CB^7}qsbi4R_tQGR=Hti-c5PaXG!D;zTW)Pcjb{Oa{&n|%$F zPf8Kz`@|&v#V9t&du00Xf(Od79JQ%-GHvJKXXLOiJd;ehl)5k;quD__tczyLmzh29 z-Ei?O*-dU$2q%wM6Rn$e%UQ zL;NchA8Cq1_a6>lqeUQ$65KcAm%Xg4Y< zOqYLTzRUW(nw9FDbShJtn-KTaOeJgn#QqN$kKvf~`;oC1g(eY))br;w8|WMX)K#25 z@tUlZ(j~%E!Vu6xF1Y=BfCPA-iFB>znCjb0#*05(W12yqobuNipufDu&{#86OwU^oIQblU_O= z-X;j`E^-JXA%8s-S9Ko!)6%#tfcIVnjNTwgN$#jn-DYXU2WJ!{@d3h^z(d z8#V2HGP>|IF@)^FSoa!M#=;LlvAkI<-PIB%meDyMS8SO4#!MuOyOHsgz45er6Z`yP zP0k;9?l$c8K=CrcU`B#Hm^cq+g2?3lmkGjp>$|=DE)5h5q;`Df0Oy211tE6_1iDrK zB?88xkb{ecE8y9YlUl*NhAINrsNqiOAlqRMUw$jZP@U^f1y;&99rZSV`!`H z<{4{AT`*-IKgoI_vjgNULte{4|*8-T?|)aV$kv;uG?pA zZDoT8ZcvO|2cZf8o>G5vbhx9)zd4S2fu65Df}M#QkT) zpsA2jv@ib#Rd5tc<6w7;%I>mn;?L>@CU0S3p0S1dvAy+sELl6Py#`D%cyEMjApu|I z;tRt~L?qv`2^oHT640R+voZk>qDJ5Yow-Xqs|6~z;v6I84M^4eAhlw~g9SrkdqKU< z#E^K@xxUN=9_Y}QNYIfmsY|wtH)2ZAh&?zQRco~MTG$|4Bn^>;CkP}lCJT`p94xjV zj3)8a$NN|G80w{<&PX*TKK-ej8Nm0u=SFw^RAOv1LE5O((2;)9&0NMA>t&dT!S6=m z#G<)ir#=u~LWlxpH=J>2wMCDJMFzj%oW(f$u#Fp8GX=LSDJVJjFAV+EzjCgmPnecB zThEK+Z5p~}ZtOka`TSaNQuXd*@>MetbW+G3pUQ>>NoqzP0m0Vs9McqwsmYU`b%LDx zQj&IOagHD%7nZ71#3bf*J;JafFd8i@!QuO1%d?^^2sE2;t zuAeaOML?CJB|a&bKZlZG6|`wU?!1(|79eQ{xXH>){iV+1+9!T=^cr&0hug^`Ypx2f z41qKNqH~KIw*TnU**Fxqvw#r9i$(mHlqGIp58ok13*~m0T^ZPqHVhU)1(Q|3Z+pPR zd>!k!#+$6Lv<|B#7Yf210t>&)I@BMR1iniR#5ZB7MYjjN_h(YC9+EWheCBSFdnWTZ z8b;%FqAqs`P}xh^C)up9KU_9QzkOU!%+fU_?S379^HMK*L%<8aZnuo&e;1zSjXqXL z2P!eC3)JS#jydvYhT@6~z zhdM!?-p)~pa|CWVxPPr`p@`i=N!*hQ*s2b;!=egH7KT`2cv>|4u7LhQyrueE$xQU? zUzfZ~ltH2;Q%=l@S<@8jBX?RJCvgV8Dvz#(-I|WEa1QX1v9;JM|DY^RY;y5$CYyaPj!9=@@tK(Szojz)7g_J3s?Vbd!&;& zMpMUP^pwDzDhu==(=6Nk5^grsUUARO_BFUIAon*YKvYwMNpQDR+gDKVTkLT%IQga5 zd9V59V`FR$stG!1W~{E+0pubUsx|Lu0SWk6Z^0B37kxJTB9ao&8>JixbipgaG>yEw z0qY{sM|G1Ks>1LhFt!+NjAXhZXWEYKR=DxpbCr?<#CMkMeF*g^lfTPX%E`o20j+MW zK81pPL*;#*B15dJM{rw9I;H}$Lon}%>6&qHCDpQs0L;&c!8I4YYMK4he~Hrd@YqUX zL5P=Vyp|<^TTPo?_yw;vgK$?BLe9Ne0y!iBD1fUm~%;Ca5<}V$wSKj&X|A zU=^6dSi(S+xy|cP^{<)ZHhnC-yV0YY=3E-lf#jJv(8HG9Bgx$R;}%|02fXxu!`_Qb zn$c@w?+)+xu1W;pGkQ8&X#X&O(erix1zkDXcNIqav(vn5|=CJ#eA|!@kN5)C=b6H3%y>!5F5J-)0cZ zAuu0Fd7?hOg^J~vBKyg0HZ3m7v%~(8VliV($EMBQQ|*lF`}z2d#^vt?w&<6&Y#4vq zNKclpzUI*W98VmGoVCiNxKG*0p7ZCTx$Ic%!|;zQ&rlFGcS<)@2Iq6gw$4 zKE=}f!jH*siW>XG7l^(4K02Dj_;^TcyA6Y04uei}5=UssN17ugl>%ufVvlH`LiYo% z{isJCpH!>do^n_cwL*NPs7t9ue7^4p_s{6{XAa4mU5}YQ6}M*0qLZ3!okwMv^u)h> z5!?F7#d1zG0Pr4!jK8S=Mtyy69V|)-AKZdfCe`9X0#hfF_Zw@nGA|~fQ5H}llim^g zalvVlCF$sSMPR>CP)zWwO2zL{D1J?aDryE%Oopkpf%dP12txTcA8+@)dpA*7>fJ0y z<|;^+eu%(bqwtX4@kb=kl@|Dye7^y*cz0{!FXO!{2kS1Y8-uNW|NN-ifZ8vE8#T#3 zfGh;u771>WTPd=JGlxiRPZP~?j}gWQquIdiVIX<^`n&1){KN5kcJ38|?4@LO z*xDmAl3H_-!U>4+*^B;5YbF1h{*_;E@3(IlTP=n%4Ja-qP{!m$V@9&eY&q#EnEqbymV@*$$~U#s zr{;@5#LqUN?3giLKEC*J_*D|2y(^FQV{>7zinjLF`PF+N^pCf_6#h_b*=PYilnn>c zf;qp;S{cQ^c-wmeL0le~>1+hjEaP6rQ#~Pjvt*9%CdkMk$Meb*pTf5#``Z!L*mScW z4zmSXt=L{a1&Z1!?Hhw*2usW>IQt(pe8mwsey8^<5q^jF=5oF!tKS1VV*0V{lS(YA zZ``T$`9@}r_WH`66|S79Rll(?H><4#!Xo1_-2=w-fL66Zmz@|kwlFGj3&ith!0fBV zj}hZnp_lB{lZ!5-V<&ndGk*tYN7$MM^7a(!$pcKmpUK*Sb=KnjBLZ_Z`VgVNlpm{9 z9oQXRnYeQNF1eY#J!s`OfoU~eZ6Cz$gKf{1s2c| zJxi#_`C3kZ1bjbN@-+2yd@{!7UR|nLr(9>$pssfb$ECQRmp;0xdhV-fhReYRP%J0) z=z(*BkU5;^zcwkKszVdmw6iI(pYJ44`FsNHb;EG9A11~((+7>=mb=mS{k2=_S10u{}a=Swh1`>034s`|b+WOTFXCEdZHOCoBB+w!TEX(~i=C$ihDP%Y}@ko)btVKD!ScvYCKGd#N^-b!+aQIRQw)zuixs%I?g=p-$Jmyh6d%S= z-2Rna`!UC`^P+Z_jjO|MaFIgPNX|@t3#SFvG;q*wv(n!CxlVr^Dd5|&UuP9b&w=WK zp7!?{WMJwnmYN&Z6pAyCHZCjuPlD&vBEeomE5eRz$ndMV)t9ihBhuNdR3zEpYIjx> z)XoMZAU@$RQnfDE<99+0&Z7=TozmAFY$YG0tIQyK9b}+1K_|6bhdS`is z2d~K27VIbUPl|qD!#V$=4;-eWDf|w+&>!$dJ193}7;`xoVGiEr#>Wr}pKq8Y@@{k$?q%Kd93k;D=uJHVL(ZuNw_?bwF}I762f zAq&EhjGEKZTEMy7@zk#Wh8|tluR5D2;8Veniwp_q6`)S<;CSV~T<31+d0oR}bTi-I zetn;(3SrR(axTvZBBv5rChwYXZ7QLZvRlcIWQshSr*xkcUKFo`@O94?&OetS@5YX$ zY{;@2@k&-v(+u+9k}Hf^L(s+k-t>=6%=YDQTXZ&uN>*MoYa-Q0X_6f!T%Ijo2?6PB z2(H7fX-K~VIh4mc^@+{2T=k$jJL~W>qy6fYbkwbZ6p_sP%eHbD!D^L+Y}8My7utGs zK6^~SMA)3vp!H=f$!byl_czuXO5d!emxg9=B}wUaZ`jVSty{R4UWWfvn%``Z3*VpR^$xhP1@HG z3i23u18a0Nn4s%kH$30N{@XN5+>R?OAc^=LmpOwU&LXO)q@OLrs5I?U?l&mG@}z3} zvuLIvoW;u11?KxsV@PYv&Q*;kK2;sLvrNk5?}yv9)}1VS_Ix(Nx7}0dk1n0uW^XYu zqTL1nV_IFPfutl>UOtJU1*@jv!n*im(hperm)5d0F_JxMR0K)CN*leq{uS319xWsQ ze23K|4(cO5%GpbPZF!xI0+0d7FP5qE@#LS;^BYlG_4s?|+vLyheRuN}eeX(GUe?$B z?q5u#UF>>er#Q-zVS$W@5<%)l2S@U!*(;Zkl6N|ax3~Us+JttW@S2bjKau9dC5>JA z6WuAk_QNtgc~NDb(7W}AyXi0itQ$T-`FBG!%KREAut00@TOOWXPxm0g5%<$R;hPs( zgx$4B#}q_|I9%}|=CAA+&3sROjIe-U#q!nf5Oekc9MRRrK+A9I+j&f{5Tte zYZ>#FJUAaY$+%z#Hsg;W67h)49@Qa^j`-HSneFc_NZ^AKyA@r$gsr;*1!2T5Mpz)c zwf>coFch!Sd`tYnFQcPA8=vUu!#i9OMzsjaHVx3kxs>V2U#{ovT4vx1ziXrSwwo6U{JCX8Xr!Ui59skq|_B8P{|sE?;IATKzV#^7M;!_M%?VP ze|cxVK%cZ-6xTpPGuk0QTA_YXDo~^)Kg@cKLp0v|LDq6u`Ggf@>e;Rut8n zs0i6u^8st0!@&3e<;s8}B!hYL1?}vIUl9ee6=?X8_Td+D4*l~cKhLt@n%2(6%c0^v zOXu46-$xTJ$6i^r7}|x2GEzaje8OGJ6G5$Vkt)`7yGGxH=9K4rITaCmx0^gdUVtpj zC*e!Pd!u%&9m(hL&knGrru2;zT!?n<3kNuE=>R=u+FBH>CK2LT$z0+gJHGh-M zTtO;A$sgl6f_FqRWt+@H{r8;{@vGU35SXnFnAf+AHE=T1QxLXxy3RU_A2psq|5FOOVWo;0j8(cyXV=Det*05 zZEcCX*zL)pGEv(}aZ3pp@BkD}fH#ZdxBdtafAzV!f-Y}LWlB+{zT8eWZ|Xw=qQ%=P z6ythHu_?bs0wAj5p_lPD_{u*2=u<>szq_}kV1q-vP7*Oy=YtaElKM=ZMGg~j|%o{%g>;Bi8NA&>1Od-3{LwUn-UJF`@g6fAt z)_YZ4x=M^K;YliiLrd>D4@UybCEwA&eyHAENW3b|n zY8d4oU(2X9!pN@sD|3#b)JQ+{cq|S*>dH+Ybyf{#!uS&0x+HHjUGcvMq`UVk5pd8g zgtMa=BA&C3%t=49A86tME_koAeG{$aQ2S*IE)$Im&z0lOB)gp{M$X6cI#B)wkNh2l zQ~ud#Nep)(#)3Tg_1_&*uTzg|P*1a)Xa3TiFt3`O)&7nRBjc*tx4HbYFLB!@YR1K# zlkNIG|L!DuQr}vNoIqSUKzU%oRgNt5;|l>Ksg^@GVd&hzMknso9lheZtCi#0+76a@ z6Gnh2@F223-}34R$6z#HTp@9mAS99fJG6f!dMhqeCAMh<7wYlMc~D>0{E$8SbGja-Bh4XXfi{7Mb*LFEPyQ z)QLK;z92-|yH;F%8GaqaB<5q?%^76OESr(M#s zix)x8&#Gq}0kYS-B1Ue?X?NV$f<%@A-mK@Kj*68dDWelV`@7we?2Xy0v)GbDdd4kl zW|hR$QeEOKuMHG6Zjlvo6onV0E%wygvC%tO7lmik(AD?EO8go#S_D=8xik<1glmE? z8+0;nS$vPA*g5r*D5PkG2^amILLkqtF@6`%jDE^jP$-FiW*~{MK)(pOeJ)@iy(ol- ztVzd|&c?3OLGGjsmMap%?JBlKsv77wdwF;bV*6`s)Z{tv`!ss`8Hc_Lfv{eP2e8wv zG9&F2;iO2PTj{+y$WD~lrX_MEe2-vs3aI?@Wk#vT+y_|If zQM30sM2z8KdX9R)5iaJwv(oV_aU$&UY7oTk5AL4S=aD$E?DMLqqq z{AodqD5-S;-zW60PIC<(x_dUCFrC|n_0+rs%KCTvoQ)yIt8GX0{NR|ly(ZU`i9 z<2-{oKk=}p_+qhor-ZXfD@ge=$ERB4rDIucNqmh{wLi4(x<9mwx-SsvTI@TgF`;@X zuHj4iSYaLHBl-THqwpcwB=mWHxs_)*(7v`Rt5==!O z%AK1>>n~Zy>rPA0t#^q@&P5iJL}XsD`v!)4@eIz9^l);Fds>INo@+yi{(al*y*0+5 z9_)mNFNZ8E`J@6=V~IC{sGu3$pMQ4Zp;deJFOFHMY7B%uS9f8_=rBDXNujh7TlKYf zU#yDA2{Wl>*8jV57yXPG(Sp?=suN$Ra}*vWk^7fONw^}zB!%fU*XxC`N(vZ>WwD}H zI?%pu1VRbbwr!{*)wYfnYrDTsJsCdsTIIbTJw~n2 za}z%p7aO^eXbNbK?Q@n}(O89aoVuGZH+>#-<7?&DK0e??XrFvIG+s5dr?Bo}<>9P@ zz!R2lu7o}P4s~7HGI=|oxM7*q(F9$MwAFb)VlYo%su!z?UswgJxSGpYm} z=ARZfaDG4EK>G*iKzi#3Uh&1L>fk7_e@ypTJDGD&5l04y*6jJ0_l(nzTGrqL1?qEM zRdPq@`p2tg$~)pUd^%*2wi+*Uf4-Qz!7#Q^rS2PEg^$s$`HvZOIPE{bp5*CYrHP%b zX6ANGC+@=-Bha%#7lmFa#&L^A|5AH6pK2ZFkYu6Koi}C-NG4Ngrhfd`5KV?Nj1f>d z0dqwQ=tpx_M`G>Es$s$vXR2a-q)P> z(w#m^Rz~`3dNnZNIQcPZj)V;%qsfM`6fMjfrOhL6A)QG8*~=F!svh=`|DzY0M5}Rt zf3Fsw6_ydU@i0z{iG)0TT$7QPFPO#FLMFl+W@@=ye>0huky8E~YABVp(Y#v5?7Q8b zafc@vKUt6vHq4&!2GW+#D`&YzoknU?=|z1x)OwGm5jL>0>jGe<+`A?1KyH|^GW)(v zB3^J)csAOIoGdRhGXv}I&(mDmuIC(n=q`IeeAA0uUQ1lxR>ga&e1 zg-Dn%TH46LZwr}mcrbNlVstMSW~7R_992yH95O4ugNUS`mF_H}bYkH54N3r5rX zyEuJc(aS$&HP^c@HKh{p^HS#z^$Kjnn@c3(#1_wST63o1&1V}b5^n3~kb#TrrXym0 zgfcxu*0w2vgSzY1E7$mk`}Gf2t@jrTcHqP2~S)<}7?KB_73PPkOSh8=Gj^x^=R< z>{oZ!10EQcc$yFq%8Nz?#ry#`Z^*YiMWy-IUPI}3bhl+RtO%I4idE<7Jy(=nrAk81 zzdx)_ynRQhhEzB75~s)N7dtb{1UP)gT#B7K_>Sug->vIOQq1%N<&doe*ZdQd2#vBj zU$AcYMsp<y{zW;J)J@zfCO}$hJ)(xvHIRw}hVRc!BTNN#oJ2Uiz@Gu5 zd{%F$)hf7-UL|_W=*o;jY|kbcV|h<&Zrod2IWhEo`n^BdJsc!G^hXusQx~mviBH8sMv_v zw*>AsvoGhELwu9hXEi=MhLA_>7zBx9B9GwrABMRu;Ks&T4f-6Rw_i|4oNO}%|=GMDDfDwjcQb_ z2|x4~aHM&>;1}O}q2mMp#5o5$^F?@}j5L#6fa0Lra)*||tEuBouM6(huTKTep)KbL zzrE>Dif5F0^rQ9O?v&AFU)RPTLl4>D;iB+WipikWCa3+hZ4;&heg2|`=gj8X#}z!1 zvRs&}-o!x#vIR)8DiCXaP$FN4sS=}nr*Z4Y0uPhWg=nFmSf$h@TDZxwT*XsbbUThSi3?^44!o3<5X7GO5xRGiBYmJXpa{s!CUVsSAIX90J}3szIycTA-VwiY!H` z?--r`ZqEv+r?0g^A1~iO%$&qhaPet5T?NSkgBJIB$NBz8cN>MVE=(nx;E z0d4X2hp2D(`0QEmR}fpw6<$_qXZ=uodQtlbMJdR>JNbe zDZ@yrEtbUGRr+HXzPGP%5@$)S#XerkxUU~dqOb(9g}UDNBIM#yf>f;WtL`@dqj3RAy+{Vj*^tHcBj8!gkUP|qwb(s(Z! z#gj41VB{||9?tw?1@3pTt{0>Q=-TV;?@(z?f8bh$hf(E^3&uyBZWg6&@8_OG+O3ho z0F7rD*dhDfJRob_meQKF(|e(8h4T6aF2U_~O%HWsK8~!Z7MTZ{+MBBwDT0jONl8mh+n5Be<{> zv!eL#jC7!uDD=`9w6h~z3uik?@~8UWiS>SYJn2|batd-}hsAYAQbnT4&kl@Dd+yo2 z8!p*ahfOny>8&&>Tm}2zu$?mO{SU~1jjh?HvXE|XY0+mVfqPOuQvFa;V8w$X6?HE# zOa)Or@sl#4vUrRh3&8?!=IPo7)zk4yAdHDL2-6ZD*G2$uSUJHpp$G2U!xl^FJjLC3 zOZ2nPTl(p1%~U0M=!rL&A88bM*wnj^VmJS6gSc{fJbluGfLO`-P?PB8RD8r|b?M_` z0J(r#ULBk*?age+zU1su#8p2&$Qj_@mJO2l(KYWXN%0Te$*=nLO&0f+UKYozvC-bM ze=3T<%PyN4Q61Rdth&7dZ!FXi5>N|Afeak4maFtUOO_W-w2imj7eyi+7$qa-zngl; z|FfzVf(^%=GLx~!_B5^JM={8K^kaiBSBd$HZ8vqUaT!_DI$x{M=ub zX>P6p?`#YSU>;ghbash24-E6|g4M)tPrgg@%Y|oim_xnK{_SpDljyKuZfDV1qOz^} zaA%}Ms!4P+#{iY)R>?%H@Awwsn%?3CxbU@^G9q7!3S%Br&uBCAp~_n`;;`xTsv9pG z*}dx#=*Av8YExK*7+E+cK{Yu5{SOaX$D;=~6565if*GcOf*@LV#z^go+dE)T=G>)( zKt`*t2t7S@G3!?*<$2yq!xZnytKJZv`zhdSmXMB(HRh0j$fhhTT z@Ys8WK0i%*P;!?0nJ#&3KRaP7(Y>DQwO!6`XPHp*3Sf}>INO~|VV@IfMP@6Gfmrns~TW} z1;8H*u-@0x`W$-<)kdx-LLPUFO;$}NUdEnjZoN4De|mU7!2FHNQNJf+@9pHJ}I9;}S9kqMUwy$=6#%(Ve^UdsbBRIe<5-VM~pTdb&WTm!mum$skotYe0Zm4`D0+z$nf& z3%-;9w#k|$ng?;SkRS`O*~*GB#s}`?1_4LQ&&IKC+A*o!Y# zoxu6-e)OvK>K86EETf^&tdADo*Maa?yyMbqyyFu8A6Qf^7xZ8%HG*qj0;n{^SuGaF19k?fTxA%NXR@Aq}&X^3-3? zIf5gojS4Nr8HH-U!dlKEsFz6G$MB*Q+LF71T}-q-&cH2M%RAai5)tc2&>7lv#;SHq?W69WjKiP(-Fa@W^8y zn%WzsDq8iD)J_ea59?UiXmY({+{b<%3*E4nMeD!U-iQ7g8b~wZ;AYuYJ!-G=96k~ z?QpQJbwaPYtg~eu4}zN|-gbCcuFmp8DvCPD)uXimR@MVAtn;+KiOX{HVpD*b(toi^ zB`=v|YA>&;&*E@M>#eD&%rXwyn|8qGUCBHZA#afmD)4oyOQlk~u5p%N#Nnu&6BhXU zax7$El;fs(ZQ=3JJi%VXyygsvPZbiL$Gu*f<90SSv1Tbnjw=}7={_wbJtnf*OH#;B zqNB4N`{f|)x_AWlPS5Sd@`PM{V+=gak@WFAnhD7@!@ko(3M_w5ysS!7YSPS_LpM z%9eTx?MvGstXK8oH1j(D9(G0ggo?th>1+B0|FVAJIIuasCX=}$cPR)nMUbS-jm`Ly zmmAJ8dW2HEzX5yrBzNj({&_0Y*}+QkS+kk_)qmYLRL%doZ-?Xgj;ad!f32eMHDgDJ zxvN|G@lR|{J&&x#E($gSM&r=42qJAcTYCJoNw`<`LvyZ{T1L4+nkPdJ_NgBvnXS={ zUPpJ3-(MIty!r)Ez1kpK`mOgBUX(~cVJL?}T=VD=v2SS&H4F*ot_tB{ zW_LSQCWaqOp4%s>|C;j7e14pt6#k8oA!aDuD_m5pQW1<)mzuSOhWp-q{Xa-Q_KPP7 z^KFZAZ%xv5Jl#*PCA<^pqfn$%6;=hal02*>xz4%|1_JrKAJHLW+g&==c$5|E2K~ZC zR|x;ApqDn#8TBLibvh7M6Eo7!M3$4iPX+s5!4JJ1>A2Di6~M-u{)w%GN)|x+7)u%AA0)%A+q8eSLLnIKops1vURS0+nLDU0#DuO z9T-mvNQt9y24x(6gkz^|HG1bvE@CfcNH8#e`GZd;6}1r`t&l!iSzDvuqn0kH;SCf1 zIqq%aa0s5yW12AaRp{pq@N>&mm{=TPq1zxMGX3mLU7g% zmTUe1&7`<4dRbUcsrOnAJw`}>lu+#hD4up+YN%s|s7ayJxUEP6^vw6p+nzdehLr}N zD@INjzYo3Mr7f5hQ=ss2Ht*`B?43MW zVI5CHohg@V`9e$2D z|J2ApWY1npSEz&qKx*mk)e3cJqj-Aj4Bz;v)R8Qlfs+k9ssYHWd4$rdm2sQ3o+CLw-2=1l4H<*4SL26KzlLJPqR= zTn|-^!75A*2Gt=ZjU}2dya-_yWXrF#b=72-t$0O=W)UKTfyw;mNn*ypk2y&}#F;O* zYJ0^7W1InB65%GOu(_~rT!1!SC7*4cHiL&5drb6bLIwiE@FWbQj|a>^iQHZGd(5jq zcEF_wq*_7$D13!pLdvg)$p(5cE4YI@6>F?YYZ=^71OyNmCLqNuzs%W#u?SB+Rgq!s zuL6Msvj#z&PI=%7$qQq+tkG$)3nZ~P5(1TZEu3>00+q?Q;?aZH+%W{Svo5z0#S-_c z#NT}MWf5(iifatqu%cv9pVX-}V2NXy$8_2-8f!6T3fWAp)o9r_itl#fL-M_p{9>4P zcSrE6w{vjK3+2&DDU!eQX}JnYx+iCArjHZRzW3|E?J`ccwS7^`IiB~BT42=1cQHHm z1mBl~iJ=ria^SXuU`gK^s6_#S*5Hd8Rn5`be4aO{NV04;W5qye5-^Y7g^J<>M+IsVMtfT+K zRL@TP-zz-_(k{_@7O~A%i*G+P%isMaE<2!F8r4P#B7O7q-_*(bn1dyE=f@E<&w-`F zhVNz@UlhCSLk1f>#H<&tg~fK(&l&y$LhA`7l6H)!H-|!z6)J)A%J8St^v@p= zZVABjVST5aDBWOl@f4Xhd!s0l#?(JwQinmjO?6>D7lf~J*I6b1y8J#^z-`=>MYUIO zr*C&@Ax8K`5IZkB!pISygW$V7Y*12{arA`J;D;(0J!HTEbG{45k}n%X>L=R0yCDGJ z56DP}s!?4HJHsV{)ba=0@#fD!tUSAfS01YXSCF-=_3OQPN4q&J&@{aKepA2NV4Q+O zQUR+J22EV zW+~nKAv+^#^3LfjrefLiNkXLISxD$1g zq~%`Xskr;4TrWL4MN3q--rPbaPPz8nHqHYq+p|8K=&4ED#-+Oa#f*uUn#wMwLezTU zBP9u2)SVZtQn2WAzVh8cj2ZXPZ++?UOZo)POdcEXqPAFgkgZ4Q#+|}{#7nj4-NY^6 z7u(VI{7f-r?f`N)wz!R}J($DZ7PZ6g+cuf2Lv^-Qz)`SWZ+wkA+bqrBy;0Vn9UG`42xQAB5`2pr^$ zFP?p@>9w~MOe75^$w8A37sJhSvK90I03^^Y67!XA{Eq~DnoN8pq0X~Vi}?0vD*YOW zAB(_x5gOoXEU^ffCpC#SlPgl4_q+)&t zuXweZO-Zp)IRNwwgSp@(mS?K-`-`TST%hn53&0X4Ck}uc+Bt_erTk|VOjzNjvreqm z^sjGBA+Nf^jYHU3Hff$iB?dOt)Cn7y*M9aP7Fyk2>T~QIk;MqxM5P$Nudil+FccF8 zg2o0FH*MbA4ofEAPZwvZA+FmYsV#uLFv>)cueh0UAdP8)#;=EKZEQF0 zyg8`hi6$RHHv%^4DuQTXfI^(ibgz&B)KbN=ZXa`e9)(2Vqc!bNi=GYxJCf;@SA zN|>cF^e}F4}hX2V0 zM8;jFcP72tE}5_SAZD;HDfU1=_NjVGL@em;1h>;Kt9NW0rpQgmiLKs$17e}v4IzwD z7fiiwl3bx1fhUz*XgP8eKFHQN2HepEHgdxj(;xyuKdIgtyPDEVNgYq6{!SXv>jG~? zli~B;$OXj~A5f*aXfB07NB6HVx5Gvz9%=WfhNebInfvDt>ilOObLG@+z0YHr`Oc0? zEWobnD=^I<))B$zd|~6&mMu+9nFN=ZKKYK&82j?!D0`>Ka_}Z@S*nwQ77cHlsA`ZU z%xtA4%uFUc%rsm_kE#&2w3fJ|NcY+$KCU<~p^(cJfLv8eoUtq5CIyiZfMjx#)Q1qe z4)}-qF%3_Ucza;H3}J@N=oRAzsJmCI4VM;9jR-)0x4|tuBLMX1-?$}Z*qeF8MK9=E zAR^`=Z8SbY^_8tl!hCrdW6H)%v`y|hs$LJK+${(q#iZ}A1s`%{p;QheYBaj6VPlOc z)ZPh2@1{{l(@lI&llx*`X3<|s^REeUJ+L2h-V%7)?0we-dEIH>-WvTP`M~L^Q=pN1 z)0HHB47x?JI8h!Anaj({=d$PXT{BY>Alb&pwx)Xe?lH{@7YKB4PAivfTuw#A_Sp;o zij6dX%6zn5$`DJN&-NmW_*Fzi9;#RstP=b*vm6u-pz5rh{cB?NeL{}O3Hh=#)rr>mVr@eg$mmXkgi z2=xfpiu+sQ=sLiEYUsbJm=5z(0Zu% zA|~K(TPIK$DYJ!P{^d!d=M&aQlwdxi+(cMUctMURm4w1T&M0^I`qfyi%B=E9uT`}@ zE4oQ*{ZqR&jzVES>{%E}yQ?iMAldw#sHUIcGq->O$cEY%gFVs4720k4Fx5W1636Ja z(UN<-1oQF|4_N+(ZgJ959isc^Z@v#-H0HI;dk5M(W?5jRPW=|2(u>(HRKH<~MqH5p z%b+<>A6t@DNs0n*%H<=%<8V9Gj(zU+gS)@q%9u#;v%7jLXb7Sj!l)sUJty6}@+V>3 zRpy%D@_fzvD4u5L$5dB0m8*rq!-uN;Txkwo!Ux2R9LQc;$y~4T#wKksj5Iq(UaNZh z2lViFhkg?-e0DE*s1~z$ad%k{+JT5LsG+XQ=nf6L*63b^Tk(FlZth% zRp_0+hLz;0PBy5kO~s5=iO1at4Wi==;rdchz+$(5u%3>M`WQH<0=X@=!QTq!1eA~6 zVN;)0ux?JYkY<8LI~R&rPaod~2=ujvzw=|IQ)Jqu`(C9rf1F@G&MOs~fYO-ct@qpF zj0@FCvss8ZiCM*78&~|N=py;h`tWG!g76%}Qgd0&=yiPu>`X%blI0bTaOYT1ew&2cd?UyoFlB%=5n6GVkyxySM!ZFe)R_rJ!M0Zb^h+re3nRnNdcWv_<-J}u+v zydQt}@qljPFRL`=a-2E5le>Tt@-<#=B8qfGQ&j?VUQAnJA&5T~WhIw6L*w$@$P??G z)6a@MONkcy9!KU^KN++To+z66DEA_nA8;}F1`~>6t6u)=?o!TMUYTZbng9ic$jVPW zjHEoRlj9|!wgAa-o^qDo%fC717^30yuvPlvn$i^om8oy!5Msz${5WoJ{Mv6Bf~Ej2LL zVl%Ogrp`tei+dG8@Gdpkif&1Y$#<_I98M~Gc&&>G`p{={iQza2>7XThpLuDH=TQ45 zy)i&4O;ahe5e9e0`3S!>Lrp)4<~P`Te}v0Vih0@pHFf42)3e(bXo0_S4dV<*n2NRS z(KrV%7jdO$5bXBH5Fux_NoNiV;o$vqK6c*ydLS$p=B2GX5iNzT=J00EGQW7Og!WI4 z0s<3ui;z*#9V&SA*V7}~7X1Uq3fn zb*X)(Flc|pd!sP^kU2cNTLTXfcJN$ng*xNsLOh3D9L3KY*C)=-zN}tZ;o)`ip?m7R zY&K@?M6R@Onkt_)sny!ZYF+1B9O!YK-p4f342jf@J)ZKjv)(Y5lLm81X;g5|9IGdf zaGm%>kd_Byl4ZA`4_i_XkheEf7I&S{tT}Wm!lpOzZZvA-i@gj#{%WbSe*t5%bG|o+ z+Cp@SKnGwG0#8?B0`zk!Pi_O(2}l?@07pmibxpk|!tA(!*gevCW>2gLc>&acVF5$^U*!^H+I zObp)y)*pm_7HtFwS5Quj`5SqTYfg{65=<*?V43f5<;1^nEddHP3DWb}nEGdzZr9*L zf4VI1u=U;EUc88Vy=rQ1H0L>XMNU3fYij|RC;ALUZNRQXlY{u|SsJi3rG4K1UUM;a ztGtv;Afk8L^?zf#8j8EC7Ri{Iv?-*XvnfRO_2MuJJaH&y)w9=!b7jx1>@dV=7$Y!L z+~@Igno)|rR$?7Qb8~_46s<{)2$%=*pE6&c7kofVyaD%|I$f60t&;w`f6_fS2op3JufvK?fDo zz0l1pUVUBe&m4*dhi_*!wyALuh5~#E3!L5n>4wv4V&^A6(V`9-#=QH1TMzdb|HWq) z2L6vvSj^gDZZEy@DAwNi7~iTlu3eZ??2wGbO&qhfQlu?%y&ug7wCh%=E&6SFB~}X~ z%==Ty%>ALD(KsYMnoT34yM0|2O87Te!Mjb7=8o}xn{jHuDVK3hdJ2i1&j+yPO(H}Q z#KEn-<5kprqlY39kzncQ-pXqxgSS(%l^9U4u5+6HKg8=tt^-?&g~yMcSleCtF&r=U z;inc$vb^v6&!DLdSF|Yv0}-J%V=%>aFFewIe(m~KiL8?3F=?~2DESRC#APy?A;UR5enld8xusb8m#-w?z;jVD(hHX{bYUGwhM=uh2gB7I zaI2oNs1JS8nGht#;qu%*FRnp)LOy)|(zY|FFWM;d`A^e_@)5__c`8AQQy))n%$+qH zy(?}LD!Otem}UVYRY=Jb#7tB!PM;4L&lcx~~21b~9iT!Z_ zy&TFFjkhi-SBICGwP1{_l8rLjm>I_S#N;u(IiebL?YUP(6@Kc;w;3U3?|;OphLsGd zvIsV5h*&p&@r)PLOBO{raCyCcxw4h9e?yzJ@{WQGte zM)w;D0$_0ga1*{WC~^^vT1^KKzRlGmjy5f53VIWStv+$21#qLUs+I;8iQF@c#UzZ1uwoK||B}tJt|dBF_qVYQRO`8cGebeT@Vuov|+H5(WB~(|1a@52lW- z$L(wnIQt4xLO2`43rO0)KWQ^$@mFjF zWXX8m5%JJiWrlHEIx6!=gT&`>$-*Hl_(uw*-059W1vXlnNN(>596(0AtZlDBOx6l(UgDQ_?4gP|jmufo~_)O+YQbF!K@FTSmFK!idDu8$#DN>BH7L_{2cDSiZ~^h@`lL%OswJ z?C@`Kk2*#EO=f*l<2XLw4OOZFVcz*0pF=G_2Lm5VCY3@vVXVQMC{`=s=b7#jDrB9X?m)QNjtqQAZ9R>tc0i?^$FWRC8QOxjVzFX!;51u1!3w?KK0Ll(eaoH0rau(w7H6< zuA}76h+xAX{_Sikijue3KbV=lm|hIi`$?DeYVUIx$$}OQ?8hZ+j6J-NH~IcN;uQ9* z6_=PdzpvHd9Ura2S<2H*53Y~4+c}-tV}tB>nX^!CExy=Bd@#L`A#1Wh5LA6Nd|Mb2 zdcK7-3-dIOSiGBa?TE{NH@P62bo1>0VrG2ZiUW27ZGE{Mtby4+tG->g5MQgObG(3d zG53y&ggHi`1wQKEb6y5!9Twv64b#YOb}m^(Hs+WKbi6M+7i_gd*wdMdy_1~s&P1ZI zgvi7do#l#wE#+cy?LK!QB%_I2zk3(zvUi|+2E=t>f)Aq2}+Mu`M-QavQN^Ky$>7mma%#YbF?R>D74bVo_gCFLaNd^VK4{x*V1*dWh=Y`}0HllPl8sXnf?f7kT08gcQh zL1=My6l^cl-FSzyf@R=|56>MO?jdVNWax$|*SidDj36q+I&8#F5D_zFvon57W>KOu zfSq|t-44h+#TWg|QuwAk53jW4yU9)XL!m=+e^y;#@CMCu4zLeUrl9l0+{tu?5^i{$ z`@E-RA6zwznRZOBAwKa}>kd?Oxq&bUQY9ZxD4BbZV*_@EylGkBXizzS3tTkR9(Ys2 zUh3{FyD9Z+aP98)>-+-V7_gb}wtvTZ3{gSDQwDHFj-tnARB9(@haMrjje>Yz+P zw&13!z%%?j?0%XV-9ddr#n!yVi5Wyoj)!7m!kqr68l|-U2<4Uzk~M^5I7Z8)7J~Qv zAyMYE4q@`o{xp%`-uQi5F}Ne^7%i7t;C^L+W5M;fXn&;uUsc%d%0Y2$UW%VS=B#AH zKi3aBGw!(1uFWFHzoo#yGgQj(59ktL!90^l{IRwvTk*AsuVS1JqSR~={@l!$T$#c7 zVfV;08#}B%pNr=l#cZ(hbyJ5}bLG;HN5Uk?NR!p~>y{CNOCFeacdk+#$1Mzj8=qbc z>7pvIXPt0;G(J_SBtD@cmw zRm)}Y{Tu3GJ9q*Xa54(0Cu<4}IPZdbH(wLayHH?eKx|Krx;1*-Bqwt)LkAE&KH!Rp zcf`=e?aeT+Nov`Wr1*Yt^72hT!Ox^huB%3pi#NqU|L9TsLdbwEcS}X-0FyBV;lqk2 zJzX<*@(%Jb$|+d>0QubQVA=s~#IfTT7eC45Lzb=)2QsG_3cU!4P1H)q%k$)Em8SZ2 zC|3IBm%tIuD)dL*a%7@6@(>h{*DIgU%((z2Sz0b2C-#~?dTWu0 zo&pF&jv{C-Sj*KG+;mnsV1w;@bM%17psvODrVbkFEOnBuX{@Bizgp=EX_I8zX*Bsp zacWuhosAMq9MO1nB-CFUKD^qWc5tl{ces|yZVT02`!RuxFVqKb;Rp@%rICWOCH&h6?j+#`WNf>>`8w_A zIZC1I=zoa*dL&@|mH5X*ur(bVg~H$AY{daD7PTJ)8*^q{4X<$L(X#2Z>%*8-c(2(1 zl}ScT{?AUd#X{5$yWG=eM^yWFr@g9evk3vyIWkw3{@x--^}dVpeg+dg#xpiwo%w-Y zT?5!xTc6pwM_(XC0}vhPJBAeY1&Qp!7ygQzGAt@pa41I%o}_L;-Sut;J_z|cLB!UVV5UYZiGBHp7^4m36vO|X<>mkf@O=D% z8b6>=dpm(S7hDfS>`0*2bsA|8{9||FrCo=I-L! zgHj~sH|LsDA^*GX4$&>7sNe$H!=OVJ9V>O(Uq*h9Q#?(!1MZf`{CCIR7I6b7uZXpu{W~I&)ul2V`OHWEYm9v=G91>s)FHwj$zmhsk+yh(g?qk zmWJ~Bu${&#%)zLzfb&+fKrGK!VV{d-uF#i|<7)?nZ(UlbYsxj*d6%V6R5>1V=6 zU@qZn#EnH1*ztA9j2;lno-Z_!!IKpN*IzJY6%|&x>bv|xTPU3MSGd1R_fQ<{dRPF4 z(paXy9a`5emF!P1_Dh<}&e`B3?BdFSs-BWlj;t7!n}-H8?4gjl>QQ`6!>LuI_NCcC zRo^j?>N1o1`hp7i3lWOqIMQB`opO($ZFWx{t^;%)mvT<9 zjJbP%~N9x2|Wz4Izbb{j+4w zkOyr$9}MES=JM_uk)b29X+(1qldnf5%y>S_EOAt!(%n?wy2y#}0HyJE+b!rB#LC+r z7VEoD1;ouOGxnm~!CuN@8QCmt2)T`6mk*O5U^1hik(DV3dhA#pUUDETR14UfD()p0isV`TJ+~*j-XH5tN^i)E zEpG>rwYTe-;@!wGE?#x|74R?`%bzT&{Y z7c7H;(LbM%1pz31AxB2mFP)?o_;#)NUq&*T&mhbDY7)NxSobv9O5w_CJM@~|8$Q*R z>oeVy5BP$uHM-6P0v1lmCA-}EtS*1=PA$=F@&l}}826B}Gxy&@vJAqH;W>WCu@)%8 zKuK&sb6Q1HGn3}S-8GIWDnyG?Ou*i(Ia1xf|Ep`6^3C|=L>PbKfTiX473P}p;6ddU zgHen=lXguT_XCL^$<~wpm*=a)_zhoXtMmH-bd=;eSOqw8|1uD>rnH5oDE6nOzS-_7Fvk{+Y!%tKZQ~8yr%BLLQ|8#7!t#9TlJN9JueZ;z#x5I zok!@;$VM`JjwZ`mkNO)UtgA6N44L^{5{a9be{*pD^k%4i7$}&OSJCjeZf}{^bW}?) z;m44$_4cGT(M!y4V;+ZTb4aW)5{4Q!^^@Uck1?eZTG`2K zqj66(Qo(85XI#I}nw_Psx)T|iT%zuJr#}KEZXlSD*0>tHElvmDlCx!6Zk`t*;kYjw zQ%sB~ZEnRh8MgvE=^3avH0@tI(`XsJ;$%D5^*w%G=Boo#w=zu5Op2j=NI}WlD@Vw^ zndh)OBHv?g`z7e>cMV1@fjy_1fLEi(SG^uY6=XqX#b2hq2kl28CFGI|k(5NbMOin= z{C2uVkmuQ5H#DLM_z6@8gz(p6@%?S(JO6A#Naf8m;9YC#J`8eu%{|I@Hd zY514`OH-DHW4713Q=7?4QK{-N6J0{u$-bxp!RpBeSdU)zk)^XfasIkxh&iUk#AN8# zuH-ys#0LCLp;o*2pyK@n5%5>KxYOdBcc=gxV*Y?T1FEEtAVNVjr#bAO$l8XY1=-$@ ztEtAE2Ln8U^!Y%3JXct?>}ovD-l(fJ5-#6~f69`|2>tW(FemoP56hpHQlHuS=3()xI z&`Hdb(afrjEx;?=4zU4{6Z7J?3y7x;3cJ;xC&bsAbCwsXjr6Bm`!H(kq<#$kSMhwo9ped(G6>DvPa(2)swr(Zz5b4F$s@ff?d*?J~NJe z5XfYCnGT#PZ?j8w;qgxJ`?ypsP6feELccdg1{i`2a)bt|^6xL*W{mdy1(8Azdp7w_ z5$#zt1tcqgSyzMx#2v&EfbSljjEeil&b&PPS}}LFPy$vz8CAVxLQ$fK&B>`%LOPx> z=>-C5wJ}_by__G9efjPs-TXc_p2k)}tEf#$O7cCo1h&8{xQ+>I?5c7V6@y;4i;SMi z2q_2GH~CPjwOeDrbjm!UxK)x(C{m9T-|k;EfsukwN7b~wYM=NCn~80iC0!u$cUo4t*bWf*oxb=+&KD=J;;-gN>o?{rxh)va)rU97EamRDSDT$ z6SZSc6c+I6x)M@r=zLB0_VU_ij#?EiG6&NDoEEWQYdxUArOD$65?`1CS=1r>IGvvt zd*fAZe6;#a+k5D_Cy+kiztt0bLjpap{lo(|{m_Ew1WhK#ChI1Am7ebFkcp`2(d%1;ZYB$u~Wb;_r+G zvfvFYeR-lavNCc4TFCP{kgWc|hH{BPoI%=JJE5Q|IIXk)bcv+ z0N4ym#k=tE4!;^bkO|2EO~=`OS<@}e8@L?G63piMa@-Zor~8s)U$+CIFF6s2#~+3uEUaTAZa&aK8=G8`6%L6#P)aOe#rDn)GUTjjSX2K-xya{Ap41s zhvTkaDP!Qq{DD@D`o&hifmK;U8DhL$Wd6VyW?IVqHYjhPhVj~M(UL#WT!;zSJubr| zEw3m&#faH@em8L6oX8_W;KmhqzC4W%DzVYmZhM@@(rQQ>4DF8T$Uj-}Pz;8)w^@#>t%+Au-w?>AuCuu&Q5m)Y^qQ zwDgHX4@oc9D_IesD%zeA@`|scc2iz&D{ANmaHX`s$>T3H^Ke#q3c6t#m$8!7_U~YS zDG`pbkBJ`mB%nZzG04F+j^yNSH)8SYxkY<(LmtcKSXmvf@La*>mbaL~05xXorsA}f z`IUa-H1dz7M2h8ZJM%7|^*DPqb_O@G{NMaq`%j?wPc6S*9jIp)hCRqh6nyz|_L-{` zq>UL z0jseb0|yr4fV0H;O$B*E22vMQiHBas zY@vXGs=lU;xNslm$3OM41AgBj{e#4j0$4`r$!1ck1>vUui2JZ$EVVHih6;k2V_2$F zY3%)X0oDF0m27$e9FhJIsH-h-9VYybSt|9t1gLYKI=9(FVO;IS{6i2+AAz{7uON2Q zP9IyX%s#u8Qf@|upHO}XxkMj~3>p53kUf7gc%7Vg zrz=0U7Pbv#Fbh5HcYHgD<>!$^@tTosN#(@Xts{?RHa-UDG)*i(yF2Y&R~C_tn`3oW zCL+L)j^2mtBH~*Y%G2XY$bJ{maH$^fuL_SPpxtu?vb-gj<38(_5WOP zw|O9U{zW6E!>Qkq5c&}2MoVXA$p8Cu6ftuiZui2(hEVlUP;_yY$N^FuSHBdMCHx6y z>PGIN#hSm-QSV6^($_tu*T9pi7OWe+`8M@pTCsc`pfWvFD69VsP8pvgw<^ya&Dt2j zqk6#zp|1NNxvU4m^6WFy`t+u7MQyLekzt=p!;@8-ZEp(^zMX}nbx#B8muNV%qw*~I z49l#+WHb7C+B~H`Qj;H9Q3|xhDUClh2NT69s{MC)HF%UaGCg0IrXmBJCSGPmEG{3< z8XpGy>uvbg!xINRIPes-sez-vkr5_yTTlX|q*Fyzakr@9zGtLd4OMel(s{g zW|81ud4YrkGi&>C+1}zv{T0yob7kcB>ciTEaBU-an#w4#UaWN7nHIg!*?d>oqE2kR}y1=Z>B7-`Zb=vB=ocvx#G^jTI(^}Oz3cDa3aKl#x zL;dhB{*RBXV@5thSH;5ucmsGZ?>~&;C8HvC4h3=Mv^Mbnmb}Ci3<^HA`5RgBv`~F1 z{f2KN56Si8U_H%`=79@VpdUZ9b*PhiC1E(Wpw?D^bF7`;GSEe$4zoLDppuVsHfF$a8ZVpP3mlvTE%x>&7V4 zZw~h&5C7D5oCt)pRswq*Ejm;3K30-+v5_j2L|U(V?n82q?jGx13)%;m^0b29{yJfa z@IVWY@~scZWqmbn$dj=w90g}mN-33c8kgS8Bx9gZewKNLGB#q7d|uv!_E!GTT^!jz zeyj!tvg!W(X~hA{0~81{-TM8xP_}9t^G`SbaNXtBDh(K@aW|R$8X11DQw(C{Ah|s> z%X702CxTJeKa`{}a+xt!^!UCybrTUdiZXI}g=xYUnHH*j>Gr+z6t`+LQGX0>Bzlc_WJ%_ZOo}}v#+tmJ=C^!%{((plSa~4t zCW}qUyIj%Xl@Q+L<_O-aK*|7+VGH2p;AP^DiwW`OIpdp{G@DaJ9SCC##A_}qLD;+^ zMdcIPU(*z_^SlWmoOli$r(1T9OZ*Rg>=6BfkhF_kZ+rHM0Z~X?bpA0ra<56H^1yWI zRJ`!5Sk9FC--abzadkD+QWPNg+5R&_BlU9&rkH3~HRLVS z0T2=Jxa-XfBI^K2%ek{MlVh$sHbp2`B^~k_R~)QRsiD}c_kR*r@o0txq@|wrcV{n0 z$yP371A&8Cx$g&nvD8Ja>tUHOjE$A)5)0)821g_aoB?_Ng`ZF_A|GP!XT51x=nKL= zFH-sjniMrXNS?~ZnW^Ta{XH5k*k8;Q2>NT%QfdBVim}MMaE1*~XKToxA|f%q8B&@* z|4ri%^NlAukC{_h4Nt6%;cncM=I{?BQI5U?<=TJZP1<;9{*emxqH@_%IbT;TTm!y#P77 zvqz0`?h8EJD!L9xB&m`i6yN^~fZNc9pb@ck?{E7HIF$htU@m0d0FGNVQVyi&^NCrnrp?%&C8eC1+TgA7BpuFnWkYpQ>txNXEVSUQdK$AmG68~jk8N(rEfi( zGJ@_Bv&JehKyl4c=N1U^-NE}_NE17r?ln?Yv2{Y0k(Zn%Eo9;Nwe=pN^8}4?YWuFy zpJrU(R~dx|Xm+CGjjUjYzFfG5y@|JltoN--fMT(H0l4*3(@r`^wl((_z)kDJWcHyw>*pef}+H8~7 z@-;L=M}y7E-&&w512tdk>a z26q(V_8gUB(#OZPT3m$&Mo#}lry3R8Z@p^HrRG4%tdEngagm6C1dFiN?fo95!Q=QJ z@Nmo&`EHl&ErQ@#k9i`TM@Z&H&}9?zD(u;8$CNJ&RUctyhl%yyzjkj)!Q?ugur;Cu zX!ij|!VKxITb%m$8VSTI_WvCNgxapSb6zbeUGM2S-X!SN8wm8B9_a-h>MF4;VM+Ej zqtX?qy?JWJlw>>Dj}(H9L#!0~6f)eZjPB&kK({mzDheWwtY45W1g`-|z#^(k zM42xag$@E)Z$TP@ypQFCJjj0_wxF0ogC~|J40>v^_t9-aF*+A#N@%~9v@>5oPZ@7s zW44%diuka)3}c-~CLRtSZ%dDTs~@h zPnlhES{EpJ8L2}%y5o!0eTTieM}eJ5vc-?vT4||JH~upP+X9QTqNyXfTVtu3(987bFie>c4=5T91^@(p~_e+NWb(4^s!ncl4^nhm2LJdWWz3BVtlIA4730>zkxZ| zYxGYyS0WOiJ8>q!bXjpz=8OlT`yh~`ssG$$Is3>Zr!A$u$Wb7H53WTYPm8?!#zK6L z7Z!>5hFDilsRv5g(-j6wi8Cu8jp91X?pdsb*6X;W>O&c^az^xrMm1wS2!ju)QTi(pYf$^$0tV3MZQXtoa9GrG$#GEeahS43PeVm@U6$z$x-;#ZB1< zBi7ggyb;(;&9cHYZnTgeN|0Z+cd(OWJ*rky*BgWOAGbvKJIlZ9KjJ@RI#g3J?$VMW zcCrHI$RM93DXkjaTynXPDX-3JwF^pKLhdCK%s$-GpMl{Z%It;ElIBk*n6E8vupMDd zk#EHGPpebS9gKaxXd!)?Lq95GuElDtiOU87Ds<%eymS~HFfWKP{Dd)e6kR9}Cga6n zlPpJ@j*BDAzAP!oM;;+?rYxj?LgPj{*as3tZfJ@LUUX;`PMFy(EmnVraCrSZLQ*O0 zTm($_&eh&G2y1c6m2uI@1x&e1ES~Ny?+*+wvol#GMsF2yI40M!8p0JjBBl?)-GJ^x zaP)VYA-v90?Nqyq?Ux}<8ft@ZS|7)QSK42>&j*EW{#{;qV@bYrnsLlsBOGy8n1od9 z)ffB3tUI@x>{%On8j{U;7jU$Pc9d^7e`uyarV|br7%~88vu?}q|^7T?EvZdJNN(pWLT~yL9j&H zr$Ctq78$pUS|b!Fw+X zA=4^)6jR&lxz;VU9=4;Ae)Z#;@c2WWOJh5DG+UMuu={AKTtU98~aT7K7^TM;qr z&X#sXwN9UEhVATqt&u>i*@!EyZnN`yuyin7g_4LfX1or!3MrA2i@7Q)!zm)e&y3Ik zZlN?LN!$+-J&urg@DUdD;0q<+DT~4Db9SGsU=3L^j-J8m&p;*gr=+eH1zrMm3~M$= zO>{A=JSZEBJh|>P*vC!m(9o6#YRlNE6d|?E-`%nem zv%)`%ELLx8J!W+pBC;-azK`n>7SAkX)Ac;zOXht)rKO#zz7-=Gem(SwDD5YZX=3e^ zQL_0$^aCG2d}nT_*2k=@rNrWEwPjq$ov%e~`dJ2nZPq>+q^WmpX0aM=woati~ z=2`K0*%4QCDG=vp)r^Ssr=IYlJQ(VrIC(^4Me0{no(z9WqZ z$eEoj0IYLLWH-38I_|DCgs=6e4}&g zq=$Wg8ruk5jnenES#P>NkAy*q!CQBIVv-lYJ(h1%?bcGA<0Xp?BC>=tBdB_H9_>0# z4H#9^2>9(oI(vXS?j@5Q`3+R0Z5FGEXCULOn`4l{)f6Rey$cTgnW^hA-W;9Q%g>!E)R22eK&v-E?#m7rL$mr z(rJ4Sw(dC|t5%Hy+ezkI33p%pp@{2Nt_R$mlL5w9ui=vJVp3-=x_oQlM4DX&7~I~j`ig13bv{OEePL^iMh8I;APVaEuxMDbhA)}T4x z5(I-9mldE?^>b+AT_!X19LonAP1DV4BlJueP-dRcpQ@bu%f@LVQwh-Rg6*^#_a}CE zOzC}7;+O_+Wp}Tl5$tXp56~5EsG(r1HzMCXI?ID4Wrbilirn=hJW9kqf7DkZhX1+=(f@T5k`X6F!h`5@n>^3q zzz>$6u-O_-L-iunhAwiK{ZJzDrmo+Xf5tF96Tv2ZhSYoYVs~*IdtrFkQ~T9F)N-&9 zs;&Ja`?}$Lc`|!>bU3S+p-K$;$RSITz*08=4G@c-8r0OE(^rO|vEh1?Jr4)Zj8#x2 zJqeKXw+knDa(d*7>!XiPYjV?mUb>HQb0;4Cy%O5Wmc$O)mia#_hhqpCdeQs?rPl{d zvh6aT8=@RwGFx3lXgk39*m@hOw3t- zrHW*|L?eDS><^0@ziJxtx|6mLvVc5o&LU4c4Ko<}(;bG*rii>R1G=p6SVOXxeHZ6~8KlnWSAJ9;oIQ-AZ0SEtAbo&U> zCHA3dw%%LeFJDZ;u7?RnTvgGi2#)rb4ZDw2-9BCj@I_-BDX~>k(|WeX^O;6NE;r#k z%vc--$#^2X0obgw9_&vWck@1CQ{?JmR1?Kfxf>*M?$eJtcb9R?7)P}w@GLdlCPo;xAFOoieNOz#X9KSg|k7VhABx9d5Xt(uu#Fy+qsa5%) zX#r10PN+-F8!;#Uas2%S-U5r8i+kLIuMnx(;~TZNiK5Z(*PEIFYwfo`XKJVUkf4*| zO?6FtQ{Y=*24Nl5&E2ZXv7@Es^X+0)5G-#u;z z3(>30lF4DKD{e0e!Ox`KJuw1fHdQ!kFKm$WTW1m!<-OLk8rwJ%*JU^y1{Y6{DpkzD z-HF-6bpmBx08eu`B^7dwDS}Qd@|PuMmx)VOpe|-w4J%M|l=~~O zc!0BleHfL0=PLy7o%shU`oi@Cs{8EM=oHZ&NKRxqYV_k0y-NAB{tLa*XFOLgb^}K` z1u#PHhD#)FaBDs`0P;%9Pb^9{vCTk}+F?fDudkMfT9~Z?x9N~aQ=9;A>GL2|Ih<#w z9Gq2JN_@95BbeGJ4e&OGTtfz-$d zM}VnjWZv1RtS!5QlY-!^6hwgA;M)Zz_*<@#qgG8DEMR+0d$|y_akZBWCKOYFE8E|p zn}zk`#QtfCUDQJ(r@ypl`5{LY9DQ3E6h99KFNmY`3TfoX>9R|?5BL0fIt1xk%WMnt zB$NoV=h0sV!!>CFj4|0&e3QIwZbr*d?q?q5-(H`MziQ(MNQW!p zkwAa^e>}ZaR9kJdH5{P06?b=cE$&v_wFE7$MM?=SK~svmI}|8x#kIJ#xVyWBFYh_$ z|DVe}GDfcU-0PWZ3W-9Vo)6c zcB>J(9aW^o^rFoQhnZq+`XjJ&!Tp3xoXV%ih%E>m7UsvV5bAAlUO<{ntTV3%vCM?g z_y)>eU!AW0;&s5@*PT}#$cH54?{M1t0{dL!2zy*eOnqv@)9W0jX?_&{0@vf=DMJx3 zj4=rM7f^5VmktUi9MzrsVr|Lkn53=PV*_H#G6N4QslfKwli}H(_7kSmr21^`>zKjr zH9^HiH-P^jry4jOHkP8A9uZcjPK+Cyw9cr(fzjT7H{e8im@Bxe2;i2-%hF{%^i8j_&$02XuphKM^o#@+;ltqJI;dD|G!okR*eE!Iwy=0iq+T&G5YiX zy?A@H_|Mq-ux7}2JpmIf@$o;}S4oPV&g2l7zUz^uOsAW|t@zge$8DUubjLI)X}ZhM zGX&29n%(U&D7`SnS`TNcZwV%N{c5~>xrFZx9{%yGR4tl>>B>`GZ9<1@NU*$bg+4rd znP)X^8zNQ6n#bcMfVQ(r^_q#1rnCNMU7WhM*JYW>h%NOlzxFIF7XU5OG%; zU(A;FUhn7N&}XC}E90^N2lDhx$_!NI06G$)+W|6-FR2(s?A*eHWDUCNBXx#Nv+)Jk zpSz8eCDfcnCNa4!GR>TkZLbn0_xHRrNGJu&Aj;w6R9<)kJcWqgr9Gd*?$w7Fk&iE# zFL7^T$v+JCaS)w*S?Xr9P0`OH{Ytr)S-ky^DMH3o(s|RSR#Cz{8n_TD;78p23YM|> z{P%&~f|J1F^I#zXLl)08IjVY&zZ%xoYh8=(N0EJeYKNjgo6*)%dOn_XG`YC^$&jCg z2Od_y7(8}>p)%+FSLLHgdF2N3`y!4m@@4cO1FOHj-Q+?4_-ofe|M;dNJju%6j;V(# zEi~;_XHmbPs}MijJyy;($G^I+p8;MecI%ycnUW6{mODr=P{nz1h0S&hPuDg5Q{KniOOa%Wt({|XA7@;pj7{fnDu{6(#lvemAvOS1Wy#~8 z@oc7le}50M0Z8J6xw4ZeaJ`Ov+Edl#Pp$v&Ca^^Ebp2(nt0Frc*7=8#M+o4K;nAJ? zbUx12c4@E6=t-kVk+WgSgn?)7>oM;g4=30e5{9vF_;F12C zjzxc*8^r*)t=5L9JW>5@1q3PMtxgbsDQWtnE-GxVxF7Cad2g4?Orhr>ms({e*S)%+ z74FY4^Rbevv+F6~88+2pr~O8 z0Ep#bk4??ktno}J7VEr81e4}}P0#i&fyLf3c-3QAsn@j){arF+<%lc=4xGUv%{O84 ze9^by;644j2I=i&o+EzU2$5B#u}uylfLKcx(grlH%0`?Bo6q(66FVemt?x}-6L*2F zbFoJmhT{n%QR+NYQ${DS%AhWo0s^+(Ij0Rv$>CB!n}cMd0; zTvnW1vTE4Qt&UpT`%^$@*xi(Lad_3c*9{p0q=gd0c@&Pgec_^?t}z0!2f=D#hbkD8 zx1WlBp02U{A_T#no}Zyc{DMm_wHhd6Ik^iRTN_?PNaQ7V+rdf>bWLOkSVi7nrKH5H zpGxX>hr^5EI?qlWv?yOYPa~Ra<9Hy8MLr=csXhwy5ZJwsTOuMNk!%fgTp8;bG1Lq) zX(<7KCI{4ghJZxbEDJiG3Lo6ucfO>J#VTJV!4F5@AWRlyI$_v>!w`{)1AEA20F{hJ z$hp~-=}ldq|5wHzQW^RGP4O5#%T^?-6X3qd{*5HA5KC}-BWMlyp_8Rcc}zIlB-ZKB zpV27t!xclI*~c{Z@S$9&c}~qo5I^C@kFf(w!%gv!hSik-jke=I>OJWjU4zIxUmmH+ zWJQ&L8M1&u@?)8?8ONL$X9Y)%ns+6S(}qq?U~ZmC513hhlpAagqkh=B)w}{<;sCj? zI(3xY+;Ky{hYj2e+-_#As=nR;FfhK}-} z4QraIwxk;^=Jhq*+aeWpt4C&kq6HkvXWQ;HeN9C5{sU&eTy4qEY8>iG6)n6}DI*-S z28_-1eu@Q7lQ)z5g$JAjy|4j&6w(C7(~x%tPz1tMO>xT}Qb>*0q6#(H6KCw11rL@P zvRdNtPQy!;?kt5zUc%Kf3Ch>sz5Bb>`o$Kf4TbrVGy+Qa)-l^Eu5Z%~LqF;Vrw9Hj zF28irQ2aPcsvOyujOM$eayIgKU=T&cuG^zUBSmOIj6h#vE z8K4Hi{prj#$hdb)d|J#x_`J`zy|5@p_gn^}yh0;C>rE3?j9{Zo<1c5U>Y^3oE7!Kx z)U>>R#}#^x0&U($G~Ip6NB++$OC1r>Tl%xGq_n zK;`(xlxu5;@sqD7>pG*WU#;`vVFcQoG12Nx@eHEAIS1S#ilp!Lsc4MY+MTX1SZ>?U zUd?%EoF@R2U241}{TYzXznUDNwsy+7PO97}nny}x*2*>G8Weng@QKYSwTSLHP?@c? zyNoo2j(T;K{0pMTgK^z%Hdr=j`g=ktu_Y(?jtVOjnTv;MCirdjfV@S3F6Y+*oi*ee zmc7tmXc3#%vx5!X?>$mL9EhK6bci}f|7Oz=u^~Q^9N{=>2yk{U6 z)sdWqvSdzl5(^DZT7g#cyKG1<30$L*-8%_kRbv(*e1OxE*nW1a17~!^cj;0;=hfiX z+^t0T@3cD8435oH=Z)UhnTs^JHC>m<=c@*_&9}NIb$j^Apfe|#j({pJVs|Z@7d{zW z7`j~40LY>tTv`$=x7i^U)5QA+>;T-I+;S9?M5-j9}P46(#C)4YB9#S6O z>whT>|2-Izg8i(}vB#x{_y<*qA3_q$3zc-pChGI1lDF>D4vXAPY9CG7&Jd~NrJL2& z9a_FtcVRZn&Y<~cbQ%^W>0T5*rA}q~7E?#S>MMBnMuG;wNWtP(^QVwD@kfZ*_EW&1 zoXbW^9^sG^R-bKC;J<7=BM>emJ0p(|nnMfwab0y+yG7v+xw# zlsskH{aD@N7BBMWc-yd=UAh4*!3N2C4oDM&QeKE2uvgE{!#28F5+Vi0L69KZwH=x z>D`n*bazlC(~#iW=~n4(%gkqkZNR%k5KScIwk(Z)TYOQ(3?Y$EUnnY2Fvtq0r2IgF z9$l2zGp=vNzz^d#;w~e#<3YwB#Slq@8j3stMW_P<+XvgZaW;p7?>KRptUiXZc>GYL zts9Ge75HD)M*RQ!9kS`FVNoIsjF4h@gv&Xfx6*frB(B0*0&ks?tnUA{5N;BKJ{)aO zMaNZ^Y^c@lyuT({KY@kdIuffN&``y9#YhR@c zFNW?u5%(h(qFADZ43Aw`BpxQ&HC&S9Jk4NR!vSkE8GnQ;>wJ@f7D%|Rf+MK=fF6P z&5Sj&@&h6Dm$}QnGS%;YRopP>BB#e%g=Fz6k5hvFoXi?%^$dvYBBt<{Q-2xB|?<9#1QWGqT2nMnu2-5=1Sz6 z^F#vly;)pSkkW*f`CIpw+oh=>P08$xmA>ai7#EutOJXUeVd(qy-4hv8X`+DtkDN9^ z(ra#i|2Q}uFt(%r(Z;=}uqQ_YDFWX!R1 z5|yb^yrQ^Kk+SF)^wbKt;kmu&`gRw_@dG>AxBJ1f-`)#C{9W91w)j1rdV zmnT3WayQiy5|y|VXRQd0;Uast1x9hDEl^NU=&AM$P-ptM9G02V&+$=xq}6#dkQm#M z`;OeP+Nbkt_gBZUoQt1+_x_9R3#OibM7kub)OP^1GAS6IXrUJzCU?qv-+17^6*;W( z28x8p$i-DQ@tqSaXBlL51Ff+b%N6(252LbKrOtDdVy7oFZ5P}%WZMQeIiH>5ax+8JjZv`LnuT|mA ztqJ&J_Vu;qn19qNpBsl7fH>d#v+O&a3rCP(>QEXGA12XE<%*q<(7EBy59Q`ZdMVu3kk;0AwlNy z;iTVCK`=XLtW{mfU36|~`JimNUT?8#_viAAPYKkpvLRR%yg~`InKbC*AlO;1)v0C| z7V!x#1c4x#srf@jSatQ`QuBwu5zD{kU5$xNh{(PA9Axn|^>}oID=Jo&IdSoJ2BH`6 z=I@7C^l#7149tva85vZFnXvP+uAoQVSSa4`hMjzCQPqBA2TKy^^zi4^_rw$HK`f@7 z%nx#0ZbfO@1E)>M6UN2bTVQ`I^yViMxFkS#f8n*`L!>3Y$x79;jdXRN>U91GC@mQ_ zsTVWTPs5Z4aa}%RSP~hQO$7&D#WX25DthAwip>>k z!`FB_CXJoz4WH1F&^<#yJ-YKg_R3#a=V@rII|7OqZ_Z<&bMV@q|QrPx-N;JlOM{z*@q11`B;uw5|S~LKDW5E6!6qH=blG3Dw z?a62!c~-WB=Nz~PB>;#Cq<44CYw|!#sV#O!;!|@IYWEdz9?h4lkfgc}JO?2**1Sac zukO71T=);a`E)ZMm&rtp^bOV#5{-X|-~MLpllOPyTb@A>MHRKc8rszYnw97Vuc&EPfRwG~>E6 z{Jc_U;Ho%4W1KHB)L0_c+>fKn4c0J4X6XWwL+)K(FjhBlXlZZ>t>A))!F7P3X070B+k#iv-LcS!gu_x)o(j?GVAuKfvY&@R7D@!)o|SN-?;uG`WB6iPZB zUJSQy>KiyYjrBYRh09d{>cKPlzw67*H}y^g{Vi+gu8ELX4hS-hZ}D;$UT0!=wNwL1 zS=Ww(M1KC}^*bkmk3!Zc4k2_Z*vyz!|MF+TyC26)@q#tFfisr#bc8NOm_emyHC~z5 z4yzXL;I)Z12QAbSeYIRzD(HP=SIoeFcUgN(cbO{Y!b@q)0y+OG2t`%}E|kQzdLFSZcZ<_QXokpmBpw=1< zq1;zc2^(Olz07|ve!gN?oebH95j+0-mLJK*D4Z&?jR3yl2@0_3GpBAS=o*sAANDdw z7eyf)=0twii-6-Oo194%>{N|0xo!|0plE%HB2o)-^B@T#^HqocGB#_ZPfI^S!P#`t z-LcB#2Q4 zKk%`~zhkk%3`Ns}3lav|IT;Nx6HnvB@-Tk2eUz&vwF$AkbTJX+ikSl9ld~u;CQKZ~ zpMZX#qyYZWdmv{0Igz7se_t4aw}MDkI*Up3WzRpcwgai(_MTS4DhoQl40|nhC@Kp~ zxX^|CV%$HPIDN-&B_3-YiS8gPjQ1M1BNIyw^{+2NEm zHR~CWob8L9@FEB${VW$^1f?5}eTyA`a76@|V8&uTCYu8iKi{0Y@EpCp_h^7c$PKdJ zbNBT*l6eWe}e5>X; z@Dbeyjut_f_L)?X9U8Et?=bZk3ztE!p|3e^^!Z@aol~KFhiTfY|8=CsWf#!)Ev=6i zC*7VB!gA6%T=Y0eaz$4Q*ZQ@TuDj&~=Z3Z&wcTl;Z|1a(UBO9Uhc;0+jd_eB(r_$_ zTBNaxtbX`4WM*F8F}~wdm^Wg{l?|O2V#4-_5S(dNj2p`z_FS&%^+`yu9}m9N)XVJ< zNiSv$gNpxk(YU+mSCOmfMqM}nZkdS`7DVxJo$Ci+vY4f*T>y{I+q_m} zRSPh;`ogy#zPI<-72144E#&kOe|dvQsfe$a>iLi4%vb!*o(9*92S05^<*xSa(Qd1+ z{&}y(yVFp%rrM3KO@%n0eyp8TUK_Coq|?af+g!MX*^)QL-XSg@*s_%UByZbcv)z(6 zaoqT!Hzw)$SGgL#JcgXtKRFCzQlhRyIwTwlIhab0ArLri2p_z9cCd$?C6r(AK@kxV zh*GVc+ojzJ^UMzD6Z;${{02yM?DFwez`%RF_u;K0>Av>M)j4F>#uA3=wBRTm zCxRWmCelb^kE_ey`7Vwj!0^(ipUvBoyC@UyJ$So>c&PXeuBwdA zkq&XIJ?G(Hc4kWSG%67cX5}N&LD zC?H+k%+_1a3v#wgwIq*QWbUaWB%Fc``s{+O~^;XaHK&}Fs5=TY--!jZ)F^>BT& zmj~QpY>r$f#4wq@5|0{qGQSKKViEqjQ^^)<{YTo=f?(&OGLon+$X~XPR5NxcVbJo2 ziat@y)y3nZiy2;ml?oe; zlKZfeHS4&#H`gm(*i;s%M!Exbeq^O|&;z(xdSeC&$Jl9OO0fejinR0q0AZ#5pn}pIXw8=B_ zr8o=T(P&hx%%fVxUCgZ&du^9C$-Alv1p+_ZJ#`Pzx(`da`*#Fx2$;Cd@mY=rPSd+c z8}QwkHqp&bZ;M&gJxSS=&iyQ|Igw829&<3ze6a=|( z_la$k%%P1lJhXqBp%8`tp^zLYppHLgU5nBkrQ|_dC$h=dy}kw?q_$##;^jWM;h!5Y za~hYY{o>bSzsZqTx?(gU)lE4F=Oew37c&D$K#+Brr2;A!Y|1q7WGIiFU{gzfKspA3b3^KO`Y8rfGvg z=DQZoYBA6pb?uL*C8QgSqks^kfO}(;O>_gjS3yA?w8Lo;L7IYJyO_sZ57->uffzC&p|b?PtHSa z;vtkIeOEGm{2{j)@Tmxi8vAEN9DVpxrcE`~sO-f=tIkBotf4g2*xt}JOtU#rj z!%TNC+A^COu02;hZ-mw8$yE`LA%UbID_ z83O*WWlRJcI9DpSqKXp78LCTh5{&urIHs9KH6AJyhUgk*qF4qb9XBy+AEFRE3snI= zu^{4As3p=%-M!-A2swX!7tR?o|1t&_FejLsuraJ`Ldqh+D?ak5R5aFfpP`GP9RdP% zF1MRwvB$GwvCLYeO9$4kdV~Wl$X!(F#M3T5#cyF(;QAd&LWxGQ?3@-aakydcD+VhP zHf3-nG}Wn4gy9(+-d?xhGHx-|V(Y79F=185EnK+xCkOb5SYA!uys}zt^ZOkn>~GVt z$%Iut=*|!oZ}cYZ6kyN^9`6E=!ejNB_cIrC zH*vmb)JQLbq(NJm#cBO()8e)E(rX3UdMw@kHih2ZD#gEVO-=o5-98#5_I7WI8$IU7 zO}RP|SI*0vK_y#)8@i`0lS?A&1ZC z(tACwEY`r+J=vE~ma@PyMc>h-x8*A1Y@yth}r7jZTbVa)9KsofDZqV^sm4Vpm(QwOzm(+VPCLBkAJ>H$h{*C7!0!>s~hD zq3^;1nQy*Hw~+|bVK#$FVo-U1n162y;F9{2w>08AlI1co=&GG6(E;t_8CK1;l0oyJ zwIx!t|CZJqIHGZqkW`EK$3j7`Cd2o~5WXuq;R7$_y=MxmVhbZ^x%~kel?C)J0akfC zI-V7x8Qa?X86~A*71t5i_tNL4ozZ3101uy+w0wKVYUD_Pa%;Cgd$Qjg)Zc+u;B#t z+qB)s*R?ef+@#I2!-G7EqAlLg8Yd8710LD?$WW`^C&}@ENFHNNNGeNvWulcN<(XFC z?u|8T;i8fO6EtOM#{{)z!#DS6Myp~`!;=Cb6)_bqvFvfg4j1qM^AvOPr)gB{WKceY znyWnROO3tV6Y9R3oUyVR*3Y5ue`^h+xjZu6g=NM)W)f5pa=XVRA_!&Uj|**9=rt#n z1q!vV%&GUoD5VMh!5}>xAI~^HlWz~FWq$yJX~{e~30H;dy@g%d{H;dxoV;tVl^3+w^!8r_>!jIjNxO_0bW^sk})_jaNGy3b@C- zUVdR~gg|&RCp_ZLOLbUp&4}kZR)II@(tYQm?Yc}@O`d9!u!K%$2?hvPxvD$JxkRmz zOa=Zn1RiD8;8uB!V6C1F9G;-MIaSnya2X*K@yU$~&s|4d`8;-69vX6J>^AiTu|j!vCbJXxT`YYg!0()FH~pCzB{1I60-~^E z>+v2|2OILT|Frz&8~XJ*qDeU`5)H#U;q}hjNOsT2e9r8U9Z35qfiG8wCjHx{KElOs z86GtAGHutTyUBmNZp`RJt6CAyCu^3QH=Rui%RGg>F^BYblKMm9*MD4%(^UxA)-*pY z`HHuyWdm(o*N{puw)HoM%8K3Pixdor&xDK9$VmV#Gz+L!;+Px>YKmiOFex%~|2wUh|4O{Utji|62XZ zIdS{Q$b-ACbT0AhY&EH(rtc`bnQr6+{Ym& z7lY8pL(hDY^Lq&T#rvN9ue+i4FqUDb>Cyy=6%WiqzHf}kuy=V$>?#}yLvvc9x+QCN zvvLid!0LD+^mb1l&P+sk*}lC`wa(!^)I^ipFdpKzz8b^-zWa?U9BbXTotc&9do!?6 zV~O?>Oaophth^-2udtv=dPF5syyDA$h|XPz0jjEms;(YQ50tSUgtLN2yQ5z5EZRe9 zh4Js|qEFsf9rfD0@bjFF(NsyiB-|)!;WUd3CnwkmUkC^AZRBG&-r&~g4TaT(>TzU(X23TA9SE5S7ND`#6Gn;xhMNUaL%%ax(eOil=V1kZ0w8)y6x z`Sm`S#O6?^X)m&hdAjQvHqe%duRySyyFX387n~HCCiqn|(_ky1F}N#@@_oc5tt!!0d-*>`&Al@c(PD1;Ob6Gl`2 zT>=_(1Ap{5Iu=-quv~Oh%T|R(g(QG(YR|B!0Y3K}j0U?jCBH#svGP3SzI)hE+|Lnv zU~BZvtkZCgSKjc~Ty%h(Q6H(?Q+Z5Bp|6yI!j+do)Zqc?e!*q1Z9*y>^CIjj%_A7T zw>v&z{?K6hD?C>yA3)uO@3Q|$xv8`4sNP?DSwj|_`R-~rRj?V5H>$p>xYHCzEeS>O zP@<9T6vtw^nT)Xq#TW7}`JXnUQG%m~5dku`*C^8w_|_()`|{uIr|W^Zd;UYezlaj? zh4aM5g=tkx$$5=;BK@we1!l6?l(x(Rc9=*N&kFKM0d;TRs)L7|yQR$uB~sa)efV$S zi2AZ)==3S`;C>(1MA>_&Vf_WBeE+1nXJnt_ArWGhOCU=|i_PN2(pmMnQn&5rBrs>F zs;zyAmSW(?=N$@Bn^Ld&;j&LGui&o78UjFz%Z$duhD54c@4}|1`Re=sM(`3@9jAAX zOz6@s0SY@O3w+1ni=<>izYt)YN(zf_&_X9!{|o#2RpS&^jJ$2YVP)Dcsz?9wbFT7h81*A#qn4DX@yCzu{RC7 zH-j|g*VL{x>K2lp#ngptKygGsWTYcNEQfqGOqRy>tZl8Qeb2ltK34;sAhk@LlaST2 zZTckBHk2d%`WP$qrCvP6)bK2AL3n#9{VHk~V-%#zUjj_D8}v)=qmX7C1;sT#o6AVNl6OTIDY9MLd;H7<0kMARxCIlr-Hhc`c>j1< znvGr%G*R-x{X8e~V&nMK7$ z80(*moStU#Vfo7f6X@CXe0h+IO(8(;IQp8%5%569atQAncs@A!aQeJTYsnKscx`9k zJYDr*5~xifJz@H=XTf60xbkvA#E+1DYut>8N#Xr+b5Dmkpd-vc$Ajf;+koGxzm1{+?v^Ow?P7_J5dkV2 z%D-5D4K>?2OWG^M8%sV-@y1M*VqUh?zpx*v*(nJbBZ%^1)`IJU>T_~lEm z$H!)aSS@2U+`**MKG|#V1fQn`4{1Se5OMVVY236%m>oO5TWUZa+>8YlPZ&7aMFj&5 zVo%9}kCR@{xR5a%UzS;>qZ?KNAC!JL;@C7-+yZ=DMpJqir}2!P8fFzVEb)w-zExstcyMI_3ikx*I_hZqh!N~sSfP@6bnHLI~QM`_XMz_`09oqXWiaNhu$2Ohc+ z&WPobL8%j75YQc$5k+CO$wj$)j{waUA3(n zG>kfop&oDAd?jYxBHR=3<)1~-!k?m9RETbKGQ=bYhe|(cT*f_t6+r70{^UeaJ z?}EM?5wKcNiy{`F+j;x-5tg;tSf=Sjq4EIT+3@#CY z;aMl|Qgsy?7xE%4By6?yA!(wL{OmoiJoGwl1z{G_?t{jwN<%yJw<5?SmW&&Tm^Ibu zBQ0Y1dkMDHQR&(I6E*8Mw&4g3_gNXp%dUxX4iLfIDiFnxG)qdg?!EOmg2b+#Mn{a zCUmiW#0-ahT6hTZQlv{Qa3-%YPHw^dG5v69y&F9L0izuVZW|fcNd36z#FsHOI|%40 zk(s0^Yd>`;{J8)WIVJ4r{bn1={@Yye{{D z^E%l5mCFAJv-n`g1`ZP2{5RyaGq4fkqft8TJ`4H*dc);8q_$?|SX%&%m4%8?7t8vF z{+{Id`lrnaeoOS{+pO5!ko=pD5a|JXHhyi1NB1!qg5{h^GV+n8kXBWIFX6dbNw?>n)wm#W`J8VYi!H2(;ru+MGjH zIE0D)L%hY%vYpt8z}nGR)34T$pWs|DrF(Bm)HXtB5=~D!+S!kZ!_k)r8fIAy^j5~u zFPS(j#Kxpcu_j`hs-P>OF{*%wcc0X@?j=^x0HlIAilF=UON$69MSPtWdq-~!L|_)< z1U+!;B9(`o!1L%H^jppH!V`;c3{@fb<+Ph8^L^{EIb*ME-#F!4bUhaCzjQP%Ev_bT zD604EzxCtDbh$FA3$g%Asl^S=~Hy9CEi2HR&EUrZ<;Nz2-u zJk@IG4nGR9A{Ga3Bbbd=&Y7+7Ytx@ClG$|UTYi+9$UREAu$;)L&vp|(vrtRO;<!W3@ZTXT6I1l&8Qa2*AOS|PA$-)$r*#SfMgjc3z zMP?*NyX2~0jh99g%jTYhX;bB=&JggLPfWCSTZ)O*jVMNpB#`^_DA-0%?KPq7Kq4)pu1l%J zqb^P#<{)hjSX<+OY-p9Bk?(7B5+`^&^2aX%ZnQCZvHwGB6RJlRTiW|rVqzGz>?Oe1 ztmcJ}e2yg^MJW3&KdR0{D|^^&XL7#AH}>-9q)foDTUWAV!KbJe_5pS`1;q8EU0!{k znl--JP+K10!WiuqlbZ95fGiedtYynQ*6z^jHTjp9(P^(y+;m>W?}nCA!t%sR@^ENB z;`qs%yQmrCytBHk1AHBnwjbR zXq87oeVXC1S%ELDm*d-FG--1LEVDE3Nd8y-LTtd_sFfW11{*n#H#KXSw~pbat;9p& zu<_^hCqzK*4eVlax$slE#qw5_)$1jz?yXTFnoj3!SMsQDUR^}r%P^s1L@VxH%P3CL zIt4nQMCXm}9JIak1~Gh-qHcIwRXOAUL@B5iuQ%vz%z-3(Cv7+mM4{EpX%aHDUKcs# zGHZo_N|o01rp?YsyLV{yWHE@R*kP}QE5W^KJHk0p6LtZ-gDodH6Vi9vAD$clE6^%U zl3bE$?bi@$pI*70v+U?`?XpB!XOX?V{Lt({V)L_lRy+2EQfXm|KnVn1BESJ#75p3= z?qq|~5-w%JQTRCboGAQ|r%;AVWc!oD^XCf1+&=q&grgKvo`u3T^ub+asq`A>_|HEfRvfFU&*VgN^M6H^likB{_&28hqvUV;J* zAh)=HOfG2@+49G5e(8tD+s}qN0oT9>^Z}dt55}z}l#sujZ~}mwP>XuRd>+qB#r;>5jt9=7pdH#`8c1; zeEYiP=wtp<;9tVOkmJ~WV3BjK1X`~{8wcouF1S># zeGPyHu|gxuAsVZuhGv+@H{_*{{i6JfKSS|ILmqVu6_ZeHW`oQ5%6kV2IL zy7T+ZP_~1Y{puNw?2;@z=ZmRsDM!CVF%&XV(h>ko1d8b0k#h+j-;d8RZi&>|f(9Nf z7+e*iVPNLMU%^o*-ardm-=SAX7d@hF$rE_;;MW?knyHeb zR$Rj(4;5gnK1OjW+=ZvK4WOV=uiU>eKh2ZAAZKB-@UO#*ccu2lIQYk^utJMXLHywt z*_~?h^=hJnp|sF^HrjLg?@+$1Ox_TCfUm>QeBxZN&nK?GUZOul7C3z0Q=NK|deXBV zRAo@;L7iwT=%2nRx@@ZL)DTPmvi9Gsi!tAs>cQV3e-ZXDWuX067q9l}BfQ#8lzwl~ zgAM@P5zIzzR>;uV1|L{pm^Hs9Moxx(WGp;2aAN4@T5j5gqy*n2S?+mX#h-8)@ZXO| zOb-9E8>1BpM5~Z+e;UyI6kNlp@81KHsLNfj-Y?<0t6;4E{Qk4D$(=+L@wP`P@my0) zAh+?qSZvmjuc#=<4W zYzo2KtJT%exn|bwqZx06U024ihNCy-MWoUXSd#N3MaB`;nkag-{(7v|1h`q{kOnyc zt1%x(<5!4{97)pGCF5ZXpI}S1aM)KC*%5yq(y97-0{y$RtbTlg(^ z;C|a%QQPDq76s|86{ zYmAK&wBxEzf0CCvi)0yI{eYNW{2n6f+{q)9KsMZynxs9RTJBrp*%O|lxI{cz!<+c^ z`)5)xFB9>kk&bGn{WnaCX?oF>VkiG=0Un##7;>RBtOR=UgD>8*v&k+-Y&+3mNFWFT zlheK*3p!=Grx=OQR_GY&ZiW~vnO#@@`>Z_npTlHNiO$zK&u{~8vmUNtTN<&rHLf-ms;MX_!!SZIDPd78HlS_fX%)ue4I$dH+ z9Y(FA+9lviCo7AJR_gCbV?Y>-EKxZi$gi|Ca5Y85w@AQ_SXXfmac5|s{wi>cN zIAM&IvK61nRQ2$4jmGtzp+ef&p3u@1>~M4a@2XQ_bFup+7wnh31R@TnghuU^I7v72 zCTHw&?c*1cIyIXWSi`5xJ05(DrnLnCf&j{L(z;#tj_G3pf8y=E6q7IR0{q6S?4AQ@ zJ^al@ye%-{L&%eU1mIINHmb#U`jbhjAd`rxwb{jP z<=I{nVSmK4iyGyQhe?0Ha4l6XrJB=Y>km;qRZ07CrTqL=$QY8=d-=61a&#R&+jhhJ zVMW@AK9Q-tyW|NUvRw}^0KVp~tcp6}|5>flSV`s93zYLTSi z6m8GSUGzTNQlZh#=J!W!X^*e_)V_sUx9hxRQ{{ybzOe>)9%?`pRN1Lt#5=3y0>=yY z6>Bt$J-z6Al3U z3?j~DW1BTp^(`OrUj(m`(CO}qbz*u>V+OMrNKkIwR+v>&rFUKN2VJq>7CBLtKkG9- z_HJJf`#HdhT#jrUrXB>$fPh$_#WRp6^)l%0lJ%ifa#+ZebPJ zM@^x5dL8xP&NgdA0AJ(vga83RSNWzoXk|Ek*o-H{e(5CRB2cD8#Z;I2A-;&yB~ILH2cd5n=B#WgF!?no$3rrl z{xIgz*}3xi*(5io`zo95+;@#PsLH>I+M|Jqw&5*&Eiohn)$2jE>63IF;-+sy@p5Oi zN2|d^Fz@g@v3G?? z>nDc4oEL>t5<-=LJTC!2$g?KA>{C`UT$Z63fID1if7t7P06g}gBYv1&m-(b9xzKB@0On+=Ck7gW~#_2%FmGAy9$6*JYNIH?T%7 z1mr=b)%fS{TOEK}`)$>)1AhVP1JXIOi%o5--61uqNx8D`gsE8Wxty4vC3TLd*sYJ= ze!vGsm&CArn=ml+9`F)%2%)KS(n4>BYl*p$NJ23>sz_qlwnSDSy*@A|y7TeWazD z9n|1BnN7ABOu7%FYzW0E{dGJ)*2{9K5=W;6R6oRQGNz9XoAb$P-wyxu5za zmQQRZ^LJT0TE|%Z_&vf{17nta8a-+~0q4#EaKD)bp*}W|QDs0JFw(5juOeJbf43aw z<3e^N#0i#c2euT>{p-h?nT@Pd+?NQwPrQD`sUnJqUsc9J*wcOfosG^U3NHsP9JgZinXmb0N;3!CZj{soETj3ohD8c(7t z0u=6Y$=Cmb%KO$YUb=^V#q*z|;idMSt2O-)16o#_@u*g1K3sZK>Ob1F=9!`l@Dp_D z?ys0-D;H2T`7E!D^~UGp?F!h@{x@B#jjpR%BfVun(qStVzn9}M&dR%s6cPeO_STqL zZx|7gH&wbNr}mo+1f9GAIU&)7(HYOVncsoJ0>`}F*fo|#kJS`JCQXfKlG*WK(sdM0 z)b*EINtv>fy4SV_f?|rc6m;>gTYrWsMp15CC1HjSbNr;Q2X}ekR75EDV$!zUq62JC) zB3jieRx#TU6^Esb>i6)Q3dL{6yj$Yp8Hol$mA-u?)Sk^>1B-CoNkyL^mKef z5}q6$Z5L#H0xmYQMRo4?Qj&`Hf@&MXDOQg0;JReLy*=BIuP3@l+RmZ-`*W+8hxI&N zBTCl!ubV(XNRnWY4y`41iCQ`z{aQsRZ_eSFg&Q%+=`80vS3+@NEOmcyqQ?666y8`~ z$UUQVvo$>@g=ErP7(7UM53C{1`p2-8a=WA@CEDq+Ms;119;>6(?9<0^$#AiOVTarV zPE<3H?$Eqvr%RveI6n_*TBfNq5I1t7Aq)gb$5K>($U>i=t=~iH2?$xFhApM|+@`so zr~{{jF*ctsD!Y{wt=l?X+ndzS0l#HFAgJCKo1wu#Oygd~p%d=3 z<~o2;d#c}Qgo__HD-2HpPKze`TDlJPLrzM{U|dZbXn93OMl>)qxE^Gf!%iL@kDQ#x{7#j(3t=HbB+$-5MZw0e5J6Kyyg&!|LmXm&~q3sykkbfF; zmVi9A;DDh20^QY=Q^-Krv}Gxt3D%k^dkw9i<+7fetJ$Z4^jKYjBr2ex3_mh0ualYQ znDPShtc|I7^5(#|uz0xIbxyA}F0PV_d`ZJnq^*LozGrE_CUk!Q^~IUu28uzkB3wZ6 zEG;qYhy(_p)2c>AxQ1xofoD7lfl@j_sZP!@FSUih;MFw$RSp_q#paM8HUE0T&iB|( z2MWzD{j9pLuhD;Es&@2x4#YU0^~oNE6ZT1Yj91$W=>CP?lirUv=^f}zj%^tftM^-~ z;|*$PSkd}#6O?fXr%&{5(jL5v>~+2d7rS$Gi#PXD+#@!fan4f3 zP;!pC8QJLlin>rW@AxHPdH840b#>-=uY~4H(qpt8#DqCt=|NKbB2ebN)@RFfzlyJ<97DvWh;i&n?QAgT!}=M9 zi=TCJG}0s-F*i7`NQS)-uV8uC65xLObL~$2L;H|q_WaA2-f985-nWl@H@>J29%S-c zUrd&iIY=OCs$B9M_y_hk))+#ND9b0QufMmQhuI`7Ll7=!JXb9E=d2eL_bF5SwZfYi zydl~zxtgNHi?N^WMZ>ZTS1$Sv;(2dJ@2D5Bz?)bJjcRpg>AfDj_&(b7e4P=H_RG=Tp**!+E1vhb3ZJoZmh%E%{*K$ zFgGOKj$JN}DYqPHMRN%jI&&l+f8L&%%(tfPT!@fc(??=s_H~T?^kgYTbsIzJc#8|K zt6%9cG)oE9Wf#!n^Tg#ImnJ6F`z@$UdYH_Ded>#REnIx;_@alKht?avM%|Q!*s!Ab z^fS+3>#T@zWCYvp-u+)}L~3W{Evg$WZOnDE!$$R{==%#~MUt1ScLHKfb6n=MD<|O{ zaB%_Sm><~7tOr92!SLaq!%iJ~Zg|uQ1t5nF6V^gxcMrbxQI%~|CReu3N3Z*#@Ss~* z+jVtm?6a1~@EWz>*!Y?+>ve}~kJQgkI+}G8c|UA(F&GK4>RTn##OQ;!XzVn zGKM2L5I8=ncb(hPX)ICmOqTpLipj_6OX*=Ad>HNOAW0wQx9lVB*%p4=$2 ztHMSfck4_JNY)E2OrW(ZlMM=gu2xMT`|=^WbhV2R@(Di6&eqSK2TR#tYK3_*+JIsX zM>~vhr>~X|hXU+Faj~~TG4LfTV3}Inj^7lCEyQDkY8o3F30#{0`oL@1x7r zFsiW{m>WH3*Gw%NHqXyoBj%^ZCLg_?cqPsSM0vj}dN&cs1t%BQM+081jrGVdKI~H=EndFYzoc%_`R8 zQsxn_@$3D~pYElZLrv@kpWfYMa2)S6g~h{xRtTw$*E+~5i^lm%J+Yr9La~60jF1FFyJbNQko)x zul3E2UZbS`B2A{?8@@_Qo9n5jEXqOqBu;G$K_V|kK&rE?I5U@yZ`UUAQR|Qa1V||4 zmygo1X;<%Pfb2M6zL<1e1z?TgwV!=ugO51BJ9R3bqWN3RJ*=Hv)6e5he>8RwFwEJ8 z@B@`g%W@%O2ifa88{N^ke$j^?$>c+CpG?LaZj)>{{S~a?VK^|4`#(D<7(Z5g0kK`O zQ4~3~n+>$GMlaWImF&IX^R9DgK&@j;F7bI$!?YpaRY*o!Vr#i`OszL%#wp@GWbe)}$t^JLA`1NLU%VvY?r70P>-5(PzaG6HZLWL!& zd)GCS^Ocf?EQd*Dbaa0G`R0VX%_&Ew=<%nMAJkL-6|+(K5Sb zx3N(=mo1D>WotY2|KAlF9?tdlZvRyHft1MrZCInnBZ2i8Gxmr)=dj@iTS3I+8^O44 zc-CpP3_UPtKy=i{+=ba_R$%dpmsFUTRdAdUeg6Fe|6(FO#uhJBWC?e3kt3(1qD4mv z{*G6a7v=#r65Vcc08cSkyjRh{Nzyjqyd&0ewfz#zW|EiEzykXkmV8oxAKr?CGCG3V z2?Sw?P(LSj2~xHm*Zho5LvK_s!=1C@Hu%7P2_IDus|bFl>@*ejMP43|qW=@S^OF0m zv=nn>4eMD%Q_Ez&W2*Nc#Vk`r|C2%fd1d;1o^u%==nMjtG2?G~Yl&~w6Rz*eeJ|n0 zdJ(PGj2+{aQ-jne-Bv)JRHFJuZI8l$A8->T3*nG({&jG3bVe(oei(t7s&*=!hLHO)VChwLnbNOBBY)i!GjI(~gPm>_BwhPc_Zs5`>}K;% z8IxqO{cSna?N5L6D=8YAo$#-JKn#rp6I%{d*4-j;mAVzR&ZE?_fQcJo8nylaxI zu&)^Ma1B`Dwx_Cc#wXA>?vn zK9*W*sjQA%a-Lcv=|VwK7PAI{jx7BL?!nP zYt$I$lx%5XQ$IJ4%C6=}@bBqlY!WWH{G47d{3|#uGqPV?6O+kH4DR34~ zPU((R8#;@yFcQ6My~VJ@ri|VB^U(5xMgVq;xnvh&({Bo{RL7)f7f&_&vs%VcGHs=Z zFg9GCi{zQL3r7K)`y+87=WS+FA1|p{p<9$j>&twPCuFsGK-$KZb9-tO_L&N2!ti$T zNz_GuQ!DY&!~d4BK+kJO^0X$ZT>yicMXXRkkW9U|v`kUc1uMIT&L*z4>?W5~NzVZ> zpGDY|-n%E^6rWdH;M;EnsODwkt^0NPoK=nX`GLp1V;cSG#Qf^!!03sjB!-h)h#L%O z#kmhz5{h?lx^JVaC+c%$s73JNvmJl<(3-9R57O#w&KF**-`C$yUqQKD3mTA(!FI9V zrmWW!@{!_53$#-IH;RQ&`W9Z(qTBC7TlwDj!sBmNeqa6q^w^*Jb|s4*O^t6}lL51@ za?!$C8xD_mnD}u`HzNqpa1H`8f|ujtU_qv@)s>)itBc;A`)E#3#^B31(E}nu+U@B8 zJm_*3B$I(Vy`u3@#-xNX+}GP~V8TvM48QiL*t3Tu;%v>~OsBrCse)6Z*`WmNu$zu5 zxw9^al1&pn?2VsB5ao(Ei)Z+vSCbTT&yZqW4F6NGOvQdenkJRk?ipU7=AJ)n3ev8VOX?WG<1@mT1c3#&JNp=Y7yrK4;)~uR+9?##82iN#8hpgO^JSmJ5 zAr1V7o{bUu8)+!6O9el23Sh(sl;EXN72Pzue~?^E3zi1}zZ;ny1pYLmy(K`uUacPL z`P~;{Kwn@*(fZhOoY!jXDW>-e9u{4@Hv*wCW`>8L+%Ln>FmvQ-CQzA)Or9@Dfzyn; zpXhlWd2D440Dm|Sqq7Dw-(7Vtba+z z3>q#}jP9t|AcB_-PDO6@3JO!a$fn1Q2zTIL=2}eX6$9eaelTH07;vR{^xm=-uYeuN z?A#1T>Uqt@x93;+%&fL4D=|r`tE2h>&GYvRkk4boPqVZKjt>?}48L$AJx-S_3y@)` zgkqP-eWW22M6E)XI&90?DanA5$eWG-B^%viq}q%AFDMi_ci9-KgR_LGY+&;8pwVkM zMBV<9XKM0BvLC%_6_M=V5O4thWaQB^FX*8u7a;f0OI4G#(f898tk*EYpEOd=-Ct3^ zRvlnArHAAr_E5!*c~5gSM_%Lo>(N7yyT>{IRA8I7gl**~;Ij+x!2RIwyZiHl%ASqe zglsa(2bL61wd~Kl^&^Shb4cYkzwf*FlYj#Cou!VY{sUraj0}6&9?it}O^DL7P4KbS zuSAM&kblP-3dBu7Inn)C+44I9n<=RgEZYON3|Awa49R|$BZTMttadtslLv!utK00hJg4uv1wWzjal1Jz3kAmxL;!lT{Ya z>MnrQ-|-^?fdHR6&WWO@n&L`anwgg6yF2CM+FAhLTEvM&L+RJ@A;ihQdoY~YKRi?f z*t$C^$!N`9n)rqD)9XI-2M9RT6F6i5qQx+hp#%kG9}|&H;#eS}_)buWO7OasAMzO9 zUXWE@kO5C!Xko)-0YnxY7UtX+jdgJ4|`+>@@a2Ivbs-1|=>9`=82LI_m6Ox1lutcx; z4&@%t^bd`ebi*`TJ^Ed;{=(tH)9mBnrjqRyI22p4;)k4|XHhjv->l<;?sP>FSLmGmwz{y|;j?ucw z(yX{t%0oi^O%o$GR+{pmKd|e-0I4;ampOe4*D8f~xA=Q2Go$aS1qhG&#gQo^Y@L;0 zUE*>+en3Bkw+S8vRHm)**SF^N`c8mYq0%%m2ErRk%>Tw01wRg`t}A7ct1^3!{%fg+ zKQpttInsQ=QaXQeRJl|jL1G9Y%V_4^dh>8irswV$yTqdWuczvP0-~#TDgku})&ing z+Osf_;L&;!A9(YCNSt;nT!%nLz`}l>UkTISoZvE$AgR*Lo06m1@fsEVK^Oj`K(by_ zZ$=15_1~%v?`ju%(E&wX1Hu4W6BbyGAY_oS?*$nvL}hY<{ho~?y+B_MIB&&fYA6Rp zA(2Fmgkdecq5dt8E0FwHsR-#1*{`X>-GA(yb&QsN2m`qq+^*zF*0G)1D{JkSSE>4` zev}fW&1bjCfl2c?*s+pUsMzU`ivXvAH6OB#`-4C2{W;JzoB;EN z7)1gR1A-664Cw?RG%Kuoq+6o$KNl^3Q#)lgJj%i^7HA2pxq@Voxlx&%R#8Gt7kPRN&tw3bm^V$t*CjdmN9%H#h@=%_EwEC!P2SDmp z4En{anYO%PLkiMZTir-18spbhcgI?}tE23{Mm;L)$ob%g<5NcWZF^Qw{+hi+7tUxcJNf;Jr~K+F-1eAv9>vkZK?hnwo~LawA>Qm zsQViXQa@`xwiW)JP?@tD6dbePlw@A$%KMRR>AKAc@FE=a(K?XSOaMo|Zj>!kVPY8T zfx`+mw*9zwr7Bj0R&V!8det`wP!$IrVA_MWV(2fT5I|D5j}gEeTdGckol+i?XYChtcTG9tD56Mk zhxlw4=v!=mrKQaNTde})-NUI+NDKn}aS3BIWQV4-txf&#YTAhMe2H9&0_rw|vlEZB z%^7nVlY76`H$6k3*!;P>ILX2YulLBP<4mBg*spf@}JUKqroS=pDuW)6S4-9sy zKnQ%LId6L5aw_1jc41iB*ci(P(px0ilo4mJsiWh#iy`Gn;^uW`QQWHxx*p zJQpDeGnmU5PeXW#F3^eJ1+qIn263K6xN80Al~Br*0v%GCM9U;Ze%KkzcJ z1QHp<=45xvI?TIjIt}b1RqJ5~0KqX8AJ=V@=F>FdrQk}?2QSvNeQEiHwuN4{%190? zu3(#&4cN}J*e`CQuy>KZ3{jtn^U%&My631~w>lEY@^kbYJNRqwq!0NSAeg%|NvdG)jsQfiIJe&n?G*q+v^oJ_7ua$V5_|cO zWZPb+tzPHU(*~#hX+)fMhS*l=zW!tzT@vGpzW!G$TuNk~jIhzCcEHz)88;ti{0;iH zRKc*n7;FAO7$~=`569N)`v%PKOO&=OOzeZXk`lrQIa-c@aFILqQ?DD9?+<_+|q9MOGyw z(2<7}Bu3b8z2chN1t+mwV4$TaM4#DoG07Y^!|X&~(SQR-)UtRy`nAGttWJld>NpC! zU+!4S)HunIxlf@Lu<;_{K|=vOky)X^FH3c}zHXP@`ff}&54SIG!3w91o3rNy5R-|Q zUzV}u`?RvWbc!*P{XA{bwZQ>8$hP*Swdv2K_5;cNv*Nto>il0b2r#FF1K;KC+q zNhZJ#gog~@JoXSX~1gt4zlXOv1q`6Fh;%K(5Q14_a`wFe|m>A zjm}>B8l49VqNd;}dpf~*6mExi{?nwfm`2jQum1dFo%t$YJCYZ_anwi251jI`Dr-v~^jkvUSgdY4uZXFf(aF)@xi7 zgqoR#G~sGtSz}yO&i#050n^>IJ9O88M3@6`oqA*^uUy14Jse}y|koA7FYEoRfl2t|f;f6{)8(K@jNj%lKa zIN@jZM8b@ZOFnBLuZ@@b!5aF}avc0_l<^(cxet|VSW_NABN6k0BDV&L)x6F6MZ;GF z1?e?<2?ilS&0+#k`f6&^HJQgej6Wh*S+Fy5E`h4fb(tTXC7fJ@ZdW$8U)kNg3qjwe zEkHXauWOLS)bRJNa}ZcO_o=8KYfec22J6u)@H?e-0+}KJb|+b}mVWfA2~yxMT_koaT&9%Ifzo{ifos@;FBQ$N;%`H}}yfYdU6i&r|pV~cG;idSW) zdn|jY_lxJ48e*bSqgx!kv|8D3Ee%UmYQu*v)hw%K{+=`(lcGHLO3`dFuJjDJux9T| z&eXJqF8GtH!qjt0tU|j^f!h!ZA-1-WS*tm}QV&^VW`HN8I*#z|3uAsvjZ-J&Eph%! zKPXN*@WVSWdbmCB*L**<{Tqu}Q;8Y}j$UPwEl$vh$GAi^dqX`_$V#^?KLcMOYBa(t z*JZ=D4ZT0`_7&^B6#R&S@a{CowP#>sl#Yu+8m~0kthahsmwnzXqy78m(47c|HzC&7 zh{4ISjYPQCZ+*RQI+ScXtOwOgW7-)zGp3y);6W%HLZ)JR@vooRClph;ZANlE#xx~9 zf7_e}%dyV!x3WRrCn-I+2Tm6xvYv(ZG?-=+WH%I1`nw=;j zCdyC|c6c;i;*agxre(fl`Yo!N2ni2X|M|~jWBOkpqE|erZQe1peaU+3I<>EFXUX!q zjZIu|V`EcW?#_8TWyGi~iAyX$d`0?spk z$c=CJENClsa;#9q(oODiOQ^Q!BKP6wZ+-pC)oEg&VjzXsqJ#v6PsuuMI*N5KHVw{{ z2Vfpo}+P7n~= zF~onk-?e_7rPoD++r4Byl~nV(0_E`L&zRlK8i`jG^(Q%~rm#wpZr!n-2q)4_q%Dma z4hnW?f8z;rEE+;lS{vDky zLfVxGTG+rGtkd;FgkcTn5ng0u=0#}YjH4Wiz})Eo-v@Az+(ug$4w z-Afv9nKo`?$#l@bZpdI{=3ZEvBZ;T@fVitAMZFiF!z*fMGe>vxiW2_M1rc59{Qap2 zvvF0sGqH5?k*GK?slVudfCA*Wo(;DDC~W)_cAM= zaeNX-A|sA@TM$IpZk*}Am9!}7yXmQZ?{O$XKl{a3l50i}+LHw88TtMB?~$pSU_q-W z%#)tl!EbN^^a9bt=>(0B@S4Y zq9FUM)1SaQfW$cTdcJG^0{9laIG~Z?ms8GGHw(ejyKWnd%`YLqO#H_=I&aTA@+F_z z_T1?45Vd-IqBueMi}x<*UT4B-A_N|C0|A?b70~vKN5E6Ap@6<$?BE8u6?_q~=}6Lg z1W62tH5=MXHge_H%Tjv2iLYM$%~@9fciqI={?Sw6-5f}c7Brv(G-lFY1;`zqr7>pg zXNQshmgih=x-qZ%hbNr5xap6WwHj)DVLdvEGu_u}>`2mQFkR4fHrF&?LLz21c%&^V zLs5lM#I8y95qXbQmDPDV@8GV9%XO8k6q936N$NKXQ9i73_!a+p6_kS3t_1 zrRLa`kDD%#HOvKH0cCdG3Vi~MQM|}ZlL(*b4G$Ws^eg%5$jU+!Y(K4@(rPc|OJ-r? zvOezNK*4YHZJ)5oK7Dwf^IMG}PL~dL;}lcdG%CU|J)gdJ6+2qlr|!Sz-Si~TL?a-; zdAH2MYpxl4S97v{%zEI<8lkTQ{@91@r?NK+XZ@sGqm~d+374lC>8Dg~tgsI;c{BfK zz6~ho60fMbmz}sYCD79A4-C4I^IvYIx&;w&riQvv3bN@swbASJUG-Ng^L&DMqGt_6 zWaIKiHOWIq4yDMj9(E6RP-Q7!iQ|*gK~=r+zZb4ou0D4pq-99Vc*O2F>V=JX!gN$a27DLFrQSe zPIi&s8fP-KYf4mG0D3K%stJg-2~Ru}47JijpGifZ0m;N3$Tf<+?_xum19(V{0Q-*h z^5}cij~j03p4B};`_lhQL1GN*6BqYb zEEat%ty=0&-ecAEZ#v6j=mJ9SAr%vy&*9r8?5{5oVtN{p7R+@jH{*=#Ze=vny;UxM zDaBetMR|L-4S7mn5uHcl^YuO+$$n)(UOaR%h31M%p$mbCOauKcDEXWJpmS>N89zkT zGoPZGj$$oWg1#l3*H&iuJ&fs_U@ujl+U$z3j&YuGaAN1XA926ZyxLLvo%;R_6-V!T zB2-UPl*`sIsHf|K%-wyC)`q-gS?nxWBe7R|g}(hGy6!S5dbu^9%)B&4VpD#`ESQS~ z=0jKN9yv&=N$RM0^DWsSy%JUoWZrjuez?zl>dVZuiM-dtz7qZBO3&-dvhLg@60NT4 z8)=_Gb-e*wU_<~zg5v)cIAE$##nE1Iu%?Lx?$h!ShCpgxhuLd2N9IH0JY5&LYA!O< z^2NgW?s>a7wGFj?9*6|Dxn$5mqPCPtW5}tuzy(@l4lUo1csFBzp!1LHBr9}X4iy$1 z+6iQ@_`&*Fzx$3RBL6TJ1YCASsUB`AfCK}aZbGxLdGBzsRcS`HO#lHjmz{7< zBB(`pv21HLZ%p>~+8?HxMKA%@y~K*o10bJTNT$OwI{_2<*4WphDr zyF{&$giAF0Hl{19N%a0$eF@tkOLvZ>!SVa_>A4XhH19q?3j3 z#}ej63*+oa=>F>OXBdj-F0fY73(A=6t;7rV&1;fBEXaH?ya-3h{%@v1!Be?v>eni+ zyB}^;YOky4!*J4E#ZOwU=DPvYFJlOOzDd)9wx0VuYQN{TOYYDxWu^D+TRa=1WxxO$ z^M*zjrVy2!c*FXFaaX}U^Kzb0jHF2$zwvom$$1i~MT1`TW*6c7CCIAW7;4-OJmp{j zQuREb6S#^ntZH<|UnlMO<%iA{|6quWD_*CiI>>Jir~59ol20kJrXO{abHh)-=n?Kr z&8eeqt(D}IpS}VUnq!M`F@2qnEGrNXY>uP}5hIGcG4$M`Y5AcMWF{t(MLyz&+4niRMw?(4hWf%XTMi?+Ji6s)G3jmGIv9h9P@&s4u~kPnbpX(`5ycx4wBH z7gPBMv_61S1vBu4SnT_g#vUW6!~!Jm#1EqR%P=+brwa6KA^93?qx}}cB`Xka?V+i% zR#25?J<M ze08;>9t*Drd}*_3)KNxN8Ug*Uu|)Dc#ZHWfh2B zqGG6}&ZBfAn0Hl%91i(H@jkq3$Hw`h{MfV(H@<~b@4z58k$pY3nm1qFMjX&oZeRum z^xR#h3Iuj(vEvjO>~n(j)_%7>a=3n=PyI1ew#7Kq=wl{d++e_GH-c~5K3f^q&F}G2 z-=3flF>mS4)N&*X!BuG01}KKM?*e(&}pJ#VvFnEWk93in6b&!kfABR{40T`KLxB`pZ<9Y@387!y*S z0NW+dHrHraK0fc^Kt*tzm=0Z*2oiZ#!pC&?Azr2)>bAg9#9VyIRc&1nI{`!~%uOP6-O+eiQIaYox?Z8~ZBrn4tfPK~8%!es43mTyOmcOpPMzo%!dZE%YB&JN&Kx7_!Xyruf%+D@ev&zaGbOG%9M5|ee&Z^Vm zL)>&jbm=+Mpw`elU-NlGY~RI>P&%A2b18=s}JmTJ&52tnrVaTArT?)Pzr$c$_SGA!7s#_sd zjeiHGY7VYR?$;$?CZ$iD;Yn;4PR8RJwBqhnr-cH;Z>V=jaYA*B#<%(ctN456xh_y` z3V9^%6eOrG>bH!CrmT@VF6j&^#`&TiEzY}2LJRm@pc``$Lnx~c12HVb?y%_OE>?j% z=BHM=47Ewh20%_|gUnPs*N_w*UL%bvA<(C1u4mW&B=P`?%*E zdKguZVx$#8!WDsr*S3e~;HjaHKkf?aZvkI`z$S(9-zbgNhVd)olwfs|X9@PV{Dl8r zIl7mDw5F8F#Uv+__NEsJ3m1;T4Q#*8ZDq*; zek16cEWQZWPYQ}H;ckU;IkxtOwXucQUWTe62zDO|h{~mlFYZ(`FaJfFplQqJA7k-) zttJTtG;~1V7t{Q&F%e@6&F+2XDB;k)rqe|?HiPz0dalTN8xmQe<#yVi9p?W25uQ+u zt^(brQ5z^8g}*K1!f%98nz;8o&ktQrSap6nQ_uP9-A{K@{qq~8UNJ?-*k!gR00;$+ z%Fi#3k-$yK--m)xhl;_jJ8(P8V(}npQ2TaIG>~Fk4b9K9M?NxH`xrB_3?ve+Nu@;u zCO~}}=0(*2gO+QYNz1rC3$l_43XyTUKW4&%c%znLJqP399$8z2;VIK@!(jY}s$E}o zqi=j7ei1(meE~bNB}0AK%6>v*arMftFpZW%ECah##3FGA^;%h4p4vOSM61xvT^29n zk7wk5csuu!w|iQz^EH6-?{FiCaI~A0Tz6siY2y6S;-#Cx%lq6p~w#5=e0HNZei?}Z*kyvVAJMrFz(g9pY;pFi`&Gtc}NbHM%Iwb-kJVHnYqe2J+k6w&IfF@voMr@$SBUeGQt z6cmwJWA&MJe{C32PdSz+=5|+3qDh-Itr@w{p&PE1f1>PjQUBU!t6z6rpZq=}PqxqW z5F+;dt(+)2eFa+6BKokXUJaeLms_;JQg3`;x75=6MqdiHFkt^q#WOrbvD>bgJjwsm zi~UFTJO(!@=XCCF-%a-`pnMs!Yd``uU!C{`R*cMP9mPTAxzpypan`Yx{P+(7x7vKp zZqHdriw&ccyQYOJe}Q$gh!dzJy~nPx^YArWLWJP+oWx+CX;tLTKQ2QRb1PL}u^DoI z)B8V$C`vSq&Of&(+l)S=KD^Z?wP@V^o){eF|D7>1FJT`|sQtq8HdAD4ot_&(aki?I z{#YPiyWG!59^r~Y>Q#5};3vJ;DdS*fOC%BB)wg<*(Wr!}%B$%&R=`0L60p*H@#kL@ zjm`K$!@%atfw+F7dk@WpEJ-NuF+$@D9lm0uT#;qlQ&bF{-s0PG81ZX6&Z8SM2hUop z{ST5{?*n2=1ky`dh?D{v3&ou2xJzd*?uK{ znJKiO-b;absSg-oqhXxjo)x9VHqD*j&!r#{&AXlbm1q#fkE=m&de};U+ijz@QAgwR*+(-YIt@aL{%l zVlCsvLiDeesB^sWr3c}4jlhB=^I&GhoO;41f5~bb6i{ABIs2%Vz64No3WgJ($FSFh z=k+>|X{yCj62j%%<;6AD3iL2cvz-7>MN!!;&~Xl#(1u$N^dWbVWPTcvdv0$_fA*c8 zRi9Id5vd*wy9VFu4Jfo~LiwePZ+wA+d@Lu{{XQd1?im;22IH3t%uqyRP+5v{q;iYl z)|&K+?AK!TiF1pRW~{jJ99*3t(~w1~8M3(|2Y0%rSESlz4)_!073qP7uP2m2^m1hy zvF%_t+E#~)GRB3Bn6<-_B_Qu72Y4dC}q_+C%&88a5N?9~z4WFZU*~;E%fgx$3_@CvnM% z{QZrB*2wEbu+oddXAN$7iZ$)59@$t9zWzbtvxvjiY!UaVDT|!7uAUdhWK_HAFB77B z5-MDan}Bx^`o%am(z}I=%igKx@Fk);Mxu{uX5dW%-EIw{<$8}-j;k) zrKS#R&vSC+<5o=OpKimAu@qDpQKg_EY^6zJG4btcIXJjhISh0(}~W2`4&0!w-Ym4Baj9=7sllZeae zb!u|L)Nmegj-V=I*Fvy21%>1|+%xMksdxxm;2urz@)G2-TKM9!{W&Ym{}%u%9fc7a z`Q+1k1>Xfz;{q^(I0}+F`JVVmiH>J|q{1>G&P7Qf37)VMv@*OtnpPSdqD~y>O;~|$ zVFyOqG@$ia&q@Z-r;Li2?}jpVYF%aXY)1dkZl83sk8ireCWc&Ote|+*p%q2NB|SXR zgG&Yqsi|ZD?kaYZ2@9v)iO1x_(3B_Sop|q8tZun9Jdz>Wc6pq<(%;eyF!#lV2t2*| zr2wlhj(*+A-yPH37f=)D_Hmpd@KDu?lD}Uj(JyGiVUTWE)u(d28rm`dFe4*{L=%&C zCzN&+jq+8Vf`{B=MOG-ADR(380>2MgEU7UQG;KaYK#+b~j2+v}UcM$?gPR3F4^SCe zI3lU-td6FJ%8jmZs4~XM0kRbstdq$4Ywg#HfZxcl;if7_C(n8@$iG15uhLSxB;s=$ zp2NxT_+gBK>tH>>#gE9`gD7cb7{57?m-%%(B5xC0G|_K&uUyoQZfON)TDwBQ;0O67 zYXOPj^Fsn!S3Sn{oH~us%2NJ>uME`qEJ8d|7a?DrO&>SK@*X@Jq;Se_VoyT zsKyrYX+q7O`?Q+2OB_e)t~78Pp4#;i!|?PN0c`z123^q4^M(FfQne08*~Yf}eCvT2 zFvd_iAZ?^sXq?4@d15bN*MD2t^Eo$b?4?>DOYS@;;D|Mf^8GnC>FHuLcNImysD4;a zvZ%(eWTg~CeM8b46x)Qu^-miVpPp`JK^!-)PR6Ugg)h^>PTyE>)8^vpI?#7goJOx_ zdbvh0;c*PD^1@kodU;b|S_~4+(j47}l8R5|y-85f&*LLz?)Ld=tkb0l%=r=`NPl~W z-8Xw5fCAigUa9 z%@A1xR$4D6mKLxKLl*B>_yX*hGGIy8YBtKzYXl^>TYF^@3dZ)0D5%HXi@UWZF27}@ z+t!AWXy=!H>yc*%lM+7{NpT~Cou$Zt_ftC8U_^9OsHZyc09ehI+yZ);O7jpYBGg;z zuA|vUvxE~Q?T$h93qPJl(L;pW3GKy;+i(c_Q19+7BkyHR^!n5tg~0t&EmDe#jWnAR z;VA)9`mJW9y6ge-Nan)A$`VxW5wgZac>O9XwHcDvTz>N#)6Qa(N!c z+-H_wXFS8zA|7Oy6C8|$k1%h#UP(Ek_}V@|QoHJ3ycrnFfK;*cCw*Nv9?{Y1-~KH%04`89Y-2{Vg^g9Yv)PiD z086Jv6UFbL$ssL=&Q6s(QIci@S%g=&c^X8^BFal(?byhQK9YljE1v_z?G5kRa>U5R zspR)d1?eRIoB^%@ttUNWUcg%WX?N!;bY=#>xB;CLmY@SVs3lPY>C#rMi0?u(e{Ex6 zPw(m{A{`*WD>eN|4!H_IXIjWk9oIS%riZjkUB4Gry>u}7q=u@ITYa~&VMB;G_qVFT=x?dUhWcXN5F#qM zrFOf|^;8gMRd(0&SZSqL2%^<}Y{7~Uq_@Nzb=XRslY?Vf8W4u%QDjbwt)y`!u&}h^ zNiPXyvMojVS?haRlYdYa7dUAr@NRvHjzRMMKU{rPR9oTJZGhs%o#I-gIK|zIyF+m= z?(QzZi)(Q&?(Xhx!QCBhdd`2xm8WFnEjv4NuWzm?5e?*yYXRP+bN~f$L6W zmpse}NJ~)-RkG1wEJ2xO3W*>3gi8T1Nw?uPr33nf!;`BcO~CU%8G}3x@O}qJd_w4? z_nnDVK4lKIVL!OUzm-6rlB=`yG@Hymaf@UC_`l*vr#G)ZmwceLATNUcB%PEJR1CRa zHOlbjuwTAkj+Ag)YA>_eFPl!v+>1J;68Jha z$%1ojd@7ce)z0da{Vk1>p!#~qyDa7FDo-wY4!18H^T`oRR4>gVtc{ppbn#2T5=9Nd z&MjKKbVASKyHi#+2Jx<6HrzZS*6LpTIeLByM@*s*FD5{Alecc8PMW{Uw!=A&*x*w$ z9T8py#G}&66BAje4lQU(Hs)1jq%n0S#SN1^t}{$$962T*G9&UP?HiF7tqtVXtq}D? zBDFfC9({dK>mxnUtj6LEks*}UuOLsZHiMWka9z;G(@9?SCXVsH1XAn0 zy$^CjB)@0Pd|}%kP%=gumq4#|?Ck54$F}>DZ-;O=8Ju{L&BFMgr!uRCsid$Ay?dP} zp5F@sjJ2C=K_h1?1dqF;N$FtCm{PYpFOeCz@$jTlZeUMnV%OzvrlT$`OA|oyM^}V# zPVD_WHU7f2{=9vP4RrA>l3Eh4eY1jo>#zdi@=}6WX|@1Cb2^2M_(rAU)=4!}V&A3r0j(M|;c zPkt;gzOP+C-180H6cZq1-Z@**-y4|_qkNyMVG53;l^(L2>qjJTo`v14lwrOkPQ4zjW>lW4(xP>(k{~=TMpdq$KFm}3`{hN zA>UNsvp*x|A~z>^5<>nXkh0Sl1_X1;fi?}FV`UWZYOVAy;~<-(YJ_pPEVkh0Xs6qvaYTZ~Ms19u-Msh`YFtQT_D*mWttDe=FNm z^U_B>ph7nUL77S_4)g?utv29SVvOXM~9j2MJ$O7ixQ!@z- zF|fZRPm?pO^Gi||@AnS8$AT=-{^(ycu)9q!{7isiP){S8o#)+dw|d|Es4IH?Nh$!Y z#O%Nq%F5-J+Fj%QSzpp$8lLFAnSuaVh^2L`DlZ~OCJJZYF9})jribF3!upGev4~DJ zhO@GtTog!Ju}m7U3vTpY?OXvjdcT7kz2mCUz7O=MFF6yEV}3F6at;=RBkkKpRaI5R z6cY!nk;pQ=1(Q`mP}(j`r+M&~_K9T1mYP5e~BN`(z*f{Jn9_cPHzd*6C3airunE|Y|o zE;LkE>9(|vckBNAh7BXG@;3FUS^6(*-nM!Rd=*xPYIe!7u3b;d=GV>9iV|?Qp5$$n z`Rqgn_RrqOiW+%ii$|dUsc-QH@L*jZ0Jv^tBz$6s0f$6@TRNl=sv!LOJDx9FdA_Sb z2wL1r?FQm6BLXu1RRQvcK+HM5%^xf2jAp0esZ+xQrI&xT8rtZ*$Y z>1egIYTuJ{dX#apd)29<(6K@Skd&fg;mMd!YD%IuZ3rD`E}r!UwAr?GTH&Q8JutniZ*RB+hl51Y0f&t^=}G()5qFxg z-B9LAgWMTrX?&Q7&y3W13X}wmP^9rl7fN9-BsuXy#}( z0VHq&&(7mq+T$@jk_BN3)7;NlfGI`s1*mSb9y=Yd_BQpA{BmIci$vu9Ry&KVJ&*kd zvU_I1pxnRcDUx+aa-o_6=1UQl%VKbhiBmG%@^=YWzOrR{6cYJtVcm0Q%%e z=a9@ze$X6Baxkim2gCJ(?10@VoD3irFW1(2*{@>Idn*A6Fbl!^lQ#t9!|EM;yngvg zu7-r>w6D2pg+=JU5N7C`#~_&6dV06?H%2mDlH=;L9FN_#zhLpANEu?oX$^I6Dcd}^ zL}mSKYfe7hy#O?zubj`}EdU(9J`dS{$lhvWp(?mWkW=2y=z(c92762LPN6sM$%X8f zWha2TMgu{w2M_a@rL`l*O4ypc5(#-Cy&5D~-4>*G7dzxxEffCu}m7vl`3uAw!NRR^I)>Y5vM z{C5?Wi#rMiCemBc`%d*mzir4|EInRwDTcaiKbUU+!xed_nUtNPDz0l*c~PIY))jD` z?Jsb+N^KB}AHhJ$jzCcCTx?ofQTmA85n7XX^)RJ$F8|i3poYEL!*B@mg2=;UU-uA% z13qdNjg|)N@E%VIAI2uDE<1um&p|;` zme)>pD$q@=?*CQ#qtq(eObHf`H{A?T>YC*(Z&3*q;ELm`(K)5iH6%Z=uU?pw@$o@= zcyyQ!+*Qk<41u{&RwM>?Xh2s54z;BSaFU~9s%7ehyBy*W48Qw2YoEFl(Qeft=Ao>c zApH=|;lNd?#vh(f5#%v?D1%(DWj;H#o|G;5@)4E^{xjtpTJ9XngPPbXi?(9@6zLGn z{UIbHp`+4tU=9IwuLv;S~OY9e{RF-naPDs4=vYVIw)Dj^^;2`9P=lcvIsOy1$EyRs(BNxUTfd zP}h=?NnQ)iJt>2>#aPIhl?tHxTcN!=@l%PZ$S=AX235(D)6dnhtvT%Q4TeRAzqXQwJTAA&w{!McQqghtR9J>?b`Y6r&zlkM19lz;5I3V)-Wl z-;{QXkgk6H>49b?Tz`&uplv9Xz73EPEQ2Lx{nMdG8n1WW7=R?2Otqz0w$?>QkyP?a zX;AT9G@@=PYJsaIaYDe{DnOFu&{FBSdE6}UTy@~{(Lb1_haG_Q`vg$6Po*ZEN)Gf{ZmD@RTpu!VV$Rq7^+2v`|c0D zkA=>o$2vxDiI4M-Iu7Z&x?IeNzkWfyxdbKE;gFr^?}~7(r`~-#6D^4hl`rwkr4FRr zZZCnGVm}~$SV}tBzlk9EOt|FT;`<%Be7(MmL#p5HbwqUtr zda$f-=ZZ_4nC^$x8y!5k_tk!DCsp%IcB<16C=42)2UR`zeX+8j1xg9=$B3#n^9(QD zy{`4W4Nqt4(9Chi-U*b$N7glUFIv^nXMntmcpoGHSL-PQVJ>es`q+yzQ+Mt|W+feA ze%`PW=iOT_v1hOpSvZ8G=p_P6{m?P#6YY1m7=af(G;;C?_)Kgwnff&^p*<$2BjDsy5KLgkRUnX zvpPNfP&C6ke+4y81wankpzT`zfLr3CYvNn6c4f#FLZXFV;jJ)*nx@s&$58W~mqiyv zU-?9gdbHd<$?xg1T35zDt*tKtk{}EqC;>FvpX+Vo`_aCOJRU-b#(3uHsJcS`GC~Vg(>(r!O%JaFt?Oq zz0*1^hYQoB{*r!{kwj<;wwF5T>_VvHSjpOHk?!{i?&h+cYfTp|l_XcII5b;#w9RMch5dpZ36(St9(X80`r7e{(LbQSN<8PL)1+?mV=Cp<6d4qr3ihm{g zC$K{~U?2r?aGud9^f!mI9s9@ucn7Q4?2O-qoyN=koOIrZ3fBH%G&Vg&dOEma}sMB1dDu63V-^wjbZU8Q`98_#;4>l&eEn|f=$nb`h&Mwtoz zVu(G!Xx}ur3Z;e4o<6?bO&ZNlT&EOK4D{CvDb0F#_q-_cY&fQw8GlEmg&(8t;|xvKhnd>Dl@&Xjbnd zZYDLCqhP>2a-||fs3)mgfrA=CbeFSt38kOpSmj(Fc+ryU?54j1JIv_};H^jNezsbd zG`~X6A5kdSWpG6QKGC!viO9aOU%6M5uC%e;S;faX#ux5$yLDYndu|C6pCh94RpKbo z{_U5hAdjoRwmX(M0K!FY4?}*c#(!V;^f?*3()|7{4P`Sb$pKCk@VI?%Zh@p_w_OMS7oUvT)M7ssvl};5rIJwl0}CV?AacYWGF5Xw%=PnYu2DDp^3;r!jHjBh$Z2JMEyQ| zMrHhm?j(Xkyv|x8x7$(!gRkDmNSyx$TcAmklQH)0Utm5#;%|uG;{sp6KB@4bv3LLC znO?r3lD(*m-<5F~t8YWg_7W3+Ffc5{g*aZ=CrNn`?qHuBw%H-h-%#VzmHym#qZbqcA7FPjG|=@X^#24&<()u@Tl{ zcV)%3My~S4clG;#He&ek6Ip{xdbUsFU-NE$5-}V0wLoi$lSw1Ts6_2IMM7Q^$W>Ch zca=)U8^r@CpdxHIcSFd;$;(AwQw&EU3vv?S;018%W-yf~3n<{nTa{2ADlxz+#xRB9bQ&~HB`eODjNEWuXQt>z_}Ic>7nk*t$>*+Lo?sDbPXNZFCR zUx!m($V(Uto0gOTt<#V$uC^}3ScW*Y^MBERn^v5)nNty!Qpa^l-p9J~kUsB|oi&O0 zfDb7;t-7q1Ow*SAUEu6TPN$v09TPVvPQ&*Ib^x6&Jn9AdXxWxER{FFhcNIH&T(UGQ zubgf+SDARz{kVR~5y)?7M-}5pJMU8kgYWCwagSNHci3vj$dEiIDwh(3g9a2xQqp=r z4P+iwwurzC#@Vpqxxj|9SPDNUh}xD^D~w^bu^$3?QvNYNKTU|^IZ*?db?Dc)fo~V^ z@8LtDul2${4gbMe(~m}MfC3aMUIbP~wIos(jnTW*u<*BW!|qW3DA-JRdFgCQ0)Dgf zSveEoCMlBJVrRQymy!9$K8H9wY_6*cJN_15T=d`6#z1wYhs)pu4~XRS55!pxeV3nS z{!lTDCQ!V-UiD-BlVP9V3(56A26i9;wjc(P%1%HRkmh9+xibZ&Otl_!{^ z8AriZk|vosKVPl;GlwM*cUTu1a6x|$3$HlBDT;7JpnHI~T51x$;w4(fFZP>-Zhl>} zO{doR6M_9uy&N|3wYIo}b9dOua5IB!EvK;Mq9<`qB0JM9NN+1NZ_#sDblC=RV7DG^ zc`7Hqm-4QnY*-$sE?K=IGWC0ipDC2*)2h;p%NvQnnaa>NaZi5Bpj|^x=nM1JuTAVd z`dly1XGGebL*wYnytp9G@~-@dhP~o6xl0I5YhH}vlF}(#4Z@>uyPpJX?s}*1Bkgl_ zU<7$Dn@zuP=R}@}H~00ELU=M@O)>?djy}_2s88mQA~^<@5!Ucc8MBUd4V=Vocw?~@ z=fS$2z=Go`VR!goptc=EsR^ggsL8)Np*ps(ty)TD?+DrACoIm2=;rwUZT<#d7?c0z z8~|HBS8+^F2+XfAT@0I2V#@Rwv_i_4sDsXwl*iSOwt_G(_UmCSo{%hX(mdwKnlx0+Pc9e@lp^au! zx^AU70Y(e(xJzY74*)!fV=U^eC`OBd;^&kw z83Su1(mgw=V1k(6NdJM^a9^5#FgtX#%>bHn5SNpd0C~9xIOwebm5*GV?cf9__9Q^z z0*38EMyfMoACz%G`Iq)!{Jy*XwW7-2n@hNUHF9?n7{0VqCp(Y}_DcmV34&S4XA~%@ z3ov(6xV(#%@i=NL=B!3Z&ba!k=qd;)G=1~Q)o`<~z61hX%{%lip^V5(Rd07@_KXuF zSwn(@pE1gBy9$k}eR>>LPS&bWvRK??`Y+!D-udCm09lxU4~yZ1 zY5;yKrtpIB7-1JLHjO4+Cb~4kUt_fVi9sqx4y+v=Kq5a1Z)QmD(rB;V^o#d2LzrS` z%1e@As`v`(o9?R_5Osti!xWt2HIK$s8Ck+n&Mc&px5kB~`|H#U2yU}6_|?Ei@X^nk zJxDenI43)_y`m!k=VYlv}k8RaBvAEk@M_%Kkx$c(v>WMhB@GkCINvI**?#q~>aF^+Ap+%PXl- zyf2L=ksJ%jxj;&#qBj`NK@Is`73@N2vs9D;NXYbNf%56tEmc_%N{|##vfJijb^JS{ z<1osF2Iym-(}ZiK>yki?@0Js#FJx!C5Ykm-^LK7(JweEGN8D#V+HI(7W-mgj9bWfq z)Z7JjLuD zwIB?t>FAORqRr1TLK8u@1)UNw^dH%?ue$#)I=AM=TLIcW=U9HIP2@e}j3|}?t^#X3 zrexuq_~;m2a_5=4DExkX{k?1I$8RTrC#_+E)u^YY0LtO{#h@3u@q6>l7<2uEZ}nMF zjes2hN!$ib{Ib?9-;^G$8Gw+{r*FSgfQn=E$qEu#C* zXE>>VP&X@!G7wAPFK0}EN_zn(zzNu8jPKP4R8c!f!!)5i3t_n< zX?6{jkLEpoExQ>npALoAR_vcAtAUIz`(lwoB$3=3)e8r=Je^EudgIt?2m%M*z3NN^ zTgT$++J{!Mm35tJ^nljTx@ivtt(LL(kkH42Zn< zq|R_(-5NOBM%@@2z11BP?Ixz@TsZC@;zs2q!t{VH{9AlLvN$bOE7@qCs+E3CKTj%8 zGax63BrBwS($KW{^q_f*pHr$u*a`qaoe9HbR>qtca2I#UM$q?ter}1hBBD!Qb~2<} zpT3+{T5rP;c|PVa^baZNpJUGGa-v)j_6GPjsQ`{p#TNkfr4 zn9oLAd^>fyfQDpx=jqdc)xZC7uTD+>Mf$VE?m-ac5!>kl`-zpx?lQR?{h@M{P1UBQ znq|3Oy>~W4NTFqQ;@S#n`zYj-n;C} zL4j+!@7TXm`ewzcNUu17j74J-fD=v~iN+rt2+ZN(ZAH3hrUJUC8TuQqsd zZF6HC6VUV!10`QDu#Oc+4&AmZr~>LKBw@vQ*_GhZi3b`nvyx*xn+fh;F+zirbv|)% ztOaMNPYhWcg=LJL3&}(C)BSNWBPV? zdmVg?fJr*O=fDHF5j=DZ!rqZkr|F*6n+~b6Gv3)Dlj*GbsvxVna9ZM7ss=L!1oKJs zdU=kQT&YP+MttAPSm0G%Av*k21bU%=7+X>sZ6^f~`iNNck+jH9(GA!`-u@FxF$p^y z7>LImI>RX7u=;pj@HUjs$s=*8(_w|JyS6S!z^6o_SB%6A(P$3V>ZLKc`Zh!jguR9Yyp_2WFMZ}V*v$6H%!TAt#1UF76S+HYO&fn( zV|Nj?S&Fcxx6uJLeu=UEV%$`}6^4-@r#M&w%N(s&i}i`p#aPPHBR=qf!esvzMIz}a z>PZeM+)~bBUpThuDbrT~6#+oC0H9}V%0FiSx~-I!N{%Flz!WrZB?)69mQZF=FtaW- zl%@Xk$M|zTbvs9HP*v*9<_0G^w78}2Asp_?2jg8t4z8Td5N$%#MWfjbguuppTUP;T@%20Loeo2Mg{$>(Gn-p^pVcj zhY^)SiCERHeo{j2I9vNYmC%G;a#}5{xr8y!;T(V<6p=Iy3w_N(#(H{qC-D8GZ?h0e zE2>iqwAMO57buCShj5)_8w3f+LRu)9nxD`E00P}Pn@%0N8F`E)tvL@1+l>2lqb#RP zSL}mgL0cLkS)vI-DdBm-;(~^BgUBtE>QT@6n*Z zNvBWhDtjLJ1V*3EKWCY1fG=zIk0SMBD)JBG-8@UmIdfHjpPmtx<4nC>ekL$ua3h#4 zm#wmrF(!EvVdcyveenVkgJw`j%EFnWG>)!%eMd?gVSO`z^(owoIoarv?&5n|`OD}z z%yHNl440+@LMfB;#0K)@wu^!GkLgM?&;fDSk`B@2rore3j&|usct~v<`6tTSY`v$` zQZUGCU-sljl3wjrX*uh6c?7XME76N1|iLQqv0N(-xz zJ}y!gqN}-|9WYN$SfAACpY`;!_x*ugVr@2dJAh%Ubn=U`zGJr8tn|^gcdmGmpoF>0 z&<|wZuZARWrl*lBxqC1&2D$J#=W2d}wHjn?o8#W$Y>M4N7EU?yUXAcdZC3bzsM$=h zE^-=Yq`L5mfFILVQr)yXmNGvCfoJO{NycTvbW-c}E3rFhm{`5pq9=w`vn8m0ZWgmL z{N|rdyaw#H&D|3J$cMg_|Cx?4znY%EDB%gl6rZk~MJ~tH-kIzY)n^n(DLPt9nt zMkiFg6>AD(Y?&lgWxscpP5v& zq=t%TOwi|URNh};2o6K@Oq=&3YWx*FoE1??!AUfL@^vT)F~@ohF1U>*3g&2T6(3g4&9xk4cdAT;mCZc-Wr z9@lvq(j1Hr{6^eGJKLVltL~UO+CPh-6%LPb+hN%{SGC~hYO51qvbl-=IjPTko)>hh zOaWDtrazC|SykR@^_S9z|g{2Mg>0cZ!y?pk|RC7@p zTlUS1e*0JgKc|su4HR;d-Yzg^5dp|qO}Wf68iD-Z8le2Z5p@md;cNuV<0Xg=_VO-0 zL16?mvXn^D;n1~FQ;=%l^Z4?I2e`Gl^e>T&qeMb~5lpz!h>;-9vK8kq?O=4_qrX@# zM8CeSpa+6eiCKmz4e=eA=juFEGIL0CEh=y3=kRqsgfpv(cGMlDbQooB_v&ss5Qbuz zq5cEM;wmw^L(^DsP%I>{j)rhymuNAhdVVlT+~-P5gH*zSvNNgOTL*`d{WxQvo7Ie! zNJLJM=>S9W?4O>JJi*yFB-j7~d<7_QaIvylkkq{L;?J+qnNR;TO$?b z^$2TBmnQns%4k}@`3iIIHZ7C8V+d|vmwN3-UD}Js3QihIxz|#N?gji%cR?$Kfs13% z0Nw*pgW$`~cFgyqmRFI6KS>h!j*BF4+Gr(VaV|V5SG?@)-C$$NPG1KGwc~q8^DX z#T5d}@@lHwQxw{4VkstnZd){H`uFe({Cqt$l+&3|Ns@5ksQ&xyPN#9X12O*3xjg{3H8HLJO=Yvo?Hrak5O6Cmc&&@e?g&# z8tjq%+q|~AmPY5i*#AHImiSL!aQ_k1{#8i3MJ@mpBU^@NLjQ zbpXbXt2zHFzGMVIZN#ZWp`&iNdghnFRON1@aGZ`yZ_M+z@vL;$SRODBUIVOIKHl5- zNco`PP>A|Io+u%+Z67BJOia*7U?bl@chLgzAJYws%xLwup)Uc@!wXO+Ra! zt`#y60Cs>!l?e4F)wX@t_g82SqFVkg$Il+Ky$#W|8yuCVxDdT1sXu-9tKKhW$CV!X zUqx$ivKWQFb=<^$RE1KJ_4{iHrGq=B*%YlD{$iPLq&iK{%LRk~Ya^i~EKea_j_sHL zOzGw;6^@R#F9+YcH3DF^y+rjLSWb_BduGV%?R!3*hW+M)RGE82ipl$ z1}7DsfNtc zMZ?nL@zQddArA};pS7`Leei&`d|w>edVnGXF$7=iK>)-d=HH&HU>O4Mvn3GvQa1YO78DIYrBlarXQ2w({?)U`=#+~(H~b(A*m z5b~S%%s1lsy<@>lk6lwx#NUlh?dsZ>p!0v$R<1$cK(fI) z%QjP-ldH!Vk0E=$auxk5`mtqdEp4%k6!gmd7WQrb%8R`oCTWZUX{a6h;j8%UqFEl^ zv$nNSsNpMw`*IQr!=iR2v$WOhdS#R5faJoWO{7G-#h30gTQ#g(0Ddm(@3d*gDLd~C zY&r^*>$Y!N-2f`&1%1HQzP>8dmO&l@-@t%LzK6t})51dR6!}p=T9IXoh}x>aW)l{y zhqqTAtgc-)p{@5s+xm&AjEGu<~E{%Cx;X6T#WaGGQh9VeHeg z+Sa!27gln;M^j5Y7OiR04P_T`5iKk3kzJ=8mQ6llArq9jEm8q0>Qh6;PMLKIW9!Lq zqp^($OW*=nhx;nV4Uv!>W>#+GJ6zY&osB|xK`yo|MI_3^boAMKNWViK$qN;6w-d|- ztWYvbW?v(NZbF}Q~19zxAb%F8182soEyNlZAc z-cr7iiMYdfh{eWqd)Zw7-^n%2=zsINkqm))-?P0Gn~GTOjQK|2?v0;}8s>y7ytK?H z+$>IK&>T@}L-rsVumO+pafO;p^55we+Opa-hW4AzR?mz2nQ=cJixang+FJ<`=_dTfkIO&-l0L8Y5Nj8ocfm}|y(u`O9Ci^HYdlZ?A*(uJ>*o^4T9oBn7=>Ad>thcn?d22RurJ|ZBZ zf~!#&8ZZao;nFlLyh z(v$Pc6RK0dVlsASzOK!#g9hF9DihK@PQV=8-1UA5s^8gp4xpSvi0^Cv`9-`bduOze*WhAItjao}LDAaI@2PGN19J<+4Hh@+)u_r%(u zdk(@XHW##hIlW)U8bJUOW0vCUgdVh*I&$Rs%%qv_yq?&Q0Ka{oa~2XlPdZWFt;nuc zheTRf96BWp4xfCzqHs*}dg(IK>=G=vQ$T|l54Apwak;I3cp^DS!- zYHZL7u-ejNR^%EePYueJS5ylbNq2We)k3wAfrp!cMCrL?{#*};;uALwt2PDlsss{d zZf5EpFl*-;8A{{m&2vlCSQ&V{Kvy2DTi%I%oicpC<22wK~;)@xhOtvoEQ@DZ>wX3+*i7)HFNt3K;qGDnp7 zdrz4jLc-5jEV;Trt-PGC9f!hd%iFjC6D6w_7)>!YG+3=dK>Z5X4MUD7MexWr@vM;f*Jfh{(=Ux&%zVPtFRkrG zfSp_7MX|k2czso zYZGivwjws066pB9i(&I+7J3AK#W)DgC-X4FI=MiJ%&9fprI3DxXxE24fWBzi-r>(Io1;_h|l3If_c~evA#zg3IK(Ev-1YgC%y)%9IC204p|VZ z+*$9X;IuUMk+*XUXu!x*Z}D=<)-mwEByWBHe@Wh>Es#o^4xSh4N{n{Er^>EfH9bZF zh|WZ4ICwhs{Uht2P=m)?2Qw`_=XtxcBR%|2%i1iPC`+bS{pF5);3nlO>*crbvf8^8 zu#pE1!Ay{f=AI-p+7yv=4|NP3?7WyIt9t@}`hX%dfz(Jwoy6(@wgi0w12T4-@I+2v zhLbDkw1Zs!35^a`iWDhCwgImDAgZql<%un{PyMq#Hu(;!FZFejFALi9S>;ow(KiU= zEuU3PN@SQfI+|SSL`=S`l+6(w%>%#A9#Z!H$%!3V_PKH%(ICGAXr~=!md?d#T4PBK(0(~cCNfQ zSiBsDc7oSmx?7+yq5pmbKD=85jJ8f6l-YhL-8?6r>D7*Zf1YYv80Hqb&i>5+?U7wr zk~fWIbgm>Hj}mn4Try;u&_xk72LSj1q(p^Og#9D!W|CKhihnGEz~L(U=R&VZH~=@K zuF7f|PCVIPXPSbO3~_K=&qwKVR#FpY9OFXCKoq(71o5!X-&u%zvB)guG6X4~e#Dgi zxDgff@t9C+3`p^#8p&we3#My@BWg{3NP9xUdSS}SG5BuVW^)%To=+X(%JIb!EEG@? zA-kT|zSBaXt$IQh{2!>UsV@sJDN!#^!xVvA`)hM9m4PGONyz=wU^c${b7}F^WeFwz zRtDrw2Z-aNpWLZdjAMt~?rysbzEFId@dJ822YQ z!#$^u4O^(&r2>HXUEqmjrzMF?*P2{OVq)2PZJfyKA^#&_{3vK5>Pz?o@wQIJZ?vj? z4oWX(8yI6OO8_mn_+xc_;RRfKK|&-H^3pVp`J@IC^65x<&Zc>x^Y_|B;A2!Gt*fLa zV}1XRqP$sI4g9P4hG7a94T6s~%SAI6%A}hnnIsNxtYj~n`PfYd<~7Aqbp3tkfZ}+y zL%Iw8uPe=q&)e*P08uttKhCyTRPP0KrFswC_6zV4a@)_m@<^N4>g~RypH9zKKZE_3 z?Dc-z+23XD>Ti?=9BkK!E~MY_N#D@v+3u>I- zp3uXkA*1@pY2PX(NV3YAomV@frslSgCnR!}p-5k_peQTE#mOJ~`_%8Dd^}&Zr^LZe z)GczZ{rci+WqP&X(dv#^$wHVXz+-DbOq?JYRb-RyD%(}8=H&h6IlI8rPig#K?|iN1@mGzP`Kn=Jh7f9l22P9T%hpdyhkOG)CNsY(s$OF0atz0Ti#c%7z0 zA1X@w%RXg4Ot7Q!VEYl!au@DxJGP9B?h#VK)8Te8$e*3=@gGw~IoE&HzGHB|{c2x9 z_QNt>Tf6!__ueybw=ADbZgEE2d@40Vvh7^{l9&Y!_PvGC|6JY!svT~9IyI%&br5h! zbyg54$oXC6^5qHZUIeSJWQVh&xHyQFWEO*(EHs+Tp}YW=>(l?t%R%pW;CUGX_-|g8 z`Zq7baCxo=XF$dd9XU$;o0nrYfo9KPNrA7v!x>Kk9|Kte@1EXER;%>;vjoREhGqWA zrZ|{Sua0U9zOh*7plm0Dl!~3IY=TFScGwAdL(Km2qCmXcT;Dc!S_r=M3;qf**_^AWRjKPMWqP1c-(mKX{A4QNJ3*>n7?Ul05c}gnaf}R|5Kqb?k9LJ zw(6$K2S+JKos(%co128-Vskzw;PE}-o+_YbdjM+k54i`8cMi8=Hv7iy!=--Pjh}sR zw+e6li`ylJ z%vi+pdfEi)QjaBt1P*nAhHooW+)bU;6VDm?vU57YPjnrqI7d$k+=9E?o%pe5!OEd@ zN+=TvkC_r%Eb=0@6Q}!v`_0DjPflp{Fl*jUVE#oqK^b^%u1k|4<9noc=SwDStBIQZ z^mqQ-;r#8`2IRGNZpu?a!oyv>pHa3uhpG3irrP*>KhKb^@08E(-|O> zh|v%$!CaI71?W1b&xgXx+L@o_pN(P+FB9q34Od&uDXN>(@cUEg?Cvc$j!pZ9*E_1D zT9?)oR;piGgJDa=x$y|7?XShUttu1AmoCb21v`sw=Kr{TA?!wPbXz#+Tr~^xL z`ZG99#(@-;j?5vEoJ>NJfNRV_UIIc8d4FwD7jU_S@gcFmgYAjghJ1uvdx4LlbVY4* z=6h)Wdzb?ii-YfGk#&>s=a<{wa73$sS6(QvIDxo%ns!V9%5D@JN?eFFfAcRNF&m7= z?3Kmpbg_opcAsG#X)USelnK@rjuEclYrqTioAmB%FER;6$98a)`A;F7BF;0zI%E%M zGb|Bkwbp6BC#AaWhHn}02mCmI+eH8;nwe=|nd+%;uIi(!f0R^IF@W2i3vT2;)dAsXa!vr)KW}cZuC;MhLQU%T>r)wavMG0Jc8yR{RSWyJTu@5Li}6L~;6ch#SAyj`G#2TBk0DYBG)2 zhYb?vsh5ix1|)CBi6YNXNKR|cs_wM!nv8Q`0F|1c-RU_N zJL3!^=^|7Kby}KyB*0q82HbW{mJ>xu%s6#jl1NL&giFkSQ3Pz6fAb~FViNF%5X4zC z$mY1v;OJ)v*d&O&DN;pJ**~mpd(pLO%ysndBZ5PW=mkHf&q`3?-Qnyn0QOx|g7pGz!tykGMh3MYGN^PCDGcme-(hXI5b_H3b9`8PX{hIoSh$Mqz zoWp?9^)N^S;^R=sIWFzJLHVi3o2Ac0>tfMyU;beQc<+P(uH*qrg*9LjO}&NWbuU>x7K10f!iFK>hW6~Ik4hlPps`K+D2!OiI)D|$^dkt=?oS=CzFFK7r9v;fmZt->V ztkLBC4j0`uQIbo}=YFBB!ZBy|wt}H-)g1s-C3`H71VvVf6l)IUOet6%*H!s`k{0oW zzlfhmAq#|p<)E8wW~rB^)^EDTU?bT!Dxsjk)G9~V&(do`=9Gv=kt8qv!8pfXWc6T7E;E>ZgudGT6uJ_7Zd5fk-pm1Qqp_f zQzn^D-t^D?-!1>=lK*@F;3)?&(}LErnig?kfmEn8;av87bdoV)@D z*>3+pU}|fs-rb2v2y6Db`k6T0thar9U{u#3RcglmR+=~a?RhQt&+(=YU4a?5-eBg6 zmFghv_&09cVj<$A-hZ?RXN)jK#ah6nSb+IxNJE$Ui*mJyWS=~JzNLSvQck2|RtIrpv<82wwRjIqo9UYt|4TY{uqC8HEIm*yQv0XhDCN?2J3j*fNFS44zQwAcZ} z)g4B(a5IMZ5HKG9A643Zc`@vo99M1^j-B>cM3DG$?)!v)<$iB*B))S;St{<^Qkf&J zI+>aH^nMsM^OTiNca-K~)}p@kMxpDl6D^S$gdO=6wV==>l8xUh>$?j)R@_Ec%gAP1 zv7j=E*VAPXl*=Gr0|7;RXM-DyBlVx->4J8S+)hc}81c)QcRDwX$^7teI14UcT~ZLy zr*oJuL8l=G;X3X~Y+qXbQVfajI6rWLeD4~#%!_0gNDAJpr-Wshy~O~3PCB;=0))mR2Psf;YQWvqGs2P7j@}lLTx4(XLqI? zS&nnn^UjHe4Ug%#doNu*HMm)yU<%c6@%9ay->d#FnJJmJwy;WN41c*i?${k%O~@V2 z~Nu1;4KKY+}5y73Z}L?{Vow>XS0LzSRjNfwZj=#Ygl{FOfuP zm66!=@Y+#6A2aw)_}hrCwQ3??kecv7!7|r@Lm~g#N`&OXEfpV%=Td`wITNb_^TzRI z>jpR3YC==f^^Xxj2B%(gN~Jp7KK@Vqi&>6<9p_Q%CQMYP4> zk>))C4n3x3y3VUF6q3S^V?DW`AXWc7U1WvxV6;yOCN}TG&J2n&y(MM)+a!orF6zg=@XBM|@G5IpVH}hA3ig(XJmP_hx*y`6Nq8j5(d%T8h)vHizm|Na}*VI0&m z<$nDhRa0h7E%q4iemjvlW|ny~?@46_bJYIDNZTYgC&YNQ+mI-#$x)$GhWdFpnR@X; zfRhr(T*96fE_@nmi@{sWXv*pDHrKdeqg+=q^{Mv7L&i7pz=@gj0lRWcjqepX*Gu3au~pGJZ5H!^ILv(5#W1lqFn@%{r0dt~RYei9M<3(v^|Vk}|& z1`X0b8l$E4_k`C z)6CEYUS~$%;$*>!aVXv!)$BPZoK=aG1zT~%{G^P(^o~7ZB^tq{WPe>zMR)I zKJ5UFzwTqD*!=6yhflBC8R_60-6wg1zm3NZWCznmectfNV9yC9MEr67jEDo3R_L*Z zjL6{q&`v1}s{U(X&)M(_!^REaXxmbY<^%)Mq*GAzBOXI}*q?H>c_aFUNBbp46ttAgp|O!4`~$e;>N{dH^J7WFme&^!ejdpzIr_ zYU!>k<@d~>NONQ0Yr|ls)kA#hs7>}hJ%(@}_NI?d!?n(#zgDW#!4ut=4Fm#TQEQBU zLx2BRiJSlSt-u_-;zOadG8X7j5D)kX^CMhvCBx-D_{+;H$hJCFvjHsg{wn-oD3*`f za{JMULgvv(XXxqY`Omhis#vHU6R{SxyIinFpwWD zku=Yts_P~ERVb$>MTbC?8i&iK|GOR6t8yo!0IDz-bR1@Jv+?0Y5I9vH zMH6XZ=b#_Z9_*Hl68=NHs;9Ovu_6aAR$%O}c89H-eO2$_#b`^XKbnGFo&SmXt`9{J zKlCw-x##Md6z_T7o>7lyOa$3oxR?c5R_pxTHD z?|@XeN#h=N9UpPAb`gR=20^RYm1jPO$-p5;TWmZX^orSl7z3xcNtC6Q#cxG7y z_XZs$iT#>Jc7*YH*JZ9(_TY)+djGEaPseE9zR_Kdpy!kal%pi2u<#u{=H&Fc-0soO z%_L#Rp`r#$lP@%5E%|cJ!1;y6<}W9cq^6KM9%e>K1IVIwR{kZ7Oud@;_F<>S8u%aZ zLjR2#JylskoV;V-+yj9ShX~dTXn}hlfXP{JC5#`kX@b2g*>ke)Vd>*3BSfli0^|y4 zV}VHV+)7vSl3O~AA2@z0QyR1yay2EH-2R;SapTh|{h>hM#b|Ctf`Es%stFMrVWw70({@)?X7~y;j#46qcnhYwQ*aRPhXah-uKkK^sZtB9)H_0+I z+C%3>3*j^uXpBBV z1%d1nS_ezGZ5%U4$l;48V zc{Hu%g~_y!O@(q*C57k@4A|4ocTgZ4NUAx|fd_l#%pBzK9Qt9F_$VM7fSmmq_?mLx z-zU6&GKieA&)JLXO>Qxs7Gv+2l%tjT$FDz{QD^*6YC;CrxjBdH>XyAKX{p4`8{`Kw zPlrDVm`BqQV|WgVbd1@h(vM#PHQr7CSo@wL^oE1CfWY;D5o;*=Pbs5XM9_9Lrq``* zD2rUyuJ`x-IfNWubs>%~8I#q3R&AopllincT+DovrBJ?%a6HPS_IeV@~2dwQ2;kAVzZzXpFIgd~JwXSH->T;~ZR4lZZS7r$7L zK}gkN+cuJqsOc(GphmMk-FAmMWjxE_a3PC?&=<>^kH`DhkmjT21@Xn@SaNH&Qc5c} z;TUKtl+yQ3+6mD%=_s>BqDq)=T3nY(Rot*99f)8x63)B zbvFgr@y=T$MzRE5_J!%x;rh!bc+k)Z7E{n3(whOp#fVxR7nA66Gmy7|p>P$635CWh z>F}xmwgw}$Xd}&=2|P-6rH?@suZ;|L4r~BOVg8|NG=rT&z>lZG}7QYv@wuSdgC9oA7 z^qf|qdI(!qI!+s{KJIq7Rr8EoIX;r##%X=2uM(qb{=<`62&2uW#sJ;DSUM#~GD%RT z{FnYye{5W})IykKO<>C1x%Ww%efQ4CV%>IWWG^wHY8IKXP%p%(!~%<-<7J^ws=Ctg zTG{yT5z?FYarD9kx8G5(pBV@yxhMG!Ik&_6$x732^3~?jOCd`2lgH!At5e_~gewgT z7HJ5H(y6O=-rzA$^k}w$T$bq|CV+^d$d>SR>2dkp;&mf1yz*l{hLjC%lTJR$|XFV zvoOE&Q}3XNCWIa*(S}2VnPpKZZGkGm`@$3Rd=OjKp$|QIUS)XrXIcBKdWIMyuKY}D z2E*+Y0u)g)kB6a0Sl(yb8VzIAQ(BtYcyhnJ!5%zqTA!twOzPe&2DLWcizMz(%x;Lv zkM3K6TC^STXL)TZ27gBc`61}~|KjI_IW90S^T``y!gi_s`7Au5Jqw8xTn?_{nhHU#mlOfOh)@bJhlT#jxeSmVH)-^wQA(4!z6>_Ul4)-S7v-O z%NWhLAHV5gAbR zgzF4t)Gzl37k@`C#mg$9*;S~UCa5Q_rTQmU6A@wu7&?WKPIT_nLMA0!5*=*PmuEX|Z*-1}O_jD}d1_k@MM^5{0|@kho-WmV|HNpdg1qm~MfHoL7jJP=j8db_ zhOS}MX?F+c2WHLt*70nt1-AOAfYKN^>nQ|WTjrNZRVl2mHq?OLN{fr0Er}SFe!2L} zPoG17PaH<4vg@-D`vRA3KNt8GMUSq`J{?;%nC5RBHrMZSLn%ouY*cA@|-+!@{Y%KWoDQ`5ZcCJ zDfHbWlgHFj2^0-R`c-j+R}?~i=&MXx*=U#P;>b9~9;^e2$AkN^#1#)xlG2{DisSLd z6Xp|U#NP!@d6kI1AbqKF?Hjn5^;<}(WArO-$@G7Opv1%)0r72@GWzz^YQyUOFvxQV z-2r+pU%Fp>O_DN6q*6U`&8C>*Mio~|kDT;lW#jVuli1KFmQ?1Rq>tpvKoPesNNBYG zB55;zDXChYV|^A#NNYa-Vq}~mhnZ+z=EB7FMef~)ySokrIm0UdFM7Es5kx9O=xURi zt+zw(ie93}`bofV!Cc9J=wN3JY;3^?4sOGq$H3dsn)<}w(+z>e&K2|YHJ>)Khn{M%jF!H5e_^1; z=T{!>+DQ2}MVOR8loVM`gH?9WVOCn1^{cjGn~PtS3s7xFeL8YN>6}nCNMm715dz`} z-|V4HYbA2WM`dQB=a2zC60;x`04dswvRP4#?7WfzO)QrZU3<(BtV6^o#wnXHv?1mC zWwrXQDHk|z-W3-cxj74eH&lU$W3kaXt>y`;$I5Eg&H`5+7 zM0CJu^KDk-l2thj>lj8!_&IS*uu$R+b8}g=6uD zt%2+3S!606n6*7hl#eTadF?QeIMWo-4Hr8^=+5> z?b$#@eNHlrm(Tf?-1(&-5HwPz(e7Qjpnu>S;651!+w{LsuQEgS^?V!)BJni(5{16zY98C4UWN{BfM|`OydrlG^Z2c4j05WmYY3 z^Rsn_$IDr(p$HPOQ_Uvb4v+6egfrMT6twQ2yl@ee>Ur6bo-QR?!xwC>IWiFCw=WH2qLT$z8E1pnmp`^qnZJOTIkg7pH-1^3Aqw9}LiS!JGt?dGs;p zEDmSU!zPjv4gD(BP^wK*6C@#qD2@X+T=0=YbuS#zhQL5to)?`q_WaJxIV;*(8Tn-p zW;>t1($o#1PSL}7b(?l!J#SgJ`oFbW+^bU5boM4#@cS)G8?Xp!scU92WN!r(wDKq6 zP(jDcXcLP`6CxVgr&+(x-JqDt$2U}btnr>>1ikl-%tiZ+aT9QO(fk#q1BtH>gi_=1 z))M;UwTre>d(M!bE@HzA8nUu+|2FjlF`9wr@e4g}$;9#Q*4i%Kjq67`e>W(hfpMAE zKrl(RXSUvB3ozf&Vlb^MsCLh$Xl{h>-rklz!(WoB3XcB;^Q6&oYgaVd8Tkpt=-noH zA-?M`@71q8SluPPu0dP=%Vuvre9k7M16uBa@D0MADiOtMX!~QDU_w3 zVsmI6Z^!%Ql-4v}Y-e2&ad?D|dHdFuhl^e)a}8g|b1nF0t|D6BP7>trdpY@*L85es z0q=TawB2)yydxg-HKY61%Dn>ft@{kxrGO1ZUC0llxIaAO_xo22ZJrBJhn#F^;t@Xz zWBDxKQ_~D+(zE`w+0#dCsoE0?0nfwndfdJTUS*e1uhf^ve`2dnr$ox@!K6|O7R=hM!|NGs+5Gv^sXO&#C#l-?eBS#Zgl zC1dk`RT&-e37(m((nJvBmD7`zGhZ{S_pxXYl zsLWs@<0CWnvwN!{;0f49a=8d8>oOb)6DUt;pbT_Mu@f0ol~4(zbSI9(c$ms}{ftI$ z1kaNc!~D8ntRhye-n_A+#Ocuyo^0b1lIJ0JC>X;7GK8R3%jiV(^B6ZN`0o^_ig5Ng z)Jsq@X3UQWekjw-Md#HHdmM8{JTszu?fdIKDY-u=DZQmDvsZ1*itO&I;pGT0&M2)- zG1)K*W(58rd`V7zAJh(;!}p7cg8Hl!8BqQauUXNGBy4Z7_4Mhxod_cBuq zS9MR8_^JH#FaXDIri}626jL@}m=^YBCTwXtc1aeNf<8aAEB=PL+F(sfeA73JYvv`D zGv|gZ4a-KD{G-qyIILFkgVlAO{UxC;EMdkEpz5=j-g48?icBo&V}MNf=wWlf8epS263_7)zyBYzoW7_I!2ry;2 z-nvF`1x*7m?9cBm20i^DdcdUMM(4#~%^Tv>A6r3wEegY_aWm88#WmPJG^;uK-t1+v zV}nWat`x|)91DI|<1|_#&Mn;zZmDQ9e%IuC6!i*?R#deS){eX zX0OuYaGei|nESDJEn^zuyXms_Vbx6x#2_;`r6-7hl6-M7mnT`mrl_>O?OO07MC857 zN#nwVq=HG&&DjFa$!T=zh;@5+&Wx>nyi)x@tB}zZVw>w2;%iHylVt%g$G1nL;jfTF zC=M?JgCfzqUV6#b2>z*Dm(9;Fc0;xiM>oJeU>54Xx*dPhV|~h(6*-g`s;h9;Ln6zQ^>0U9hb*4iTh;}yWZ%*Ow7Zg82_ z*e`_b#bmI;kIsXZm%_U@#>aCD65AsbcI_naD?;IPn>XKoT`{{A_g}XjuVq~IJq0#G z?54sfUZtS}inITr-T?shetr^$@o%7~U3NTSfbt?J5-cwxi-SP)Ht`)_elFW1gYYo~ z?UtRrM1dPR*?OdE3EHcU^hSNRy_=^2-mJK96JV;^f2k}ob8ywL?cV#zik$8N%pb;GgmIp$XbV2 zL=z)ej3ew#*<92ek$s}KOZgHXll7h-FYHUF(v;;Mo^=|lM<<>GIWA3Z>Xjd~)eiu35a+J|w^5>cOR>R0Q^ChG< z5;hT{YV^PB)L57FYrRMf95TIcHMKLlHrqV9C1jhaseY?dmOyA)CFf7U9gDm;q46Sd z4b@g_k{{;^n6pdX@tQQ{tXUF>i4-+o`3N6iO#pq{;${O@(beI9*f9oH*-`L)Oary6 z{%rp^KeS?XqVGbD-v;Fvc@?BHxr#$zc1bB;H&X@1&NAv9x%#)P1zvx&2#~bku1zFo z_Hyt7G)=c{>n-tWfW^wvQdsyH4?b!2g4tYnIkGEadSEkSsZhrve2F4-|% z;8!8t5Nx@9=2f3hgyrhIhJ-B>>?0m0zPfko9$Rs`3;!48Fnq~wk+5I9G){heSV^!+ zA`NxP$(O)R4x+k-w*l{zW)V|gq|n$V0(2=NB4hod#oL-X9=48Vw42*+2XTd8;aGfNt)1@y~R3e)v5(9zBNn;-vL1Fb&~w&HENP`ZA#xBlEj1(ZPJBkCI{{4EjJbteHRqocASKue z7BS}0TM{v%6w@dG1x*O54Ui306Zlc>brUGrSooG8kR%Qas~$w!zfQRGja*{sT#VoD zRY`R$C@v2e|MvBy@F~&x)u()_9-wDLZ3}PW8(A%x>A%m_Ex6d6BCbP1gSR4>xuKwf6^l?A!qbUdopbdOBL*URh;P2cB+%wI=zXJ*T}&~5g3LI^|2g?pip zL$gbC)#(*DPGcI4kLPfp^iN>iCp>DDN7y(T9p%*nk~f1;}UYFRaBGK9r~Oci?rarv?K zK_)v5$3fpz%~a<850;DbmirPjysHBkf(ryP2ule-LzW$||B`=rCmu_BMI$R;C>`6u zLd;bjsAuK^7c{MYT)xbS=MT7oiar}Ho_TyETeq-#`&G~*1Ebmu^xnv;ryc>>hC*b? zu?*YMrY>l5BlDLRK#EME%DD(*HlZt%j*>gz-T+@_5_M@O6N(7*+HbToJKtgpK%E`S zPK`j2P|wiau*HcNok}mhW47;B%V_AdLkS0vsY5QggBz4I@x1)H(uSz3gHZO{E$R*} z%hsi5Wv8!g+ak(9e}T^f3KxneB!pMgA!jg>5=C2 zzQpzFl1=Ksg=Hm|^rxUnC?ST;f%%0BHSp!jLdD0Q(4Bal$d4bw5#qVP{Fjt!Dem(4 zb2^5G+8~%Zb0gqdbp36fTJiVWi%_H99f)J9yzl#E$ZI(t&A@3wH6#rtg@wWUq@u4e z3_pWoSY=x1UoXZfn!sS0D6;hX{3eDT&$zbDi^MUi8%uslKMtvU$4VIT&Zx(ELR4-> z9>_y+$yV0!-_)jxT}q5)yY3iO%8uC={Bpz(ZD+N>5SNML1*H=TRH(WEvK9U*mfCI8 zkk$PhI}+@Xc`m!^{+t$bb^2~^my^KXRgRoh#El+$9@-jOCbA z)=7|*CP}0}n<`#F+RrdNN@NYpSbgLN`s@fd9(T=zCBJt2mc57kY1^L{Vkj$C65aRs zH4t6Jd6^uVQ9*N{ZK{0Dj8mBaNC@@4DS$YUQQ@UkBiBukG_gw#1S0#c{*nl^nWF^W z{5+mZVsdT;Ztw2Ks(d-{cQT3glVioW%aWFG3~Vz9v(Fwm+%2q(hf)MpUsY*nT09`8 zIDXanrAxj$ZG*Seabb7Tzts6m*lrbci9Yg}!`Uu0ZliBq!DWDFAmZ7fJ)K;Nd2_(as+cDd>=fM;#EzFjAaCO6^rJomQ;K8P0eNMosM-zFTX<+Tumxc&R zJ9a8#@VzR0D!;7kDO+lw{9?PL35s{Ed;DYzz*^Nn(FA=IuXhtL8&~&FtxVoa_?|6x z2Y*c-ysB{wFc4i-6i!{#^LG=w`uS_bxFh35B+5v7XQUl!$Czi;n6zsxDlY8QU;H&g zQR$7Q%gfa{`@C@l@nR38^f&&#{+BqKTW(~C)e}K%i_o};n#(b(Z1>D!Rzw(OyW%pq zS)MsAY?Qb6o5S67ru3VsUYE0D>~|eIfA>#VtrY8$`#xuyV3(9f*~iDWuzKonOXnTt zl&h%6UZHX(eWnWNB{o5q_Ul59^bWyu&Q*8xXGemcS_C0ge30k^dprNI}g1BW+Qu z7jh#~I-9=YIJM3rtM%O}mHvz?+{YY~HhD0>?wq%{6(H@GI;-XeG){I_^%zbi)E^{u zCzR*@U?DlAL_cQl-M^E?CclEn%3FwGcl|eWQOu&?xElO_sWu;+rM4esHLR^=-y3Vg ztWRPxMdDzw6%ciJ|JVTLDG_v7Egj!yzojB&>MSBAHE?%x5!KE<#H2v>v?|kIlZ8y~ z&M1($;_-0Ka)ovK+II>+{L)ZAN=$U>_F3c^0PW&)e8&RY37jA*i2&+u?xJ30d>2>4 z{uCo;26$5=Ix}Ne9j5|OChn-Ie3U->BU1PN4#xiwY8NSR1O%{Wk*DrCj|92tnMtR| zV6r-h_gn)>Vj3N-K$ybGUBeSr+Xh~y9C==r^;%@qBRoK#%0FMMGCt|xZ8<1Niub3m zV~e2&8059Tn^<1BH-?Axj&7tk{gGe4{T);3$AU)H#^gVegFO%d*-5FmAN^z8MJKz% z&qt9U!eQENOsaHdj%KOwQ%}%ycFontW_P)gynHSrp1&DwBJi=ScKEod9>u&FmfQhsS}7SJnxuAZBBuPoL6o0+EL%4svj%?%9ddA&!Vk_8pqUm_Q6cG_a9R-?)3 ze2QSBncNL!t@SYDgc$MJ)m8Q?5tfkRvTMxT6~y1A!UReTz)wJ#-6zFTNFxl|5Ty?_GtGY*H+IhS5%OjHP80+-w!GV8^U#i z9v14v|GJCJOHf00J7Z=n9~JWNK5i7lu9H%k(qxQwZ9;je>UdeGIT(F7P1WL*z6-X% z=ZB3%VdJ0KHebog#HQHo0aWO3UjA0sz*nHij|@0!YkWerjUcfa5?PtRtr#(Q8$f$o z6pP{3{Z3YXxtUZ?;UsFn3CVkzx9A$I=|NIS#RR09rHKVr?b^S@%)!* zksaGGocWLspq%-gspgCnqkLulZ%y}OH>B4bHLE-Vg`;790Z-mP+;BKWQYkSFlu)&n zf%F2col>b^7tT_~26mZ5HRvHZBMB@uhz_uS(#4%iPk-}`kH=Ye{gzp-Td zgrL9P-bfj!lMe#M{FL5KUc-yTj))wbU-Zolpmy&DCRZ&tue~`4LB^$~6)nB7@7~M7 zYm?PW^nLeZ$9!PjuZZ&e_$=y{G6UzC3yY`;xT49@HsFTVL|+i`2hTN~Ipm|gEa>~A zKj>_2j63)(c&NtSTLydDaSLRR^h;_eHOzD$baz>x2EAwlD3r@=(;$G>GG8$bg-lwh zt^8KEwjoe(xTH%D>Mw6!pq8O5soVrP7%oU`d(v;JloERk!?PB2-=7)O%UD+Z3in$p zuXk_F$@T4_1Upqrd(M# z?RTwf^xBT0k-c%$;}omHxB3Q_0vSG?qo&{cPz9sllL@>+6Wjd3%eJe;-d99wE&8HXAlPqk1&zKtS_VV9!y9L@ue+E;%N-s zG$OEhpm##I%p*)SF)bmVV=!!JFB>6k9SEKzU5XmIkAtN2~`@(0Xlan22li#gi9k-MH5Y4 z%Z#xP(^2@A(}Uh5m$sIf*Yjd{yM(ZVJ2=@#dDwG~Nf>4-rj%q8Q?;Bdh`E|*>6rY5qX`n+XE2K@NKd@nI8h7c=sau)TpD=3+Tz|sFUM!p zJmzzJ@*uTs;&Rlg0p;XfjRyG*Crbt#02IaE?rTsacfwvcl1js$pr34K-lfbvcz|eG z3N!Z3S7+MB60d5_)%`NH0DGlND}1jvu|Fgc1|5aJJec*8e##RMIp z#&AI3!})T(SK(ePsGl63QEc11DjEeO;`Oqg7a zdPv%DxNQU&iHDVcq#DFM|iccCfhhkTQ>h(#jf+LH9HXxV0dQt5b*05^X zO|9Pwo?f<-|A4S&!A;vKqv@0mFwZ6r&GZIW=edeyt!<_)2=>&Uh-VhwTM(UB(ra}F zAt8AxcLHKc{-UXHri{-8%)?1elSiyAC&Fkq=NwBuVd3d=-kDV(g!%+ zu!$-lk@EeblZ1CGi-tSDf5uz6LKj|DyDEM}jL@%JJNP{+lh&P9RC|#Nx4kuCwB=Q_ zVRI!*5g~01oE%ZCpSQX{(-KO~U*@+9n_;{)#u2izbq8a7%dBTG4yxF5h#lFiz5|*N z1^;-@cKAS)USZ|R#>DVAT8k`e?BI$HB%lW4AQ3!A_@1mjA;%yYM5sKt)~|m<5i>FHubwf**0#|b z1y}#lOXZ4{w$)01(Byi-v#|ydqx^`|qYTq%6k#xY9^EI&c!F-yw7V04q9~XJZ4P;c9d>EK2E1eopW=`~-MQh3V|=Fr4fXTeA&K;j zOE2jjhrgh;Rr0(8#JcYjT|36Z(AXq*`KRr^-#>LcFg3mMhth6C$M{ZUzjrMC3+Y1} zyYP}@>qGRIzx&$jLGER;N3 zkEMUtjt&bed?QarYz9qtjrOHB-sq&euF~o%8&*@+B(`!%BeX-y;J<~lv7`era#h>C zX|)ryv=Y{9pB47S-{J2LMQaC^h`S72<4r&~e@1rk&kwe+^j-S9XrA%PAiF9_22Zj4 zXnRr&k>qv;@+Ht_cK#14>%8=wXIA3lL)v8^5ZXW%!qH}FT1P|z&nO&L)ap!`zpRLi zx&)qapvpA;<^%O8#kev-**8DQm)-;kNm;Q`>$v0TH|4mLqYQb?ht~R;YRsQ2VKFl1 z^h$q9dqdPLU1e^VPQXc;UhNM1o4IPL)7+JmW)*&-Tya1tNrMjBCNXuS;+?0)VPJN~ zWuzdoVuP@jVo^Zq>)#>Q~jkY~VN)o?_2{hMlH*L`Xzbgi$=C(xa zF+Z=wUSI}YP2sXq?z7GQIm|IL!}&OuVhK1zYSXTe|D#gJa~~Kd~%Av_L^d+saqp z%Mprg_X~fA)MJv*S=c@t%ufmGd-_%JmgKlz&O%Pbu;J;rrN5+2Ke2E02xIM3-E@gx`FkZDNBvoxb~1U5!2bjP2U!5V z`q!EJcqrD6OkhoqJ^?IE*mMvscrQ8w+J)|lJFjDQc@o@rFoUdsRiW`Pa@_mV(iyHG zSh(k%Fa1xgzoBe~S1!3G4}#}u>T8AepOcK5u6QH9VHxN&B)=d_0#GF5Ql&B=eUJgD z1*6qm1Tk4bazVyrJ=ydC7gm<773s&gONYqiQX!JdQ%sk@{N0a~`ZtI0?rsfboN7k0 z$U|&PaQMMKGN|CS(n%Ksl=WIXvG?_s%xy&J3z?Q^!Ph31Z~`{QLW7|rmj=D|jQ5Kl zLkF2N_OTtE7P1>Z`8i!Bl&R}NgcD^q;`gP#C>APGZ5B9pSCT@B zrT9tll!%944q^H?Qr5eeOw$e}J`Ks?@EM8r3rzF?l+i?)uHk3G2A4SfV3&Zi#3MXS z9xj;&=APZ`mKWvQ0$jskL-P8as+Bnd(tjoJjXSpFZ+OY`jvGL!0j2L#Q5(EjKvp@0 zK@(1OXUJ3EY(BbwlHq;L%$xO~bz6h;M#GnS!g0Yv*|}3O%(nh8n4E+xpkJwqs>+|- zud^qzD%O{Qqe*C+MFM;$h{qxHvT#n^6pnG1^D*C*p5QW8^@=cB@Tf}DB}!A=tykH^ zZjDMmShk|AC+xepx+E*4^z&T4ncx(o#VeE-QM?CMeXhK3DVsnv>hN*i(BSMUEEEPd zw_)#%V+(l>gH*5ZiEb`f9 zm_xTLj3Zl|<$syBOwV_iE!rkFoHA7B8Hj*4k?>{c=`Xj}?LFKvK5SW861z&DHbgVz z3Y)icv#fZW?JIBT!F*Ok816-DfR;smJ04tqg=)7=r=e;Zg1gjU#Y-Rtm^l`92%oWg zoWKArsUL}t;JUVNI-H>FSSmb#i~6Mq|-gjEJ?q4p3k?9#7d&)@C3_TACdBSym@h;pq_ ze+y7&_@6s|AZ^MW(wXS`cBnxQcL(U03oQVx+sU-re0de<&QDD&g0RoB5TRW`$2bym z_=%g*n$zIROAXHIgabYw?%;Foz{F?co9z7VAM=5~6|697Uv&NmJYEOklcH3AAYBU0 zPLuQanWq%(Jtp481B%k+z-0aM)de_Okt$GC)F zz4g{?^}6WteE5#2c5s4QkqO%$lO~j3d-A1F6`0kUAp>*XeHE||9=W)_xTJ9K(zmYf z)=CJ8$T7Q27~2$UVts}~U1nxnp*z;ixXG%?FGfhSwh+;1Qx?DGeVv)?pcsvk>@P51 z@)A2r)GSw|;R4R+QS+S9L zc+g`dPS3}GL>OOwzxP5B0F;>!<+m8P`yR)+QayV{Xc1Z(_>e&?VqzG=u-Ftm%6OQv5?a^Y4%|(|XqG5YN={~HK)W~gApp9{krrnb))+<^ggt^R-_ zT`}f9zooY1=Ba;DWn0lw#tj@P92}Qj(YS{72JO-EO!6)tRFA<-+C4x!_kG8qyP;)! z#|V7J2^YAPuV*%Dv?j5c<80q*IFa)nE1~TAGFP`-21OMPC&i8!@MqA z@8|DVZc^PV*=O}`hPZ?X2w$ep(&4Y&XUa|3Y0OS{yjs)R7JMhvawQOFboKPHiTd-a zopH{MEh`G+k%LUk;!>>Mt$``b6p{pDU&y%FCBc_Q%+CAY=LYMuaK=AwHnP5#X_dB5 zG+{i$Ja_v8KlA;Pb4K?+vLekOA2a$Ak0;%>qO}sa-<`d;W$fOVCF94>y!tu&-E2@O z;k1JSxrSaZA?>%Rv&X0Qgj>n+&^LArWRDQli}zzO)3*CNJ_+w^qs!{#{!Bc^^}a@E z3X+iaU^Jr+wj<&##Ii;+{AZZ)yiqT`MUB2J(aKC-{0ifRJZrLq^wj5YA?>AoGz-GAaw`* zb;DjQv9}QwAzR{6FN%3sjN9ke!<&9rZBX<+tvnw%49Et%p5Q5@pfsMKKTp(O);-rA zNHxgo@=(UPZ8SvktKq2>LGB1OU4)w%s}F($)bjjjfaD%7z^xP#`$Af)StMi0xGEfq z#7-Zq>IsWzCGfonM4+G)8h;yb<2a2X$7Bh=K>fh-$&bSYgstUxw zAD8u5$k<^h6*o70A#Qs1ME!^{6hqWb^;3S=_iByYx#(>br+??P*S}Rjd?F&KR9$I? zatw`(+qYR(i5u)GJ9rD<-=7VH1*Jc-TUD-cJ=QTYEs?{{T=IL}+?g@PZuawBjs72+ z&cZLMH`@9`cXxLxA>G|2jWkF%NaxT9NJ@7zG$;c|cOx}`G)OnnJ@5SPz3-oJ&T~HN ztmnJe-un&P^<1k`AcX~`-spWseSvzsy$!~_$wpH3%fT}Y;$^>n)QSRoIj{rs zPVSB7tOS;msYp3IN>bUyW@*?-!%eB;k4ckD9OiT`85DSI3|&=Bn=wnr1Wlv}yon@n z=IO|WDv&7V*sl;-#A6ce7CA&;|r#uc8na!JujbGUrh>$RaJx161 zq4F`Kb`uY^YGN-yCS@W{=Va7nt}S^ccLBPN&u{6=(Da5L0?_oj0>sxGFa5p{eBRET z51@6DVE{$-lCzj?$PkTDl3&Re<25%*&p<8biX4>2AnsNsoy0@M1Ctm`^gJhI@nwyuFski!`kYNb^jo?L|9gHu+c|ax{jQQ8SdWpSPnaA2E#9Gn9pAJh=b~kNEUjuv|btS8`J?0CTVQ5gZeQwHI;di0_fIw z_LTfmYGkmjJ#w{93NDE=AtMJsbnld# zpqhPwA^|H|kXtLgqxn?n-5u+(QkY0>DM&?Lk3$281)v1$Fli1362?e5{!qT_r=B2m zQEJUeXdB7S^Ce#SMGG*c#s^rmz`Yu5y46>`V+I6qry%qe+WLs>bitre&lHu!M=x8h zXtT~-hjX2+p$@eDOjy@@!%^WMk`?W^bum}qL9OT^hZm{CdxMxOXu8>E@zt|nWWd0g zO!*sy27ngDg5BnD9n|sSQ}*q6)B9-2yLvL>ogth5+ZwXH@XxsHupH9U_0yI7rCCsF zPsuqs(XBzQ)VjI8+i0DB))4UbqZULhx1Cs`j=(PC6?^>Fq}v1eVt%ZrqxXv z?Od}s0sx4Fp^>jSu}oEIyAy9X(;4nnx#O}e%NL|&k*@kd<{m*xA2MI z!$&C^r;^}|3g=i|y}t}Y+!tzBr}HObAq&sG?n3d}PHRagd_EAgb_0yFqp!uZ1efXw zA{+}=JZs#0Hw|WwIvw2>%V*NqOb9ObPuj0ZzL`J|MG#JThAf|={y@{wd7}v9fmR{s zP~YuiAhX&XsU*<>hz28E;^PwQj%gn_T)*PE^D14^Qu&7mFNb*FPzoruV_R>MahrL3)<=fdwE^1F^!@CyO!|rtu-@9@}-!* zG6LunTIC*seLP*1Q$^*7+a-%NNs<24vkRD%ePtsc$DlFbdbkXPvKz05+{Nr@4iOLO zON#1JwMnu+YtO?U$j93cmVZrccYS^KApUi+wq1Gwjr3!b7~wp3ioIV+=n=!E^yP*B zSL&_HC7vCBE~T--b#tm39GdUB$;f9uc~Zyhpv93p z1DfOsr7WY6VVni8Tqyy#zsUQ$M1fQ8ksWW_TIo5J&}qg1WI5AqzfPFVN;RinpJFaT zo(sKNe|t2fv)V|B3I%Es-3}MfSro;Kl8_d(;jAR_OJU#Hmr>@-wHJH@Y&}<&WW}w> znw6|5$QfRH#@!cD&%Xq{rMsO_8K&C$qkFG#eQMk)2unjpL%Bgjp|(y}x)M@~evzhC zD!}FT*plMsn;uCyV;y*TM%n$vrC^rQ4>`_j3R^42-+RZd160(aXygE0bkl#K@nQEx`3Xfzn5bj*uEK-Z zmqa!mcLdEQ0WWnvv0XOPnmX{bDFHFE0b`imncb14y+O&b9-Ks6_l#snr@*4hETM8m zr}}>GEP5$>*Dm7!!ARnmY^D*;%!ggo9 zempu*0cb>Td|%`LjQoh!#Nf@1g!?!v3J*Ruf@liDfx?%v!`Yl}pE==*w4n!0DhG{C zsR$Nie<=Z?d_1$u&3;9aeV_9G?VM?BnFeubAmWRS_!*kbbFKD!r1T&PGDtRVi0$a7 zsVz=PX6cEwV9*TpVc$Mu3zlYKoac;J3$mvJ<3UM(MA&a>ywCvJ1Fmu{?n|ccKfKkj zeE>5i*(~D1ufR?T&SAi($m}f9S0^d-?9=q&LMjHc98tfM384^RBxam ziT8;ilA&Hff7+WGJizEXF>N-Z|5%d9z-DafF_{~VUFJGo5bie@0UJfK(L1@l0nb3b z-*B!72zpZzc;HDK#WQ3>bR9GRe{ws)HYAV~d{PbH@OuOR{CkNt{%XJF47KH+`GLwv z?`{nCTA|*-wlqMfd)#7c7qKIsph|$pr8(l9NWs(0+#viE&0(F--01541?jE_Y=3iE zJMEj;ak@Bh-hGNNxKsH|y8%{%gua+id$A@8r2heOs^B*lNncRpDLsc5n=zz6)y_i9 z!TD6N0geHiA20q|?72h)NJU>Bxd&LAe2W;ue(6^ieRaP->LI7CXtushW3iLB{~`QL zvOWx)qyOB(t$ZqO3lD;Oss+>LM@AoQ5@YSdhYHY$SwHYs;@yC~t%p*HIERGy|D+HQeg-rs-aEafl+}%GkDfeCmG5fN1r1IR9b6OY& z-2z{@Zb@x+_=q`A!=;PwWh|XipzcL!kH#eJY6+0GqC0C4(=lt8TfP>|YQq$Qx;GW@ zpL9>{C|znfpQ|8be2(i=P$O&~`|e=^NTfK03rghiD(_#Bf0NeT%f5OlzOprm9ay~8 zbbipPAzdN@_8T%s^kv{IB1xO9W_RR0;W#>f@%~S)O9LDQ!pOnv!n$)%*2O7A5E`J= zKapZVh=K@iVVnS=)n8YTLl*GoxbbT_96orsPs68?Mz4;KH&Ia?L zIT@TH+h=sc?Ci1=XZipQmW#*=Ptn%(6mQQ9)(i83JP*=OmfQEYv3F^ioFPF%;{%7k zzip+1$QtZYV5uj7gfJRFXpr~0@atBZ)vW7zdxUQoD|C0=4f=fnXEEOAGNz=yy7k-p zrk}~1yt-F2y9T2CL2Hya&&$P#R`EpY{_NC@dWa2suuooMski7nC-zYnyz~YCb*fiP>K(YEM*BF!dVYbljU{f{`tYVD)MkcJS zB*$H9g+(uL@GI1G^6HQ;reThmhh6q_G|P5Em6fnpSYBOd+mFGw>xQ6JLpuOZh9M8P zpW5i+AJaHS?QQK{fP1#HH5+xiHi?C3&Bp?2bj2oP%K}L}heCeEX6@B?s@<|S2bp_TLbCyUTphyGGRE{q=zV0KcDl7%@hfsQ@awo(M(;@e6fYpq9D?|ZX>6peo4gf z=i7pOxDrJeiO&+2`l%|YrBj)+^!Zo?DfPSzCug@cnozT#zsE?w0^XTW=Wl;%vGJ+5 z!@ zmM@a7D$siXc%YdJ8)NQSS`wgi{!#u}g5t2U`9%{}qOpp*SK>hJ zeeIxEu_zG*1*#b>NVWwVOv`u2T8gLafCzb>Q8q3bF22iDVW!%1+MHNufYd^=AU5xz z_PBo=zEJ;hgndN7A1H+iVCyMhIxcAS#a?1-*}c_w%@+qToAjN8he2`tP$xmT!qr4K z9>1bg{S=}S!2V>mP0OI2tOH#UIN$j90}dg}i3Syq6L3|Frd3||PSPD4fCk8i)%=2R z*X;8`YFGddJYtbEcIC1%KR1r_JbBmlCpVl@V#~^_ZS6fJc`4VwNBN}R6}jT(N_CyZ zfpRCrjw^nm|M)D1WIUMf@a^jT-gx*;fQpr^PL?tr)4y&cok|4k+Em;@Mj;f~rHm$EF*MA~kF4!&>K2od7(GbVg;7+{;Su2jNqG`A{s zNVFuU`G&9w6VE9D#*p3bG{3Q8J{$+U2FYs2M>f9~a6@FEH^26=UgGWeA>AbM8*{H$ zOfsn<-6)^gnPVluuX4e+TlD$n^yEY=EQUdZS+i=84EqJTivX`Jptn^Vt%jIn%nvEn0$R^-8UmEuT*#~BNzW?=34g&t9_vO^>8NT>v9P{T9NP&{Om-Ie2Sf5`yGexg&r3q2Ll-A$qPQM{>Q)?Q zxdR?)wNzc1i15FOgWfNMC9k92F$M|j0dPgq7-!e1{f}GCzV*KZ=x|tfqKg6CTt%UN+M=T3&c zD@`+*Kkb)H*zsm_P>J$zJ7zsQh3DK{E_I|%EScNewq0B zGO4xv2J8{MW>nt7$B#V?Y`TF~f>H#Z`lW+I97N!XqTDd*%K{Xh!`p-9D`W3@0Mo0j z;vaNvhF5LwdI$hKN&t{cN9N_7yL%8eipYvVgIk~cgv5D!QXwVklV7uCow8sX40kwG zpEQg>cRHTliK=EymkI*{qY(i@;s)X27L~uwuY)LaRY9wLS~||xpO0Q<-xnhEeZ9Rp zIM8;3a2QqI;BydYaT@saL{XP*FoeQu2{Rj%#@5{qSPk=vmC6HEDf8J+f3mM7Y@8pt;29U_Dn zIv49)^i&%by^Uq!5|0S@0=P-|j+5^*N?ftYGk&V621vlD@W@2aTs})@D%A3SY$X7T z8_Na1>djOw=Z}kj2W)NSMdu!ygG3k|YT@w#Swx@UD#DK_P_~RA;^mX1bi)%KVx`ak zULFP4!K3&!j)-^s`7;j2?8qO`yRZXvNsR6YKIBh|f#5CC^NU7*l&C~kMM<^~cL^wu z{z^_vUsC$8StfO!kV7)K!bI>8EAbFLJ)CVNNHDKuRa|&V#y;oW9q!-S8?E-{jRnn@ za_NoMTqh?28=sr!0%)1c(O)ncLJY1|5Gu#U5a&PHkDf*cJp9{qkCmA65m2vtI!4%~ zNXQWowZ2MVt%(%|w#ePQv#E4tWf_?RNVO{OQMsfwSV8t0ix-*`KvREkk8A3_R+HAo zR|`xQRpXY@+aPyF93Dsju2L<`z#oTUW^i-!51oJp;!*g|(m;Tk2muwxre)dQj) zr#M*vUW8CG_t)deS+etPxh}IA@l7T`GD2v9J}@v7evkJjRQ=vp6S=ed?(06;1NP$+ zReo=0xF9T}kDd;FvZU;Q^izB%Vi|~R$yW%zAx^1+7O4U>4V>E#z}i9yWg@RUJ3X>K zXd-Z1XLKk<5;lR`v39>%E$r-m{>JZ!dvev;5IKHbl3zEp)%4BNOD4)0|h@=s31rsEa7gUd_PXSt%Ev#vLSaT@2%oq=HuW(GL>$j zhJ#l(P`6?MXg=ot3+BScSQ%`FG<@06tvs?c(bXv_sW%~R2w{DkM#`|t5Y8vh10UAL z`Njnwbewzvz+Cr-2d|m&Rop#BmP=KRCz}XW zUQq!bjbo9AUMmV97}Y8FXNwklXJNy8*U#N0Kz{jr_V<=G$~6wQ$36cBw<(SVUxbA) znZkZfd@h}-9oPinWNkP`+m=Q%vj8AMIloR_DVhvoOk(RkO8Y7R8%?M0M(j{2e#3zz zGEM`VWMMM!1;9sV(}G)!KqF_9L9xxcqi)EPGu^HYKloXCg6u-`jZ&3GWB12_M`-VgovUC_CpWx^VYP!VcFDlR~y;UfG;}QmxYQ}(A_{V>&cHm<~8sGH& zM&(QfbFqzdI%>(_f6TKcxivJ8=c&)PUS(xu=aT=$4`0I(NAu8-l$qMwn3BAk8s}$i z|Cj>3?7&ag^y$rp-aO|Nf(3oh_~<*iBvP<-eZnpw$kmDmg4u8(1c4vjCHnJp44fDO z8Q3>Wsm9mw4g`)iX;1TGHm-Jck0B{=1Lyd@FboFx{&_EuXB&h)u_qoe;td4#-QUWwyeBp!ZouFws*%m?p z_!=j=21p#5cWo7$zfz6Cq4}%Zil@Y`XM|J2j>I$cs78-Vx~%JH2m|;vy)0NRH|-`U zmU)T6na*H4Xh8i4AMmw`VI-MjX$N!f6~UCk>__(_j4nN`H2_)HWj}h5%4#QO9j<_K;xvoxJb7`N&m7arzO-pU4V@%aVlc0oF! zDzrPl58J_5rA5kr6v;>>4#SMRbebcyyy#2D!FBN>Qptadla`#O%!8NTq zse4^!PlDi)l$@MH@OkE@7^{9ljL2IZgCW=)l@I6N#^{ZG6FZYFe<4%M)We0839z7T z=TX14;9IBhhp_96rL$OXj@q`g7Ai1VP3ieT6HRALyk-UxM7b9=omkJu2R38dJh#1a4WX`LwN=^^diG9m!>{>w4DdT@}{v*RD>z zz~c}H_4FcOAZ%}ex7RpD0M)+is#1u9Jf}_mSS{`MH(rs3A_9QgRXxs%LJ``0==sOg zcIT0R;pX+YtZUA;j!6I^y*=4OYzDGBDz{r2OSN83~~j3Z|Q1pu&9xOy z_Uw5pZq_&a`z;fZp#b;&4e`^e(re^o7NH) z$jOJ$@T=j9mxz0%yf3=H-UUwG6rww})E#9`Rm1O;ic0LrZy_Ry47i|x#O@nyN+nR= z_y^xtgPu98Rf}&uWHH=3R=cXzMx-kv{1rTmlG`axUEQajl__pXQ`YA3{)9jE*S5?b zDWz4-Su4oxV7HqD@#}!>#7)Vu-#&Y_ZTV?>+`LyOWga7Z?oqJt4072x3*xSJUB-v# zF5LtQ<5z>7Z>4KaF`l6v%|*vwj@D2CB>!ETxH&ZFW^%^={Uav$IMZEpTLKQ1Y7~y( z)yF#g0{FCk+S1N}ez^cbRe<_6P<;JFr+CPw}AfKK<+Z|Jmw zu)IY$KK%zj0s*SxA-3Z?%lZ*VM4|%Q?9z>URd#r#3@ksI-)P~ zI~D-1Cu%GPJ(mNEt*FiB3}MJ-%-pShDwU;C@Z#WVXs#L!r0T8D+fDdF+6nN5J;An% z3c$~P<)m3vQ(ROBr1na-OLIm0yhEMncezm%xrpq(_n#!GYZ$unRP&$FV7kdOXDw2O z<{)dplY#5 z*5v1CXk8>+FU9qJ4i6SW^xL?!wMLQnXGO~*j4ZJ&;r~?z^N4sUcuFy7aMk3!b67OFKC5T35aiyw*=lV_O`jHyKW_}Ev`Ozj;k=>?yX?&l28wo2plMN&b z&iyA%StbOti)-HkaU%b0zTQbD{D7Wqg|PhgsAw-pL-D!(dBOw`TG>sW`>AE1HarWe^1TBQVCu6g`NGK_r(d!kkx}VdqgbSbYibpBT<-prCN2Ut#>8OL#z)h3 z<=u_`T1tD}c~L7ZBXZ5R)~#_XyB@ZqE+>)|*on1ZA4PJ62c?o~i!%8z(sQSwlH#VP z)e2GEUNdfL;%|*NhxN@w^K7iFG%u-^9h$@A9PA{2?$4{>k#%vFeqI!x(pwPs2F41} z`(y9W9qRYlGY*fQ0%1W`auYFK(n!3rf2Bu$L~YDE_(rla-6y^&Alo=5QSPMQM7A zsXG9K+%+J-iB&K3B!H4uS&uOiVUqrwP@p@~j#yN|hp^IL)#eKWoDp}-CgILGmvvMg zOF}Azo0*KOZ+~QC^PP~XX>J~~5ks}aDD31WbHz4XHL$5QKCVn|9o-GK6YrDEVi&hq z%7Ox4<3Q|v>>!Z=v1;@bE$~+@H7sAd10I%2TEl8ADi8D|{kgzuuUCzM#8+%nc&P*Y zCWAp?z%4e>2{Rz;-t7*mdo2JrTBHGho!6yp8IiPoy<`tXan&AT=w$KqDUjgFTfO4A zL}Lx}?Uf=W|LflX4wb@PO2ETMUDzPNKlB@kR$tpISM5G6Lk*qUbw*c~i2GK_e#2#r zaT!t3$WfW#14J&&ZJ?rXv=}g-zeQ)QxPfMZJ_N>6^xs`t0^aT&7Oc8-i$*@Ru|cqG z(7j6ykv6{BY7$W-6VXxh{P_jA;(MEZPnR-{zf_6_xEMad^>y@h8o;Ah`YDh{c4E+i zXG%gyMEr0PhXx2#De}B88rFMv+~7*#Xonxb%f0N3)cC9<^SMWo+zY7A+e!0eu&LDA zNse^N568Dy)_|IY>%NRI4u38Tt~n|OcRk7`UIS_9VuZBMpXfXgnri|zm+3= zFU2K)&w#a~4RNWOcEsz~j}a3Xe!KX)A{=>!2zViNtb0<-zYL(ftrFBjSv+d~uQZ8q z4)=fg5_aoG%jh$#m75;48d>zcXW$LjoZwSCWO;&xxMnmulyFe2d8)gH{keV1;)&s%5MDAPlr4&CM%cSx)XKrN9RVm0?-OA zDyG%1Pi<4;t?hm-*g36|_N9|yRw>AJv1MEimffF7vTCc2%Elgtgj7NxXM1X)>IVR| z4*(uVlg^UpKhjtm5#!Gdpf48j57`!Xn>6JO3ta)eMyXsghoDXC$&>QtdhdT4&DN%e z#W~cef%r~8N{Ub5vTquK_CC7j{Ano0Y1gK)NDz~t6o{K>i&8zAVh!4RcE%%#?(anv z2~HMDw+N!wxF4uQ>#CA>QB}4ut$GZ)J(1MC|2ry5Do+SGXy5uLG$fy30A0df#b_21TD$*_D#(-Mo`fB-dXSndL^7<jy6YsB_=Q4QuHXW{}v> z&a8IQde1f*U+yT8|eawCDQ4;iV4ONJya-a2QcmF;|Z?DvXjE|{2Y`I zD4K3hwLhuaGIqKjJ9eU|h*a2Z@8@*z`kEGh5gebk+CNjjc7EzVUU4uuKm0F+0$KsN{fj$5XA1>Nme8_GVap z!w$S%ppNU)s}DLLedwZA;SXU*D~0?SrEk8~-47(bH10{#0IZVz<2O3I^Qt0R`*dY) zmEPlqX$9)cvU2MN<`zyrYawO`ytJxbyl!re?dVU-h`a=q5TbPa$|;!%tYd%}>A5@e z@5dv79O6`SUQNk==Ek@rH)d*9Tx6y7Q3E!QYse6R+QjyWhC~gTPk4HES&9oZBDyKs zDKQ;7++ucF)V!C-bWwenD*?;-NSsy2L``mk62MW;oa>W0pfVsCn^*P;MH6~L)q;xp zkJZ+YX<{bxGWT(8{bbi)aNKBTzymvU8M;3&Th&927V^fiG#auE?{{EZ_{`Ey*XbTf zO?c@-Bc!D93y$Nsz=R?(_jmi$x%5J}K+G&+=+a--To<U1rXB^tKL zHv+g6m@Wj|U9iM;18WKbzl6V<3x?-Qt*a|&38ra5IBZQDQR?DrH@rrTk_iCLXZw_) zFh{ms4(q+ae|{CB31NpT!ai|9D8a!pPpAxh&6!rvBdM$KRlUN$()_8h)1d<2TY%rt z$pC78bCC|7X({z#8)eRwCYSP|IyFBzv1e;A+X>_gvXA^@7K<3laegY~W zjn2g2kbP99NTpE&u0HN21x<(E>4*cB^vOU_R|iKvEt1QI29J!+XIQi!vQ%T5)U4+s z{&e~f-#rWP{zr~gt{@lwq)RHdf^kFmjKA>ZjLNMRM&+&j8A}9w85KHJi#BAN&EhE~ zr>;>V>WkhwaTi`a4^;}$bUk2ms@n$Ag?I>k6BvIQz?Ec)ldn^}!ikEAW&$v2Sd1MZ zH*J&>o>}1dfqi>t*R$`k*ir|c!vkw%#gk-#wxRn4rnSwTSA3J3?(hIl?fl1G_e;Ow z$FH3y{0@xfS5Iw+VGS&#bzQPf--$-<1;{ioM@W4VPyz<6=1-xN5FeDqka@M_hyETf z^Ss=D%4YokRXE++&sbP}2{YdW6Kk8}!1F@8X551^zGWz7zUvQc4 zEeu%btSy7akslYxV12iPe0mNh&Wq6ojZuCjnm1jNV}o9RV(szPv{enf4; zDfi<-0?+v%S(Q77%7~-IMRx_5T-?sKXalFe0Tp=m70Qm=JU;GAi9Kii3k}fAJ=T^m z%_!nKUCPpB`t_l1jZVKdMn*>d$A9UXT~eF&aM(ghz>}mo_%a}&4627|wKh?OP^{h(=-MkjU zLIV7d7z2zRx_ZF`!Vh$$+{?@BQ4N1)s!FV@-z6>nQFf(m!t2D5gO?h4YlYTFsn$o; zwlF#j(2?eQQeM!>>E->-rV6wGc@8kn9$2NwS1fHCnBc_U`&lD_mXA@0OGTui3k?r- z=h13^+U-qYhshbkm-ilMy|at;^-u_Cl!+H*a}z|#-Y=LM_sjqXkoR@dV@}JQ& zORT<(^uK99Y=a=jewJHQ@B~~9eLVXF5AYcI#+ht*L}+ZMy9=srr8}ctxp4meBfjs; zC)nj40vClmi<}yFuTu$^^?5-)+5}tO>PdwWU|-97(>9-?XyCuPlDQBgmoAV7NFF%o zKmq4d$TQtHgsZ%6YQl%|PnP!af*d5@$vk~y9@s0^g|a?N4y>?|Fpw?o6`GP^JLkdO zpo+sYz^Bpxf8ekX;2l?QvR23qf55vqW1|L^B1Y?j%1-Kp zD9WPZEiT-7dbjD?R-@&`(*c_5&;AHKE4S}TR^I-r+v#g=x)Opt58EkQSeEW%g|-rv z%kxK}>CV>Q_}Wc#78aj`r8x zvy?Y2k=5s@wXnYDhbQ>HEL&*#1PRn4L&?}BKC)lMu4I6>W3&fUWgM9orYXV}ItN zd947s3TqdxM~XvfS8dw?0xKEA6)WCO-GW-jFAC_O3{`u*=nMyim+HD@ z+zDtPtS6834g9og8>-dE*@{t$oDj&VwP9IdV8`#r9`r#8MeaxSUS+kyl(NT3Y<9p)Wmqj1MK8nV=!nNb3?!BlZpG1-#s zXuhKJ(`me-jb-Hc`eqC=ZNHX*DLM39>t$HSYbr3H6v8gP3@z1`~h zTLPrp#{KGcnfzGq+5*d-`7)-gH|yjhB&^6g8)vm6w44}LG<*BQCg(L_%cM_c`m0L! zbssd%XZp9qDQ&LMs`r(g5(gGTPj%s??s#{!&uvd<-7D}O`Lp7(R8vW*j7w!T0QM<+ zsq-3_i`|5FM%8W(0vpJozGB^N?BMZuzsp23- z#36GiZw=5Gg&f#AAb5NEnixrOYgFBBgd3JysK%e>faaWH%kste!OU-thPR)V7W^%t zOFLRZjq(L!KM|g3K92iDAx|-|zyW+^<5~WeK0csGu4lqBtom+uVUbW7Q)W2_j5hpofA9b*G(>Pzbhhm8`2Q0DjUj0T}^zRdhBp)qJf-P zS-%>_Krr*}>~Z{souu7!zzDJM{0P;7kac*u{rHFwRv`J{|PX~*4j6Py3C{|cS>3yXLX zsR>JNZ$v8LKG`+WJ0VQigyVhbm@a$Vg+{wP#kv-jRNv%EiNo>ujo}rq)U|Jd+!v>Z znj|?|3e>h24rFDKEk=$S%AnYfpD~mbZ76e(G=D{qnGzmcl8U;UGMh7fR4ZN$Xcr${ zO^(gNOt?GGL$V)q?*@flA2G6$6#cjo9)G_yTU0^4e?8`5YH1#uECy75E zF9b^U844s#*Yqrp7=Mc)EA#}oI&aby`XVl4&LYlJWdFs14UbE+-0VB`oS!(BZ6yha zELh;59RH@5&-RIJ9F%#+S54kRr-l_)HV%?+)auN~h7lV$SVJK3sy%a1?(rFsDNVDM z{am*wqvEoNRYZo@5CT_<6OJ|UzTVpf-*NPh+1K*(_b2_v(_%kLv_Iqk+*>H&lM%Y9 z8DdY8{+@Q+M+XT^qf`v$udkaWUCTDRL!zxLsX(teV>zIJOi!(>=*)J)GWUwsZpdwt z93HEvwJm)COzXcWYLPwq;)4B+<<87jov0{N1->u?HUPB%!*Fe*dW8!5**psiecGw2ya{h&it` zzOu}1w)vaF-O2IK^;w_UqOIcb)Y0m$=Q=NY9NxYeAejD#Yf=EvLrGVFQ6QUI7_LZR zx}(uK6Oe2=b;o_6eBy9=Q2j5bMmzFBd;a4^`7g!6a&Z`h1B3#U<)n4FN6?+ta2vu0 zArV^A+Gl+o^30fM7Dn(N<+ek) z;Rpj&TLJu7a6Jo)rOzin-&7`>0tkOP&6+A!9=!#4P|Nu`kl5N|2meT#_#a6B5%qr~ zE^EvdAwm0gTp^s;`>xX0;1Rh+E<_|R8ySckhQ!m`M^*u=+gBJ1ZO&uZBU$gPBLc4kL(nog}~27PX7Q~n}9*S<;yiR=VZ0x zj-OnauxLw>`<+bkaQMG&L~S^I>q)&8j0rfv6gL_^(2)%exUCyjGTl{z7AQ?+y3gR6 zyguQ8Cm(B!v*Z)rYA_Bd*VQF2IRA+FG4M-GC0q27TxwoQ@_9P@QS9G07fBeOJEU4X zHsGI{Ao)!jLxg9hUW;Jy!GWL9M}!WG9~4Fy$$Fu7=GwaRxteQz=D&uT|Mdind_0qq z8S?3inEU*}QCm9NQ)o9G^vv12)1-Re#JXTXqoZI0-SHElsIn2ZRepfsi%`w|Vg>`7 z5Tca8@R96hUz||HP{A0ZA-9SzLuALqEP&)(56Aa#p-rN%{m;jI4)ANoi>)Dp3U2xt z_bDhldGl<27^f5Sl%ZC|tAF+9foJq1-~H@e;6q=(l?6I@Yzve#1$nZMFW9qf&-7dw zOV0efF(+?fNyJ^JD7QSTo43|+vyWc8k8LpiY0<}mXmrX!j}pURsPtKrM^XFm$UGqa zvxT0sZ6^(q=Hq*W@$fXajkj0eXf>E$4^2c|O9o8?$3yY+Lh5QvG-4fxA_f~Pc8RpuRXSM~dM8|6rb=qoiAVVkWkL z!F5m0rOw@R8eNaPE{1q6Y!Kshh~lf|@^S9s=Z4M_8`ogk9R|{W8ATp%QsX?>~Pc;cza$ zFF6$I);wPeZv-jx_xK!Vw9kX$J-i{W!ScKO-CDX}OH?5Kde-r z$@r{wk;MSAhEbk3Er^_Y2Bf{*q#C{x04n^T>7i!AhaA>BX?|;bSNIRC*rs7ld&K+9 zdIjQA7)D69t*|g=(>r=!2{gdc-bvx?x^G&!pph6{vIE65P6#kMKMmsu3 zU}*48(t%EteYG;QXuumN#P<%102(aJ&M8i!_|?g#>RrL(o?9NNMqmg`o>Q^f1c`EU z;~eUpbeu`pA46J;Tl_si;?59O-dRg4c9gBA(FHqwdlhFRKS!1C89w6pNS=&`y4H`b zpG^-6)yA4?U-eA`knJZp(rpj}FyQH@QGQYW3t=5^KQc(dT;`g56qik5eqH_h{+yEF zLQUB8eQ`0iq_}P`fWfRY9mmO|G|3hJQjCj!lNY0w#cY| z!|omONY&dyAq4G^_mA`o?9 z{E*A_CjQLyn7p6Y5V;3wp=)4Io(d2?CYL1T6nMZw$$eDcgFo<&QirWato#;@U+KqG zFtLqR81(u2o<5tESC~}iq5}I{(w#F!lVH>I- zO`=LZ8n>u^lMrBbzck%CG`MHj{KBhTafYSfHu5G2$NI( zX6uXXrX2T`PES-#+8;a(*Nv{ImU{khWpfl##skYL` zi($x1=3P7YvFFiQEJ1Kx{+3r%a^x%GSgJqG51o?K^)-!69Sc}2)dKkexi4{|#=@*_oK+I=FMQJG=0q(3<~3f9}CYQEcK=94{e_x-Y`~ zT;onVN;ZGaKo;`4Z?23&8$pGopHbV+=XuV%BZ;8G7pPD1Cva;~({e%>U~TV=8d(m0 zoFn}SwL`56kS+=SC>I@6(P9u1#I$xH1F>!R`tmk5(YSn=+}=~0#4Q0ivk~MJ^h4E{4`98KeUs6=3C5@Q0>l-^9q>9Yxg!Kd5h*| zV*2q3G$Dr2^W98Z++6}&!*binmDb?Q_z!Pi1u}hUJqiV_auxY??ZHZ3-Vs6!DG# z0>YC?oz(3(~iM%)0x@ai{QFU;NyiR%QAyl6!m!POB2fINgy$KA4fEr$m2C__jSG#{Yp+qDYd_&%YvtI8F~3d@~6 zylZU+9;tqpz8(KKoYMHR`^XC2{LFlz?(OJENpQ**HgP7;uk9mwZ0t-3F68}UO}5+S znTbGaY}NvRSiZdA_ZxrPq76yWQj(9g!6-@KJbRC&Aa7U+Ffa{3*U!2oRQImac4RmX-a zsWmWq#QdRXabMJOeaFx`(w&N)Evu2V*k)hLFO^hV7dH!cO}(=lWzcgn@p5=PzWlS` zBnDZMOnD)u^thUCK#lnwViZo#eS>EC{ZI-L$KP5z*oMQ&LRf9r!hnaGIJoyj+KT&q z2VbbOrB5>?5m$5DDF{VW^F{V;g?`0@U1hC`?6Jk9i2pWwi&7UmOn6g)>3+JmXD%On z?9aMW?>b9x4RgZ$3Y!yV;DvY@QL;p-H~Mj zffZxZWjU>XkIxPlf6s3(AOsBZA0&bxu7NlPVyiOC7Yd5WHAh-_r#eL)aHT zi4j-vbBv1QY`3STFE9ag$(-2Y%yE(mkPp3f>9(Q{^yLE7tcIrlgn#n?@PNgo_>X1S z^vhV%;%71Paz)&qxal{Q#2v9AQHnS|Db&)#iPXh{b2i@5|MkL}MfrTH3qI3HmC;sb z3U{>ZjBAbVFG-b*Jf0pt;zKN}!=PRqfENtIq&82!L5oC zK@9bi>|V;NDQk)UjSvRqPn~GZM>K_` zAQ=HS@&f!9fi-vlH&NE{Z6Q04v)WYxvN`KN+~rKN^JGHl=w$UupBZ`{$SlKvO^yzdECu3B@gk&y5+f zQlC2=D1SebFRB?@29*quWbiDmv>d7ik`0tp#f;I5NXEtvg*vFDH4P{Z~e&|}P zuXYzXMqFq9$|n!q`6eTv^2H(vm}@D_`vcujlUt-l`qP@*VZ_exD^56S9u{N;4(+M3 z;&o?Z-CUsC311lQG65|zFrau1#h1w+?(J^!E^Q_hgSWaisYz8{Ibyv2{0Xl4W5HN4 zkWk(Lt8pmd)Cd0H3-^r&8gOfXT_c||uEivY`qfIh)FG9nxq2fOW5@R(o@_bq|M-TQ zMOCPEND|rjP-FbXUSv;o4=NcF#|iEkKht*vkXSx>mLLEvbjgJ}i|Z7!>6i<-POH#@ z;C&PngDXx|Vk*%qar2h$;k!+Vy+Oct6 zs+rLwuZdw1Y6*}Nj(M3kB-pJ#E1jU8tL<{Qn=WUJ;eiDu8FC;8fUJ`n4$CEFhIScG z*@P3!Ew=%$7?(zK9mH}SzulE8)kcy#{`OPFoSe$C2TDwH>)jgOzQaBM*aS@`W*=)! zqc)0;tsXPXi7!8aAX~kxd9<;dZOm_Wp%0oxP96uRwfzddY#>Tv>j_CPfqS9p%~5mi zAbas*FEX1V#0lUfs50TCy#0!YND>xs+^kRlUn+ni!IvE!kbhm}&V`TYd|g!?I6mI1 z4_TG3(m%Hw)6|60j#MQFz!p1M6DlUA+Wc|e;XBS2iS;*u(=_+0Z?X%Vru=u*S^W=M z$(n=~$?gWJuNU)GNR9KbbI+C^8v9I{3jla{&>`|E@`sR3TB=yP7omUY)xN$4+EbHjgGhVZXzynam+4fQGAp;J^|ws z#%0u}wE9YicuOR{J|DXd_-{n`6Iw(56sOp2>rW=0_0h{A`S0I&e8QsM%2v!m3a*OQ z&rAVL^)*$x=+-cbY)cjoODa5o&T1g^s$QR5#Gif8Y%==KhiS$$tZI?urGkcGXdJ_j zAR~=4*mSu3cT=^q;n{q8Y(}28Rr!6uQI*6gg-4F*^tt_Oko)H@QQY@r7gue0)H&$p z>20^iG8`y9-kwshsw~*uNthFV3XiYz1redb5~+;2{8_Sc8#`+lM{&#keM|4-wB8?h zkBX|he$=reCbXEBHM!(+jKQ!frrHqJ^ZxhDBDRC=)4&B-nk!E2>e=hSe_+QQL3GVth2=OTyl!Lt` zr6S$W)p5uzimbAL@isIQx#2AtMvgZdA?(YjA%Tc71}jC|xIY3~$-@ZQWasc%wt9m< z%ot_xGY9@wQ2z20#v1HtVsAKg%=r*{(%<@~n3nm#(4I3dJfa`FTRFr7#$_BrJM}ZK zxqGi;w;9jByjy=Vqdp!#bQdU939mh;&x6%Cuk<_p*5jF#DgKETlZ{Z=6dorLmY%XO z6)MoQX5Qk;-n#d5c@agzF5b12gAdu3u{3gf-_Y@+1f|@9)uCB?8A%p)t6=8#|MD4g z{FT2M*zOGR85Rf3cBEDjIeK5+DU^vd>zoK97A3>&h~0`+q(T}la$>#0LPW>{$(zF= z2@xlD`>$jGpkb!OaztSmn``f2T#16W&6DmSi7kZYm|GCid)PWt|(|M zz|@obFRfg;sZJ}&{JB94=1^U8ZLMxoS(D@mObs1fLqxX(w%TQiyA&)2zZLaFB(o^)K#lr+`&2`Lf<&wuuS_YRbdy$;O^ z>XC(+Gy1{K@-d29G+^jXbJKRtih~E}9~vf06zs4jhXlM<+ge9tk}BO!Y6pJ4mzMxN zcY8Q-^;DjJb27<#7lx#ZC#9FJe{q5BN-oKf5|jUkQ~J)@vkvLSFE255dH{aU~zZ;hs!2hAc;?NyR7+ftceLTS!}FUTsCs~Fakd`5KfAlLus zPg(Hz2M8t>b^LwaK!bTsb|n1wreIR|ZqMJC-d9d(&GFO~pA{KT7Y`SBlFtZY*E4nR zm196vI@E1D@R>nImTu``#jBs7=>0_JtnpgGs2bA~>&=iyU7+kpBgm@aYv0Gor#ot5 z6+b{N{~c)Y(1zwzDiLMa6?zl6M+^S${s3n^z89`G$Zle(jXo%7X~=ca_@=%EY&~!# zj6@S#!h6fN$U*dr$PvvX0|gxtScgyvIzB%+eRfrJZsGbrS5+)~w@Ze7)c-v6#9H9P zpuVChap~vf*bA|u=f25@Fh=yJbL3|{UHZQUvkZ=7v z0e;lM7r0fdceQP^Dm+pa7I&No_+_x8*Kp=l%=bQe``0pMN`D(Om6%>u5qfFyP99!E zwYdk8e?(P;7qjYgv2e){In)4W^uJAskG^=$1^zKgM9FDGriB&ix@n$ZYo0W&d>|pB zt8I-Amf5e8-WI{;t`R4Ne4ku~4kE3r7E+c}8K5~8&W0t%0oQ_#Yu_NX$_rlU$R!Z+ zU!Ek9=h^c#$aWL9;%;NkHSr<{DHg)-mcRSIq7$DSubUXUD9kg>Y=nNOC3P=*T=$#S`I}$CJVYN z(>Ped4RQunc?sc0uzdOW1u;13@9zr8OPIff!?IFhHfyg(M3RUco_s z6{3w+?8GeK>8tW5m>@Sb8QtQrEG|nY%DE;e1z|(}qX?s42(xLgeJq}pCy+d~xpOAZ zq;{rsev5h%&UoaukK2%@Ik0N3p8Ek4w+MRi)kb$@>9|5k~EJ}yB_Bt4*QxhFVRwz@xly2L3gRWfb!gm@>uP_vN?{i za&$_S+&WDTBCsWYxi9=O`?6p>VGx_;F{2l0B!CxN)#NFe?iqP6y&}ckg)GU_Mev4m zDAreWpQ|QwCS#u$tB%zsg;d+v`MI=JY)|ESlPSpz2Rwb@X(ut zLSUm*04uUa;b?JdJ}JM-i!afS_g3B0#0Rwb^+RAB(+>aKXc~E|phHt2@FfF!rjmxW zyn#llD0uWt6W_dM{!ErjLEz&|He1pPm^8oLsKIgq2w=Z_q^r8LD2yj!e+)$hT;ezS zUkWZAf;?68aswwvK=UAqMH2d(7=8xmX=~jTJF24q-hRC#&#zcq_fL=&5g9iHBY4OV z-V!CM^;=7D3+nWm^I*hph3~_kl??UVgc^TE&ehL3R>IkJ`6THQFstj=u$&w*w|r4* zyBL0nxzyvk`tYzkeAf7Y2$~oRpuf=CTd9fz=e=mEI2qLR8Z%c4BFD>)*92zC>6G`-M=P zs5W~m3A>?xB)?_q{_dizHF<%YN62ZzZ?-e-SNFp3`(MeN$2aGg13eBdWle6`l4bq?A$9sQ4%| z@G#h^Y<{bwlvir{DjC@z$gKsvI-6LktC-}_cQht|o0tP))9||$>p`8~=jSj|^(~S* z(P%|JH&Aq8iD!R^lDo#wk6)Tmn)B3Nd)2F`2&J+21<${NUM);F`qFKs9L z_8ec|lqTBkL!CnjnjbmZXiH`B&o=iX^?@tDsT}JH@s0PMU*If zdER@Y;-OZ(X*@RNV>UhWAiP%=O)v?$gRlm3Us)q8=otf|iB+~}v%eGG?S3nK!ja%+ zCxAxXe>-%;BeQT_EvI|=NsE+b>E7!UPf4a~Tds1O-u(CpJsn$_mu#(>5oss^yeBR- z@fa3d_agkMF3NSj9MdbdR5WVyTNLiMexQXECsCw|T)G}~=%6eMD~qes|B@161>I7{ zqJ`pc#ZT9hM@>hF@i9#WGNI{AeR)mqCmx~vGGIOUQ;ezfJBl^C zsGO3KTuUoATS)+bYpDsY^d*QL;Q7~1;#f1CuwdIQ)ha56a7BhNO-2d+>ZkxNQ^c4} z+kB)f85vENKlZNU_WYOK)^cF8u^lowa%u&;vB!27iZ*u>6tVZFc*hkdsq@7R$kdcB zflxhNB)*03jVA_b?!bbOh7ggbI6B$Rk=+9{=UaV@&PGZl^YJ<|M&FpAF}45a~M z^+xc2XkCA+S5;RenRZ6*CW@v&q>1JoTD>pwm~~2(s_)830oO>%8`eH4)ETd-^;uZi0VC1P z!B%29&sl6CeIH0LSzMma2*VR=VdaRdpp)&_9^!Sp#wqpG`U^aiL8Hlw3aZKs<6n~) z@Jwk~&kC0M!if)P3{IYwOv-=&Bz=N%%>hwWZ==j?IM=`2`w1XwY#-gy0D?R;U14tg zdq3mNlzMxE$5dqgd^G=%VMGI4g~VF?k#dujSK?`Qjr%6vjV)L7yVzBrGi+Y1qs7(d z1N25*{6Tta5AKxQDy$(*GjVP&WdrM*duB5>?!qk}tMY9g;%V-g!lU88hj*grODO;f z;Fhv0qROqyS_PXXbZ_b=l|a8ctcWQ|#898#&>nLn+pnezwH8cWGGM5Q=tJ5n;QR;r z%$J7^4xHK9On?Zu7Rs&pr$LdGk@*g7!lje*rd<2ehQ9Gj;vmHvPR)1mH2m(F{rsXf zYU34$?cDC^>ofn}n#R**OilaHL z3SSZZQl~W;mu9W?a@piL;%(*X7W5l>e7IId}gr{fA)9rXy(vd zf-pW3_$T^;%1N*}|GcO{H{N;zoE@rnqFK<@VD645AA#iAN+sRza!?q5A2v)VGX^`9 z6Lohk_`QpYi3iAdoJ$qS6)|;^9wS|^zADyliv zu+AF;8na;mYq?5a0;&IueO`a5dJLEp`Wu8F?6LOXx|@SXdzMPT2MerzdY&MCqL?VV zjScU-ERG(;Lw^)||K-lyN?)+;;))x>$*~SDT};@$*)SpT#`xA&@~zp1t`II`(YifT z`l+4YQuw^&lF2rL_Kz}MNc7Y@WiEnCiTPzla+E*UDZx2kMp_4kxK)&8SSr+0*UIGQ zSU>SbHIkRXN5m|_YnJ8P2?>qhms?Hh#A9upgm?@WhAU=&wZn%bDLpBEY?U~ea|h&w zM$CNF=F3)ZH#S>fQ@p^x?cQ@rw@n*#{aD)9#)QQ0S$XKoY^SzXb_#p~q zBG(ng+9>oawTOoi*8dVjrP+06hB!Z-C2u`u#6N?j*sn9}LdJZE6U=Pi8cdR1V70Ne5IHS$s_roz`y9lC3GRH^q`gS#N~)ELGM|+-;1* z0=x=a81)Xo&AsIK9=52UPj##kDrn9h^#8L~!$rVcP0os1&zU$?-3~v72W*J0Sr!`+ zMhr^L)tiZ&so%qWeF4^No^U`QNIp+fZL#arIUWPGoXVn;aDily1w3gK8L6k z?hXkFgf1o)Bu{uhzWL{1%p2=&4_^lpe-6>tL~80wh)UUoX16&9S-d-r8Ss#b2A~Gf zB(LDNpjWWw_j&g#4-Pn!qhrLq5Se(d6gBoGNotI!KG2$lIE-LH1K1TuZAJhw(;lgwEdL>`l~vxSlo(mYTFpA zN;SNz-Z8b6U9N%_6VBQOm!WR?7sh%=t1@>*rg{2zCL|p`kZ$sS#o}7(U6ysdi9IgN zp>A?t5FpKYay4rR{jeS8F6n%*y!XQ2&&!yaXs@X?NnnSSC0Thaj!%4c&%{0QJ&MVn z1#)YyB`!53P2riI#jt1=xC(-2K2`^H9BPQNBXNLD=1mt=z_HZXI6<{pGCMlqr6gF9 z#6sA@+s!SCB++>XwqVVD{HBM_Ph?&Wy&r@H5S;Y}u{|o|8_x}Bm`h}^rONdG=|L}B zJfu5D-2b2g8w{014EX7k;t}&F3<3b0Qu#y{F*aq5I+F)uD|)}PPVN9aIZdPOJ3CnN zs1wPTfQB?6tD!3Cf?Reaplz>tEF{}u4e>|sO^#Sj$OG>asitpcf(^BrisPL^8ldia zi+-3s+IJ{%l^xC72DPCL329*BhN#))M2ww>#$_#f4GY1dwVo zAhOF(5ZxJXc*4PQjr2+FmwQ_)|d1#ZI~K#}EoALy1yFxO>R~LZ5xQZ-k8lDH;>MrZQuf5A2O|YOP zRlN@x__Max^6*>4@3#{W3xdZy=;UNj=*E1I4>LQ=c9aRB3#@*t&cGBFWQFG5q2L18 z0Y6p?DRu)5+SbVdF57i8l;*RVX`qXcYsLqHgYDee1(~i$4EVln*o3Y+;@XMYtJ=HX z>XTsDDO@>2f|lvlcb3_JK7H}Z4rwrE=iJz2419a9sLOyYOkPx7EPQk?cRQ(tD#B>E zP{hRZE7sGE*k`eERW_;nkU(OKgBsFr{};IkLi~SfJ9M#@w!6gYY(=%nAysBh>J2_1 zogC^PDo%C-Q=Nl>fwxzA72+07?L@~+5Y9pG`9mj8^E3!31`+V)K+z3F^M{2le5?T* z$Nq&JJH&%2B(CQR4PnQ7=i@};psul~KPQE$H0n|7%dKBESQLC3pAWZnLB#Oue$~<=k-6e)T zRV=0&W(oA-W~La8hpgJPI5zKI7nm@Jfwy+(X`JKX%i0<4WhE0^o>>Jd#_rG6e#Z9H z-w*qxO22VD?!;n;N^RNPAjyZ3qU5QwJiOt;vuP%U@H<4%vm@ziwQ{5DURjV72?l|; z&j+bg+6$oiaQgO*icYpB0sv7O4rM=7h$a+Q1@j^&FvG$s0&fqQ<29_mFP?$kAxYEI zU)dU(JN7hleO#D@?SKCw`Mud^zZwecmP?M$Wv>=4hG$1YRLn~JjJ40d*@ggwj-xFg zicUL+2u48`ZgUcZwQ?r|OZublh|L#z_l(%qQPMK}s;%pSeIXj!+KFvZUOWhBjVTs6-=H2FjFM*@EPd}yKnvuOWW)rK!U zvt)@=bNHyF2x$gp3hm+x^-tt2ikk=!!)Wf=(s(lv2H)fF0FiV9%D)3GoY(gIv0mZN zMz*??du6ql9qu-ajzxH<*v2QUx4eRcnj=PwQt|FYR6yx3z)KQ69(mlr=MLPwP-i+W zEZdc4onAc*Ht}?zt&?*%`Y)Z+6dZ$B1b6uJ&Z+#+xzhNvPXg*2|KyLn;2c7j{0yk8 z^g1(0=Rp<7!(tSvZALV0iB)>vSoQ|s$ ztjeBiC8Edb9(_3qduF~{GaThkW$8tU`d0CtEl=sdTEkHNYyPA4a;#|UnaRj7l#!}i zm2ug8|0|iALnY5Oa6YUNhTT-2H{P!1alr|bCioQ;;1hb2d-jEl*5tS8Xo&3?R&G`5 z-THq1Sebt@f}w=<9yxZrcWn6D$fc@g1f@lnA#`lJZjvZzMlOPc>1Rc z;`pB~BvHHcqqF#>?Z$9Y0KHX`c4@3Nmb}ePEiyAM-Wp2V+Hi_;40L|s?UwC09rBNF zoo?&QuP{Cm**UX<<^TDlrY)aBpK=86lli%d+xOYZGoMw?e;PB#juK(}Aez~cWh%A= z6z(a!CdCu(-lN6_rL8%_m-niR|EPRtPea@S;e`Yq)YY5;+EY|EW|`U8w9T>$5>6Eh zzzbK(zM-c>PcFpLISA6pi*kd1b~rZ7r?x*$thjmMIlcgbR#ex?h?mZ=p4d5&%`Ib2A$f>Q9u@4DWZDJrL83QX0A0lMu&0?rgm@&_z<6ycqad9wd8UA? z{{MhVoiP8a9&X5VRSa4LbhJ9kk|q5DxFI)HDVZM*bOJPQDIc{Cmrp5YLF83PrDJ3G zd}z8I(5ov}Sqod$JsOj})DN9R%}1a-YjuLJPJwlT-s3;ah8keq6CF2;Iz}NLepB?8+t_ z-s68=p|#yB1dd4!>)@Yi@OL;*IehwtP8a8Ymy8GfgZ%+JpnXpYP5j?i;PynVi_Ydl z6?iU5l5$Qh|2#?JRkc{4QF&N}z^p_Jx880*hL7`1sxBlRCpZ| zY<;l^csuF!ekT@2>eUr5BJ^?wa#hT7VlDkbXu{2}&#%?S&SN>;#pE|`U}mL9j1XE4 zO$eRqV*{}0+|;zbU-o`Du=>%!0?bn{?2$wU-FxfRr3SI0wplHR~(VqUn ze=-Tn*A-`I)+3Jy3@L};YG3-Lz1S{MpcUm~bfxyr!J*oXt0=T@9BZ%>+hA=F?}H+l z9N1wU#Yirv^sp*jQe=Gn#$*GT!;c)YQL+WL9r3j29v51)xL%4lT*rR`J@0*vns9## zw_~#;Gne208)~rQrk*^ z3ug%>tzZZsjF}$cj7v*}%6vVQ`cTA=>&JgIJE`$u$rNDnx@b>Qglq@DvOjG{bj-d) z9E}bx+7LI?jF#+jF8WG+e!@6ItB{0!${^45v&R&@VIIKTcfoV2sekB&;0k03Bjm~z zB!03`KmJ!}NORiwVeFWFPJ-Kzj+ho36}5i+cex``?WeBx@n$i&@zJaDr-6cnmoxNT z~}l5(FBZ%{qyARieodEUnZ`HS@TOr2-{TZ1^xBOP;@SDLln`Bhjla6y$E;dP8*^IOxeIri`t3{w5dH2fJjiz!^g9RV znZD#E1<@Di-!)jy7g^>!xtAtef;NhIes2ao>^;UnZ~{n%&q`;&PS?H=$K}9+sz4WV z^nC&dYRpRN$DTc%sd((ljH8xMAYbIOyKOOQh7*>yoM#c+_qF&nVDpsRTwJ2FF1}eOUe8B(8{SH@bR&y*lQ84NUu zsS^2~i$s@*XVyYG>R2G@$)DSHS35Lrm^nf;^7<>)){^I~^78kf68}^QD03m zrl0hh5rmH3cm&sdi=xcl&W?+e(iLb=f$#g@t;HdFLsp`oaCM3xXS4pH9r|yRbe}Oc zH#D_s+41Emu8t}N&NvIg2Ldz9<)8TEe{>E{!3TXPK&V%%d9P*F!PD1NC+}q6eRxsvU)l#6`f;(%)>^6ym0woufqgHmVdhJRqiC=IC8>eTu?L^{ldUG zYg2yaA@5N+YJAIOdy$X0X?pF1dBj)|>y{FKvNKw^1pRgy&asSp<8~;J{lcUnCfB6# zQf|D;F-$zK;w!kHx>NEWhdDsw8lAKI|L{_pr0<|uuL^yO(hG)*2u|c$e6480412O^ zUD(6cu5zm?fsYt4p>;od^khGN{QxDI4>$YUmio<$uIhQ=v#p&uu22c$EuY&4RuSfK zJLeAO4%K$Xe|O2M!x_Z<+P8m~wJAd)kVcD2NoH4TOLRnBmp-deR;IDKt^c7{LB^GU zr@xF29wC;DgNH&&4o&H-kI##Ze9_)$Y8lS9LOHr~w#c8%M`_%S8_7s4&RpXGu;67Z zk}P~>Dh7DA|SyJd2TSteKGtwmPHf|4?dza?5|>oF447pZ~9c0XfhEG06UsSS<=K z#+%kTCW)q8M^Z%mI?85s#%b3SRz6q6v{W8nJ7WeR75UY{cM^b0W~qs$Ies&r=^)@w zRkI@dMm{2#hs@BY^JcyG${uWmvG^+c#WHVr{><54UC~4(3;tZD5TXyn z?W?t_&L#vA-z+qMJ{1=rp`_Rs~7A}dT@)-H(8j9q9u?d z?!X#}D~Ts&_Rm7~Tp%6R8D#V#&x8+DbCHD6StzO!HL@L0DL>dQynU^73hhJ3=LY>n ze3ifM8jPr}SWkR#SDs(EjvJ2|-Rc2)uyPCxO|EJ^Kilg`e4sHO%YjQCe28%qKCvf7 zs8@|jWxF0@m{PnkQEw2^Vb{028y%>4W?u}TP1AYQRKA2GndK^&YWSKk$>c>qm&G#Z zwBPy&PvrI4#wYizf&@fw7dx0C;Y(j5k9#ZFXv5Cx(6grt>Dq!WGa1)?&X%`4fU!m* zV!dWiV%`Y^+wL9|Pr&mZHF_>mVX$tU6+uIN>g|8N^o7Acfn3hR8zV1o%g{nJoG`{T z>nF)bRg;6ZtO8t2$|i|PzO~xHuxdg=s&xf-xZ5(Eqe&<|qu4=M6rC@w7j*qSJ7WbH zC?ocm*CPAQq2C=?Xe#!AcR0YDeu@)0BVZkdF1a6TmlSVE_g(WgOidDxTvDsRpC zp|rmX>^EzNBcp=H1wf$EUTfJeDEU@0E{<6ZzV+Z19hiMazevWZk z!iYc6@oN(+jLeV|ZDC<(rE4Ksq+sFu(y0LwI8u%34bL0H{X}OdWiBis)`8&ndo*s{ z2oXT;XG!Y{$mDR6o-;*@+%@;6k%SBhV8C<}!kg)~{YF53!%vrOr7qLNtr@M|mC24& z;tV)uA{7z0qLf79gOmZI{9)(83ZwKs%3JdXMmPUb?oyN$Pa2lzGrcLK|Mt_}a2VzwgwX94?zl!3MYQ<5p8lJ;2nWh|v1NA1$) zloxJ-7BM=wy$D%)3o-#lYU#%*??aR*N|nS(Tdfcf#^Rm_p{smIsY5^A=I%Mtm~7z( zSl?^#ebS5h=EU@566mBeWhm7PphmIjH(Zz!ZSV!I?*4O(Ewh!u(F=(+bTEi&oN)!C z#o@JSTa$+t+jUvO>*ER^)K>5`rD|civBdM0z^z>|zOpPtO>X#>nQB7bLcG7Z_VQx` zne-*P^2ic7CH(MA%erq+jv6#e+ za3C>SHjq6gVF4Yz9k@K0?ts1=Qw^mQJ(knJ!lO68v)m}pXs4~FPF)eug;c_Qwj z!T9|hOzM!1i*s93V|&LwwMrCYMx#XXvN3m!<+^Vtg~Sm0T;4nE^Lp<1>wk{8Uf2EK zcW(8p?@p^(@&x&uIi(G3>A?cL-S*%x4XdTZUt(Ydk*}@s!9k}ALS!;Kkr`v;QpRC-Y*BWXfdMO+u2)lDqiP2SSWNbKmAY z$^4s|rKacdWTWQox1GqzHH&4h37FxEd8}p^2*@&c&NhM+sf03H3rJB2(4;9I^Y2GTHu$q&?FU$9cYo)6v$D$(>GOu0I&sSrUrtj{#`-YL!~@8sBR0S!#TRa0&s~}@>gOh$S%3*sG5dWNwm=U;4qJQoCw7T+#UI?Q#)gS znJZ_?uGfFD=}c8+f@dFRelwJ-{Tx!X(F)c#uC(+m0u3L;tPiv>Xx3jBLZr@>P2aVO z=~CO@gh&Sj@5Sqmp2!-z8#iel{V|^W)fIVEuUrV1$#y<~4otxtVtNXozXb%>_emqA zloMIse~|PI&{{L@9Yc$ool;mwXBb(h#kMzhz7v_or!tNwm<~4O%cQJ^XI-=(0mIb; z2XF!O+owis5?EuUEPDgbhBq6<`t-f?t}k=!T^z31=O*s*B({Re6x0560A;)}G!<qI<&Q5w1z9~N+*?boH| z#nxo`VH37ZKSY5FppPYRP1M@DoY}Iw5js|IM5I0<+!SAQ(IRk$lkYFn)6nYzK zz?iVDot1uVczx`uYGC4hcK(m65?^JW<66ljkgCNQKFyGjczUpGKVa^pFnn*kfOhpS zmGRg!jPni8zf`_VK3`QAn+p8s4ga{byRUnC=Fa~+#g>d&B`+t?)C1p7);|rI7eWy7 zdv`1BO5C3$%z(P%AxT9En1CrgCV&n){IY^pcfU}SsIZ$SD0Idfv;M4^lUn&sXVK@| z#dp+FE`Y*DIS}SZHiNI8mrqh5K(4vg@L2NpFCyQ;N|ZI(HS_(OTkyHpF=3v$@R^jK2G9)G9<2NY#{Jhu85qbecYZ{LKG&>EPcTo!d&+AFZgnS~= z=cBrJtQ2j1s{2w+LgDChTQMVyWYGk=~gpwizi zgsEJCWIEem%%53>6jd~R-21Ea2N>r^XD!<@_D@~lLdzO3^gA|z5qEgBOa$-=FY?-* zD!q(LmjnCahtHs&#SKY;WbPA%`vrsG`db_XyR3C)wGMIa)-G&u)i0**5#PIT$~kR6 zf5oRzk~pKw#h1Sg!A0cBh6qsUS6Z3s#a5yk_(zPU*n-%`saSKL)7%zYZT3Y(kf?mi zPJ%@4{a8|J7PZKQv){=CO&ph|rvJ zBDcc>c$Kp9w%|2N)6H>O9mo5qv%$~-5kT9?{a5W{CdYA5t-=nxwXHZKzhE_#M5qkO zu6yH4WlmHL>+I20g!e3yEUR<*zYIIMJg*-;hjYF5iw6+jnAJ9etKs)C$;bXWNWPU!g!>c9$n&=E@xON%7Z+SuT2Sh)2rtCv zusVl`k5Mjdtb~|p1?>2+E6me9ON%DowZ)m{iFT|8Lfy@oEPAf&p16fM;ilJ?L6L@%{ybagm77TLs zRg=6sOnSl*?0aMM3@NL~EQBR$VGJ+0Q2b=tBK?dXW+Xfl_*J~~>`foyk0XhK4yO^V zg@D|VF1(aOF9TQfP%1B^%cvOYXiSUeD{bA@-XHJ&^Z?LF5+m?tf6aO3Um9otAO05k z7cbdZnEYc4<4P$m99!4#O@wsRfPARkqDM$TorSE$ki!JM5&R0N z0VUxu=?o&Jl}i#Zi`et=a_mEp3z_W!zQX3$rw*{1{+GF}`N%3K4v;zXj`>c0D zJA@8-X=Wo-S5pIx+$d*e_t1Jf{o0W`)sI^CNZoP9>9I0YrbcRn$+nPFVz^Ckn~^9L zM`1?$Va>{NSzs8(8v7s;Z}Go3RQc_{%a|E0H_a(AS3iHPj3(aB`rXaOLRsn;l{e{2 zR-19?lANHwW;`Z+Oerb>9_U7|JI;y}9!?KLav@bVp}G(*<@eSc#jdhrRpC_zYo?i< z6^{#hyg4=TdzrFZqb*iFe`h>6a3XcWu=%{P3fW(3n7~v2{72VSLNG;!M zX&T`qHAqyRQCJZ8UI+pa1&!;S%sWUTL|E^O{>Us?)jmO{;bz^0=C({>* z9Aq+W#fPs!36+jAd`SWRHoxjy9aA}$t#X;_cP~U16L?e(XH76o9jH}U0jS0>Rd7&f zQURl;3rDEapxtj5t)^(4NCJ6(PW#S2p!Gv5J{xP3VyNo%@Ywz;b0{}?)K{A_pGs#k z8Id2+1u&Y7M2CSZv(ahJFc0y-J-)7qfP*&?yMq&{ectNSv$eHSCa3(oFo60fUz68= zPRB4%FPpYMOLWA-x?LY=&n`egmt`T9dI=*i?ZchbA_vDj-s z(KNr;y_QibHg<5e)|A58$$g@2dta{M!PK(sZxjIzX#85vV;J?c6HU;*9JdDIO@C=Z z<)%v%bsS$23tpTg1me^l6^SWfAnhCm|v)$>~}3;o)~6wZIM*v zZ)0y!8{z=NYDWr4V4!}VoofylCE|laoHGp=8Q{1z@2E~u8OUymKF|N@Mjw{xXe1P! zx?biy+BH-)#x|W>E;$rlVn4^vzVR0zxZ=xU$Ot8qduAdI0(nw|22B%8LQy)|zVrY+CRFOnB8_g7{sDtO@a!^N~hUi|lWlFSkp zbVOwy9H2V(kjN7Dm+&%zM3FNnmb-iqL~p${_gk~;Hf4*y)_LEp z@gV~$l9zvweI@{^F#x>Ol!B9P0`kn=xycwjchX zz3{r$HyV018r_AgVTxE75q$ckGPt557&GL1N=1C^qk4!>$+$BRr8F|X#|m(5({F5G zw}LXiN_l)&a=qkG*_5>pUP;}t>~v&7)G<-iv}QZ~PBhMLc|p;}AWdwC^F&Um*!#$+ zXizOu^6n0F`9fq%%UI0toN#dj3$OvO7O?g+F|Y;mx*b!wgFDl?8Hga#1@=Kqd>55x zApkAqbg+8yrs^_#s^jJR9>+qCy|kdt#df%vF6lJNbei9&t2k1_wy~N+>6K+X{-&%6 z$_ubD9kCW%KSYJTAE6t~wYk`PKP@`XjgR@b#IK*Pa}$U?)^dnitY14WJt^crAx&zD zUt5Rv{YchBIa;Ltc~$Lt{x5~dM%i+F>=)JJwcw(J(mDxwT(2AHjQM;X!9_xMJR3@r zEW929ph=7ci%(9M?!I5KUf`U259z#tw>_UfPulN390%gQuNJuFgD=$O3!06TJ(TLf^=+Sg- z`Xm6HpHEp!&zmiAsQ2MMun@V$U=iYBi7<=Os>5wA&9p~C<@3hQ2lV~BktHcxZ^72V zjtN>{qg57-)GT=UFt2ddG4p z-7u_aCnN`>*u+CKCxlY_==w%IK(8~ZxO#rc3LW3#grVF0=XK4sv%}9)zPh-Sy1|$b z&*W?MaUZ3Ky}X8#7TJpc0eKzbnVqX@@mu4Lf9$?2GKo?PT`E!+?3sU<1z35vE}-t{ z|6}PI*yC!$^u&$TCY{)5Y&N#l*tTukMq}G{(%7EZHrsgT+ui?guJgRNar`v__O@jZ zC&|4_J^S!V%sB5$j@IGa{p{;4J3)_O>9^|Uvoj+!UPr5OS3}J~u_EZvm8e{5OrkyH;XAW|-1@Z64tOva( z`6IAfPip(n0N&0EjODk9S_ae4mH5+zV60B5Q?}D4EFg)?3YPB1&!c3lt=3S1bLs(V zVEl`yLv=8aLGh2*QXhUeKCG4m>4acZM>3Y+=3u|Tjrutz{U|5CDCFyY7vcy3<&Hpx zvAUablCxHG-EPP->w{e!H5kec&Z z0W5zSQoyqPVd4$`8ua74Q4+y#375Ka&;^>E?I^dyWiS#G!XpbaPLY-1b~mq zEgG?t_R-_o3x4C5h0&zs6{#l`tmC;I!%XkfsKaj)Dn67g%M@$wB$3Jilgd8Q6kf9B zuFw2R{>Bg-T7X%uXFUvOl(8$2qwZE39;Jr~K2Rukv~eE573}sXM#_~O=8G=DdAPX^ zznHjJK-7u6p3nknk(K{b?7(wQL+gp(%rzplXzjs_l8%w~;CKCTqNX*`un}#v;o{^m zgmH@6d++r9J6*xnwKzKBE`Kniw5j+zT!#`v0iVbF4&gb9Wra6;Ahk%$VF8Oc-jxQd zdv9h+M+E$NrYdw{gtgqgxj4&1hc5DhmKE&j(Z8iL_2#5fyhs+fZCrNoT4XKQdB#N6 zf4{sTKgHe)nNkuJvCEOK#%hsZ06LuIXY{k8natnRb@Jix-?HUnQ7Mrmh?aCPe379m zsLf_i=ZzE*cWsum0eOo4WUXul6FWJOf1PDS_~WX~mSzcz!OK1##Dc%>@m^N?>TBz^ z!hLZs(LN=~%8=13j|20|YG#8L@0+~{f0*aw&=eOv7pI=U%stTwHI3}=L=6h2aJG#> z0`&Hu=Sfae;7In@2tUjmmrCGq@YkU{^4yJB`-fMlAMf!4|1Qj70XI!D^G)ky>(sFV ztem@3zpEl(A-ZI8KM(1f|0Fb#Hq~~CwBp{-4%xu`v{Hl;U{$>rdYM{LBi{Jx47aHl zmE6<;t<<1cn*n}hq`}R@&zn{aP{~+-cUFv2PEq$U*0sD$eX>`gqiLoB%zJEm$kuWzbCC9MTvO^5QB>?Ar-l=o7Gmn+-D(+L+gG0W zU*vX{`leW_6a|-9nVBpyZu|O7K;K!I3lV4Sc>2PzjwFKyn3$@lxrDk_7n+}PRu6Cv z?13JdRuS)ZFU?i}a9d7t9;XWX6Z2w*EJTo?6*--QP3Xb+shNJOt>Tlp2k3Z>`Rr#a z3>(KXacAo{aABZ;M)T!(G9!CiO_I=D9QL%E6w;Zy+GrCpkOV|D>9~RoZ2M2yq!yAp;$ySGM zos+_dx$rDk9AfiNF`v%2O!q*S4f05oJ(pRv2JymDHJVD~&M&zH>y-p0`nc*oJE|AN zBvZ;Z(j>?8!S3F_vT>+(D`w6OZ`%~sm+82xP@W%);fh*|31rbrBDG&h)9~zg1_xRE?3HI>mDF)x-Wc%U2 zl6*flQfrW7USi=DO@*gc+&D-hJbL=fnBX&-D8uIo;5Oc@Gff28hVZ&gHg?;+E28j7 z$c?tPNYsoikB>PQz|}cwsqAYL6o^5`rc=9YoyzO1nuMgczxlGn0!KJj@aBeIB7Ilf z$h%jkk3D(wv=V@|5KT$-Ivs?;=p?kt0fWJJK@Sb?VB7F-xe?<<_fuuqZc_YWl$BYl zUrT31sA+uVEAoX$jrM)Fc@FW-8`AeI;$-!9zW40NZJ1sp_B}pP=8e!w2pMdF{xkWU z8p(*Pe}3yzA5xEb^CPqtb-M)c%{c5M3%1GVjRh7B8)L!63oVm&xw^yb_9p(slAT<{ zI^=-Fl(oB!5pHFLcr5j;NXVSdnxFZlsG?IJo~ER@pE?1@C_c9-f-v$c`K*{l7@Y$B zQOkkCV5J-O{9-qpvCPXPo=Creq+)UEKNJ#;AJPucAC3m1VlRo=p_eD%Ix#BM6`dQq zjoVYs$Z`wTz#MhT7=UKL7Gs8yqp1yXf;pOm>`RO?9W47MK;AH9#n=|`Tn|Hq(%4Ob zBo-Owq;_ZwDdXzK(%RdX^}o@fT4=w+#@sij%{WVRK73c%eHt^8XfIw@q8qk@dNSg~ z7*xIwT(*d#_U1<&v26*x4eaCIR(nz{1vET$Vyv-aM-9p7rJpq=g0!Y=)AoxD7}iwU zFCKK$@(L^mA$z(cVX2dfU1%Ow?Hed5C1l{#DGR|B zyDFeAJZ%TQ4ET3=*KUG;(JChrlM+l7i8&6_!DdhXfp+qQM7hHtvO;$T;gSmnZmgsk zhWS3?#<&$(47SZvb+koXwP5hvbU#n6*ZwKl_oR}+aVhz_GDl@O&gIzMQ`_A5tXK z*dA^a0yZfv!^_eEqL0eqk7UEXqL=VVF^0t0s7&Hn()+6;kGJjH^)Pisf&(STzacAdOnRO774oeb+xGg1C2D*?=oi;^uc44@aa>0KyD}bi` zK0PcDg<&wJ7pt?yOcNJnw1oCq)ZXx))bCh2MsH7awiI5x!DE$&(A7eCV>_!(h1@%$ zGP|?{a2|X09)GCd%>=y7EB_VnZ^P+;uoHhD4w4GV|Gqx0{S*@a`(K2lrkmB6Ib>Dw zfMZ`uSJRLeKbnfz>*!0QY=}dNnAY86U|PcCAc?c8VJMqqsl0UuVdPmkmdSlsAz2;_ zLqK}yjUzOc%=YTH{(_4-yU2Gtt)`&Ov&b_Oh9K*`EA>TF`9fEe6K@!&-XD%e>{>=Maa#K zxs(o57v(%H8IBNJ0+U5aju>t~4v}AoT0v@0Hi9ic_K@i(^cdo83TMhX8Gd?n#qZJ<-Um)%`N=6uVCAIb5q=v74Nm$t?kEL`YJY)?i!l4Y{6d1 zwr#)`nZVr2237gZZAP=HV!L82E>O4M3dc-ybx#w82;ep}f1*egA#a#*M_VMw5y0<^U9%bh+(vc_zR#dX zZ+^b;ONFu-pwmh6FeeS7K%?nK*{l@(x#(rc^vn^#mb#@B(}`;ON&pQk#wz#FD`Du# z-Y{4*Jvk~{nEoJ>0EL2EhJUhDh=~#N2ufX4Z@*#2KoZpG4B#|XwWr(2v|SjNMIF?% zpnWSZ=jio#jTzkL`%bLTQS561sY7AKiWA*?q4b<;SZ(QF^cOeGR+3MRM4gPB_NRr0 zkYgShEUq4s~;O2dG8NGSGd>#<^6(T1tC@7utTBMl;F~e6% z#6fe3{a)SK?~i&f8nN-TD^o7A;xCaUjFjwobd^*jujMu{0&!b{%G|6}yxwgPXehHO zYr5#*5GKeK(`GJzm5@LYKat6m2vb?j`tOVzvL=Pjn zgD_Uge3bs}BNu&UC}ctYIoKZC{z<=kl;lo0i_LoQKU*9)Ww@_iIt+?va@Fgi< z)>#o>7_I=`*jY(eQ1sl&E$(G(_IFLr;4s6iCoF^hIKJnQ!g$XqE8%Q-tr!GN6ru#>*>gnJ@sG&Nd~|#jMwQ~qVVcX4RzV8X!u7DKZqd`&m2mc| z3M;aLT~hlBO87)^*r7eEB?ihj&1gP9FlY?HQcmA(do9$nz&a^rmGKnpwvJsmmDem= z_GN3qvrT|s&XYDJV@xFPuDvRME*=xjT}T?msL*xF7fle0((icir!SKp!|H1^|IVQ% zts8UsYg%OO)Y>|6ktCJuSKbpEyiVf#_BX)Ex#tvbn+>S3y?8;I`K~7p|H}%=cN>sH zKJxnY>9INFMSb5hu~{Hp0R98RwI381nHpLZCn;Wq42UZ(p6*MEgkGpuDD0`?C~(GR znv^ZbOpccf6xcgu|I5Y@xLcAKYsbmU_cPV1R9&2Qa;UI)UjctVJxu~Ihy2B{MdL+W zHn>)gBK@jUuvLESs06wq9=^H&N69W5M-)S$5_er7lMqz$n$ zAJ*)LAGEkkpb=Qf37)#$ch`^$@q5GQNyeP4=E*kohwA_%X=H5ue;j1-e_2FLx9lhl z4N`*c!kE{e#l9n2E}CO5Ls@w$;B%NLi(neep3NtHi8E9@a?JdT`r|bh5|EV*$`~cU z%fnQxG0IfQanAT@l>Rq&7pOyS29#(rPVnWuu(g#@V;*ehVp)7%k>serqfkH|s*-Hr z6O1v&?GfF|+_LTe_^a)1V*UE5g9x5aTJ($0IDtiR44bZ=u8Zo{P+z~60cVWE*SPY| zCpXp!5a9r9-kBzCDj17V4k|?YqUPvI0xVhCGcU|K3rY#)pRmQu9wCS5ZNAL_f0)=E ze}IuzO)->mm7xp9;p1Y|>GG^7QZ)B|iK5w6Xc>Y5;wawuWngs(9g!A3cq0YjG8KEzS(Qv#zy%UAqKYJoux@o=v zIJ2RAWdEHrR`1&rp_28pBVHKD6EDS7QmfhD|2hx{jrzU%;{q^qEtWGhedxwTVy^Uj z#Q{2AHa-x2UiGrgq1XMWD4RG%;fuQ$uRDK-U|lD$yI(`g+|&uyU2>5PDBcsx7T?7E z*P@r01=>frGqkB?I#YI&<0=)UH(;-_6H4o943s@oVh;WU+o_o|KxR(mYi?GHs=FwP ziM@>T=`3~p3M0g4;dJ|AseIotc$POkMlQxrXDqDTxK@-^H$Tko;N|R`Z&sQbuqMC@Ri~--6J>UduDfpNxaiCOABIiZmFX9 z&CtLtelZ$nVEwD!r#O7Xo6i6(7nWeW!S)C0Va_OS3YF9-`3*?X1Hp~u#G5gPVPr1$ zC6#R3w(Y^jl_~tFT?K<<uy9o&)%>?UcYRveS6z@#6`f6FUU%#1A0`tK1}S zLc6{;VL>XQU2!UMxM;O1xS6R=dg3uAgiuJ2Cf?agAY! z!jph6f;{l$EWi$*phX%`#b={$j&{w>YF#T}E{#I^>F8ZGJX;cE@xmQ|W60*g!uFw3 zYSANsqCxvl+ZHkFYSnaFkU+3os_FRf@lY#ke*PCr^jTO1UKQaF%M-^zz!5VDGfQ7d zA>ZMThp~li{YH|>w2xN)?y~=Ul6S%3zYLqHu<8E=H8vyvudToU)7(Q91|xbmUbYxa zEYHC^?1wg{mf7B@NV7=oXbmgbpGk->+80{S+Gt8N9YuMK{`6J^kDoRr6If{u8v|*5 z(6z%a3t?yOJ6>fpU)n9v4psZnxY2O^n7K>oeSi2N^*|+d1*CtGkz0;Q;2>+*gOZh4FvhnA;3HP&FiS`-*E25d1~-kqYG>-Mif}n z&xbmOV-3{mnX_Dam$#*9(1MGx0$(0g07R6kM!UQPo?@8dF z3Ue#G*lZ5TFqu_R%gQgxvfB~aAoM6V@9SM4h@@AF0}gGJoCQO@8f|O^e=_xFs(-&V zj0nS#;qbNL?DRk4npX*uWt&_Sl@Z&gh)w_J1D{0Pu}MS7<+H+L1~8WSVE+vmj)m^s zu-jWaBWHehsm)}+7%TepMSFe3XooE#pdPhA&&%I4Nk)d6lKAxbe9}9Q`UA(dN?w!f zH|rJ3tyYT=@LUvu~C?M!bbiZN0kQQrB}2|{x3h5HEsS_4Xni3gUGu|@2OT+ zqzzqQ+P9yg_pux{P}rYhzjdqm6mz8=Wz@#I6%|)M;R*l(M0h0`SLutFpz8|cF-Gx1 z{~T#`tmhf~s#I3kMNCbJh-70UWt`JpL1dP1JKarx{Za>!bR+RnVE4QiFY8V)P54x& z%TM}v=S>osHU;rr7+OHd@xsj>TrF2O4K=x6*6)RZyCmca$G$@>4v_vLI;2tNzxut< z%n?pLGPNJ|z;tW6frN=9vQ#!fv}}G8l|+KnQ2sLa&=QbwM(nxZVob-ODf4Sdm7xZD znW4p^==$gAZ+pIZLc?W4&FiQ&&3|Uc1wH37jGKzrB_^~5dVS9ms*x)i44p6FiQ{jH z-x`MkD~IY;<#J*N8-BMFikfa7Vl7hy6gq5V^zX@y6)%faPn-T2ZCXCo9AU9Jw7#fX z4yA)#fj#XD1}!`rWR6gnM2dxnSYu;F5W$5yPB&5eEQ`I%wV4 zhPf``#s;uYJ|7Y|N}AN1imJjA`zEA{h*=g&GV0{Ic!&-fo_xQNd z%p&6*M4n0E>iAoEfW|j7%8<9vnw@%-K%X-C`P0?0Qv$Fph~z*s?5s)y@Klj@ATFfG8VjK#;EKn1krc7>pqiJFZrp7m)jg} z^fS_%d^@CRQ&9&V^E3rJ;~W(}xa}JCSo9{zd?|*LzG^@1cx9Dql+GK?`Ok|*dh#cg zVpe^JyT4fRoUk8x_H}^c?2jkWi|qre^lQ@+4B{re61!}Tu3LVq)iTE*N2%FbOo^b{ z^$3=VC%%rp#SO(WnxY7CkqrVI7OPMlKgrdY4qosQZf$BEp z;M)gsLa#|Hxz)!-m+@g-?)*0ZBgBf7$=8m#+k5(YAzSj^s-COPa(TWl6;0y1?ickb zqAHgO>SxSs`}1|Zaa#kr!W2HLs%1J6$O-rUECjHYx$=c5wO6BIv(kKvgfY*e zI~PG_{A;?6*(S)Ttj9U}LwOryl})8lHxiVDGGG1PdC|1d`7{#2;{=74&{JD)N0+ou zI|?@;=F$3C;|Yru^)oMJF*vkr%`PnRu6=T>$BGZE-MM8-!09Z743?4Ydk^(tS-k#On{xbP0yK~Q}lDwS_ zpOjV6nx~R^)Sb*L6J;19bNDZr-d51GU}lMhOI7Z>+B@vu0(NVhXgk~%{yz)L@|rO1 z#0%J#IDBS%E+)8gsL2>a(V_#O44uCi^=nh6tL3MZ&Gx&0Kchz-qe|`j5&LKC8!Ze_ z*y#|sWb+o-yBe-$OyLslJ)sN$en6i>S(%4o)*&YANaUurN zpnC|z+~bYno33Ni6GVjU#Qle7SN@J%k;dB40YRDmM!GZ5M!4k*=WTm?a@IOex)-qh z!In%^D50tcu?4lvPJ8-zka@RDjHfZqW-%1+@?}lc{GQEpd=LQcQ8-};foTKIn1t)3 zfDa8avi0!SdS#**Yo_ppMZXEMQ!!`KJwXP^MMXpL73>+6VaX`+2=n0@4vo3DIsN)FL!^ zrO{Vh{Ste`BSf~8W)Hc-kBR*om)nNqn8Uy*!~FyPLMW*)0WSs5O>4&wI$qO#0Bz1}N~6|kx*9iG0%P3(RxpyzUa z`#v{!Ycg#BM^B<2N8;2lCBrt;91=KiwZ!1L$EtS>QD2^p5$&{g(Ym#3Z`JA_3+_&g zP5U%g03Qd|*KOl-tVu5A&qn0a4MFL}&*=NzADLwSlsk30Oj?zp+ zdv}u;z0hXg8&Vc4Ct~b0&qh*#-A4kt7K#u8X@MFMWJHYuamuLc&1z~B`i=Q6+;Tdz zLxg`yr0H5P=Q~d@+kM@U z5s+RKa=CxbeBR!3u8v`vC0Lro^kBcb?ZoZ(f`;0FUcpQnn(8PW?PPci|6(|y-ZX!c zkZ9wyya}tB+5DE3n$q5U)>NpcBnh*OJ}N0mWKE~Iuq$H8aDcb!X&z>@`tlGFx^<$h zqTpOx!oS3ileR8wL7%#n@WqRd18-OkdujdXmGkD+`eN;9YnspfsjzY1+7D>aO4f^) zVOum5&nRKb*1!m7XZtO+E;S{1uJJCGq4m1M$et9Vtk`>h z(TdI=0m#1~Knlds6(Mr`w7|jN{)L%mVzOd}(P~B`8Bz76aYxKt8X7PQC?TdDsYa5u znbizE-zec#;D7%gBZmC{j2O&8>uB|oyaztB87lOYN{eZa7=0wKu&eP%Ombrf24&3I z-!o)Wai&)m9bGgtFFytxO^bK{S=QyAl79>>)7nrK`dK)ncpytS1oVhDF5!w0FpRL1 zi3B(VNiyk7r5Ua= zpS!=lL~6g;{T{{`TI!;{bzwdRc|K0|e&!ddy!|~_ylgCkB^nX@VM$fdNmPlmsaKfy zu`-K>&7&v>uvdLGzaU>QeOZ$Hh>(Rs028}GqGM|8Pxe%JCxhNGo?25U z-vRi|v5P%UH#nTlQh^C!J;=fEkn}PhIxHO-@w!Q@(YC%+p!G~28HDh=7vXF zpZH6fu)3r<5s?11Lmn_}+|RppMj6~vRxz0nOyQ&yX$GHJEP}o0`BwSFYC*C?56LR# z5O?W`VMG*KRsbN``}=Nei^wXNK%T`?w-?QjqC(F@NXZ9%?7 zTExFyxLF#G9DE5)?pG>X@YF!IzH15J>_;J|_z(eQrPihDB1~sOS#E0R^8njSv(AF? z`7-mR88fg?aDQ%pWzQJny#8hTg0-HA54*H1`@_x8)0k=~*@Et{N;L9itKzNMSpS#Q zu`r~$!J%oCV*J(P>Ev;sRSuZW#=)EIt%K6CKRNt9Fk{}IF+9v@kkv#qa{_9UChbX0=e8&`Lz;_F+EB#$Gv&ykl%317YrN)E983<&) z?@JY5Nm|UiaH?Q#yQwS&Y1@HWqp>xQ69Q3e?ZP0IgJ`z#RS+NN@BJ?7CqEZl!k?Cv zsp5Z2T#+~?J_w6Hvffc2w?pgOj|#zWJ_!GV3S^f75bwsWt@ZWDjSqMoK^rNDe6@2t z>%yEBKhG&cixju55C;l3rUh3L4Z%_V>QB8&GoVi;%Q|5zVr>W2FvyrML3OT6m@EAt znOXsV5`!Sbhknr2h{MC?n1w1jt#Ku*0s>SI1DKI}X$R}t2@`owNM+flTTklFFn~@& zei+GYF%8eGHbR<^IwCaRt$Vx+EI5K{XEn{Yp#VGd=&c{a`fue8NZfe1A*xC?v4KCPQ~$gTD)Y)4k5*W zKXP)y&$w(#U8ew$mn3-#4f+JdY*ra_88z&?x^NP%s~ExZsLHqb0zn$2wi~c;5)FEcRAL(-vXcQz5=3mEv$O7mjRz zp6_7~j`1i7HPbd@hOR%QmU$lAuw3q98PDDJj$;dWtZjS8F2v|uX%yK#*p~Tt^OnNb z&-2@!&OX-%HF|8lap&c)icyUwitvz_RvJlzT*rFgRT5vK!y>t%aSLLr5}td83ut)- zBf1mp(>h4A4Zum(38qJD>cfef5y|qM6fO9T7&0SVj1XFgcoOJ9j2FpwGL~EK-(3Ea z=W}JM!MT1+ese!$3^F$lA?m{)ICbK9>UgB^?Y(k!6aex2sf7VklsKMx&!tKVI94t~ zzC3$PXIOL|O4R0D+^XHBzN&B)l*QgT8ole%J;K;`DTr0CqtDg1!51QGwLrg&@`PfX zh~_tQht?b8n$J6fCUV6I09or7MgzR}qF-kuRfn{Z0@A}<#ER*pyhJn0+~s=OwH@bv z;!M?WSf{~qT(p>d+QIY{xGJ*~*uy!8Hyyb%ktiTK~f0Xk=W} zVz92SG1zkPh?v^sD+JLFeu|EV#0T|4dc~1DRT3Bpos_;I{@=rRtnkxebmN6tDW`u_8GpJGKOI6gM%78 zf;-(<_OltQdTgOITMg)c?~DZDE7}pt$`IZ}HN5=4F~{Y72Ci3ktK=xa!*=VKVYdl~ zKXG~b5?WQW4jTmtYXx@|(J~V-CEU{(D&%z$INVoWApIvT$|V2N2j~VFz5HwcbUxcFbzZv!l^2wdQSLnO`sKvLkV$@%NIKCtD@*x&rIfK`3uRY31N2J# z$ceJ~#;tNCWXgD>v#Bw~`PS=mt!bb6NMhg8@zyH*JQ8>-CKYr9JQ6s@0fgS&gI0YM zbw0#%-$+Wm9ZMJ~MIK*wsQ~sRy?1MpPo1kMBEJ8!b4dX&<@F27C@}Q`14v#yEfvKG znB6>aUiVq8YzYy@&7dnCGti-4THnM$2xulBjdZSH&!98L#x z=vJt}yWwbLVD+Py*1mDd(id%JHRQ3R(E?5^0c(sQ2?&o*@0<*V39uh~rJsRBz?3yM zWabS|yyW-T_iNTk5~AExrvnXs@|&Uuxf)7sxgCXMtrNq6DYT;|){BUDy0tt^R=kdj z{{+KQN%=EoQ_on=6|}Se{jS(X5ergLExhQWG_z1(1_|h^u)bFBVl@O$wCo{8$MFy- z3jIW*3k8es$^WX3%`~e=P7|dOI#5)r_mv^ncm@8zT3PH7NXTG`m?n7q%`|L|V2_pi z3_MK{wh*T=Kk&4CO-3zl1z>*F6RL?a`D)-RO~&dCnpY16`QkGGDe03acm%f2>^*#t z0nFA=O3FDEMo?L@NicRR)6-g@1LjDN1uew3`3X-*9P3!{w{|7LJ>VIMn7EQBf~Nuny;t@!qVSX03lF25hP^)3{NWMQe-Rn9&qXN zk2nPtqia&fkRx*AI|DXc^;mnpBYcnx zrG<6ZSIx|A5nM&m0>1TJXmcloip7qn^93xI4-?f(oQ~Jwp#|#V#u9!q$_4eSS>|Wn z$W|O#Lu~@#?Gi#1w-YPkgNVAN&d#zyH|gMx^}=(adUKDo*f14l^R!J|(ZiA%cjL0b zdg3!Q+>FO8VPiH@c?BWe(k_hSO@CvI=G9Pcnk>n*u$M~qbOz~Bs^1Vka4tbS)$+bVq^Z1vR{+Y~6JmfT$ zeMp0?(x6 zslLh}Qr{ZIT|zt;@|0&M8D9}R^S>%ecEtZ#!{XrXxX;3dPyPOuI_e+XFZ!8)W=;_R z+#CEVPFxy&J#v*Yb4Gqi~6(@?xZS!+vpe(q%-eJy!>=3iGkLAWkB zclVt?V;+t>w_jF=l6`{BJSb4)36bkC&LbPPa+wO*WX^h)G;(N0!wF?uYZlsL%ixuI{C>|q^cGONpxPyc`B#Q zI6RaSJ;ZYLj+VK-Yu(gPS;Sq7A^kO>X6u1>$HAx% zqC&7|W^si^4=?3vC7%ZDes7;|pZ^77X1X~b{6tqOY2=W#CUe4l)X8~0qbe=7nY+WY zjuT;h92Y<&08yDj-{>mou%2! zyrDoN4@%U}l`+w7HV0&J4#&(efAkAKkWsRv`SjT-egxfM#Ai_bE)}xKlXf!z;17@# z5mYfve`xm{BPNb0upMR7QOXzcsT7x{!;4K4Bj!5A&RHtpJ7|9l)8x~yV+iY05cgab z@qN(5bDF%S0&=R;1IoIMosr-}d5$fBe05X;NGP@%|?X_{6}P~YSO)P+l^&TG!KTd4*NnEVI))?>t(qQgyoA2qK6=< zIF@?=2)nPGsV+}Fu`as~T0034ksD>QIHx%Y%iZqymr2%xluo`w#x%=QSblEhF)G#f z5!_+V?#8qB5ZZ^bI3Nyg?OC*&?uA^1H|6E=S~STbh+^pCwdCRWBQj8BipTQXXVRV` z(YUDm4NSS^Ys#=%OFO;O#M`gh!4>+87*SHE7+Y?r1^&#n@?^TqEA2Bpb!Yiz3Ni*A zPq6`P>~lS4!G*~c5IktgQ1(0(TDP2&1Ik!`O}UwBHUF{0+$SyAGMpK^v9_N za8I{j`c`t$mZ>9WQt`|EcjgobcBu138g#h?)*J#9iGYjw(84i_jp56X%5t!*GaEV< zeqKbwmY;s@oxNIGE)L=UvBPqZk4X&OYjWSf^El4w{&H)1dzE%>{B)9`BAf{Oj^&u z+iSpjCwE!b3zb9YDm#t}5nBE#Ff5Hy<9GG`y6!|vqAu?rWwSkCgHN7w_fq)jDR7db zL_4wl{2~SexC(|7?7nOvRX#`)ELmX)lzfiEXa-hFV*~UtW3d2?!U4ye8L?9T#GYvl zKhzHChIpO)c@H><|@I9qr*ju<*aa1*crD9)k8;~t~5VMEgi_L(bX zEnzyTCt-p^wEhhxLW^w=W;b&O=_;BKK{=hj?O07*2yW4uYRo&XFX|hs2ZGm_p!0E& z2lf>**5l7C6FRjc3RV7TTgH_Bi?E!z1v&IxrF(jjqZIUh2XeHw*D(JxX~;g1?rCZR zfH$b(+{%(4fN=ya+9ir`+=cUgEKr;yOk}*Zgm3$__YH((mtli0E^i|xbBCNG!VBV% z@@J(Jf(($JJ;+|dXpn2TthV&CNJ|IvMQzwxYxz{HY>VH0+AttEreJ<%a&=;fO-lt+ zOFZ9xGwoRXD(N9hXe&nP>L@p^15loFP`fT_T z$^F}4K2x0snGcEh%VXUidGN?|RREZAeah~|=`@xK;dW&@V>Tmheb6+g`EhCpT=ZY3 z5(~0h1kCEh_DDH{OQ29gXL=0$H;1lX+*rqxxop20AS?3QAK z!c!w$%;~;`&hyXHcvb#w{ne7v!B6~29=XcAptVl&;eH_|HrHxU*X<#PTZF^yLC;*! zp%Z<*ss+?3N|(Rd6ZB_i^t2P&o1CR152iTivj;z#UWdQGkI273?P_hLUY4SOewW2xDz7mgF7@ zR@{0RE2g4vJhxfmC!1;qX*M8BCF1yt!T>NYKD7aW zxJYJyP5A$yWr7soW{`92J*y*2mj>9ffiO+7YymY zVl<;;0hP#omVt+`vN+2uuCge2T*~~1_rGrlUmeq=DSlp;Bmde*$N zqgdn+Ht)-Inja^}c1S$^W_KJz-_s2=t1J?^Gje)ywK`AlBZe|zx{+P-=_KHBwy|jP zRK?yGe@u2-ojmq{oqV-(O1HFo!zDC%I3xf`I$FkBF4?~( zVTfF?SzLdQ$Yu}_T26gCxO>=nWM`An_^W*gsD$m=fltr&tGfb%8#9?%bEvEEwhb!t zl*6c$)g@faRUWUWG^=dJ#OoXfo&d$M8ltSm;qVw2a`UVbGVq_o+L3Y>bFc%H$x*kUO{Ytf~wA3XyW69h4Ryy ziV%tT_$u2(;Y-UxS&}WJ%Ljc>6&?Y0hyHYG09_N(WFUUX>gR9)4q%lRJ1jB*#~_K; zM6(oPQ&}&#g23VW! z539eVA~spC#3d2WZ{9l@!q)J?k%i=OQ76P}(4r9Q8pwY|@y)&z^_g`g4*SIcU336n z_095wRM&_Z3h^iyp<(#KZE9D_ zc4k`mLQY&D(`LoOQYwcR>#O4J@W)D#bz6zm-_ilTa>;2CNb6rbiUcD19s= zRp1ET13X;dZK-F_@Xa!IkjrJK$%)oMT6R~Z@vKe=PmW^72@3)C*$Fsjxgl2kxfkR- z_M)~I{ny7Kyk4cA>{C+&^+}wL8z?W29Gr>>h{*YoQP_q@>7@-%xwizhO#)38l2>{@ z{UTzzwDc8u;o5i$Rm4=;{hZ_TK>a|gIE)%O;F8fQ>;msPB!s@3OcDNIS|CSm<$Un)0qBpxg zTfnNs4o9~ifSahrQw_7*R7Ja-*E(VB^~p`1%`wdP-#oJ2{Z(+3QndIq1&JP`M73g% zI#H*!HL70D#a9}lKL1JjrWdS}Fo6GZlMMz1l+U8S4=#pBEgXWQ?9C8cTBCRFEec0? z`2X>giW!fNzoz6zCjlx%KiU+!Lqz!oOBC>JnQ87aH! z^_o--149NZ71R&LeSc4Tg@7>;9Z4uxc=>MU_sLf`Lu_!|w9Q{}Me%c9_Fxcg+DY+4 zbFC(VwNEp?Iv)}M2h3N>NJOj@yCl|5-_OT3q!A~(0Xx8#uUA&CTYrQR`aM1xpngoN zEizhY-z}4#r8W-A{lMPilzS@+{9N8Pgh2`=?&d+{M-=;D68oHp8z%u7ogwfb{WtU@=0c4)`9a%g(apY}OqTykMiyiw-m4 zq30=JWM;^{%L~1w;3a1CFsd}I1_6!aK0ZqqwrpphCAh4oCdFL)2ja`0TP=yTDD*DX z8GB(2R2y2ESwSc9z@h+UC|$2t(ibWDxrYZTp2SE0+a5etXIdG^^7bU*3;~Rqgo5?Q z&Ow{n5w1kKCFy7kQtr@TNsJQC_)>$sQ?Z6cn>+%kBiYwBuHPU52!WChHy8l!GN26! zP_g`;kK})YyqaxO1wllf#1dP$_=(&9v3-NC^ffFD(!VD6T%D-(XzA3=IFZ%h5aLE} zQ$yLE9`GL=PD7xLV%B7ID~@R{0iT21A{l1No*-2`%U0uW`hDh8^MUk9J3}BO+$N9; zZRzg10&GONfKoh6J+k}*Nm=u?n6*~;SoM;~nWx{yjLk6bFu%p96%_9L##bb}SBh^p zs7+U9YC|yfblQNeuXjny=+!$fBE7%yp8j2rZrG-0t%Q=5X_{ccPyn|*>87h;y-Wr_vXBU>1ji{Kls}c+PSb)Euk+;=8g=86oStNCKlSj3 zvm@5-;G<2apN0Y)8)|OxN}0w#)YQOM@vy|L6i&y0-C2Lrdf-r2y^98inu+hQ3y5_hst&}A0haK9!y9vlA0Ad?`($jhYG5UVo;TQ%M#5_FFYyvloKA=_e0~vVvU(h z!-s+W1?#Lem^!nXr&AEAMP>QGxHybgLsnyM`7!h*Zof-DJv`k2q`%?har2F1rb{N3 zvR2ktm0qGVO=|8c#V|cA?9hlpMxDjFrs#4h=1niYa2AIe?t!`IyXC#u)Bs%A!+fX~ zdlT6=Hrg>QUTbI6P5OBDHM9(H$4FHl_=Fm%Qd$AH(T6xEkBT!EJTePeE7ncuf-T1* zE6+L<^Y)x+*aqiJ*(TitvQ>3-u+wDo=?x|dw`{Z&((*U>&4PB^ImU;0=wzc;N_gZ7 z-o8Rk^!!`k+(eXU-ok&vfK-C95-c}6;epwrBg6{*P1OWd!*g=FLZVY_mf!XzPK&T+ zco&K;k&`m8sI26SX8Kiv0Y3)HXmg+uJ+qFqmZvfPkWAE;3o^Q-oBiUc7NsSP2=H$x>i!0Xhzo2pp7b>2aY&031;4 z=vn3LG3Q3I@W+LoSHpFGM;H1jXUpsspY?RHljQ3Gu9fbq@LDoD6L!gSPJR)W1A|g- zN1>+}11*|<>Z5&h3~#=tyAi=FZ=3Sj`}%tPwO=HEHj73c=-{YWPcX=0nm>yB6NP*Y z>{DZG5u6h@nB*x8t#smTCdx!m+VD_D6sd{JwUB#5f1L_h+vPevq&hjXl`S;N?a~!) zby@mXAh%T7b@q5(UdEAWihNTSXda)y=zB7vR)Lek+3tK)dpm#n`ay}(o1+?Q(wh{R-?rF?+D>GUzc)wwm*o;ZXL%he z6u@3xvd!nmTS;1eCRO`uFrV5XNj8ovQE{Ym>woFv*MiStv+XDm9H+)dhVBgd#4uvJ zWs0Ta8}DU&4_mVU(c)0lm{l!3JZ9s?bt{gwT;x0o`dJFge0&Om$D_3_A@9#&xi2xi z0_e*an3&tar`@|5upI$GH2GaI{0G`*cIYZenVd*El{O@U69z-4RIzy4?NP7d*Q=bBib0sKV(3ww2P=KKeT;o+h zxg6^sNKw+zH$yK};TOmgiW1&RbP3;2FgkR)<2AI^4vgW)& z8%+yk+lXKcCLfk3S>Q7>-r2O)6!v2d{%!Ij6onQ>JLqjQgt`FKsuDR?siWJN_&Khn93Sq;LPlE=K!tm%7R)l=dr?^e{-b$pc2r9T@RvRbM` zrD>^=NdD%Uz;?;a5YuLZ_V3WZoImUD?rZsB4 z{(DMU>ErdWjsg?gA8H2#6C5oy`)y+)$!u~RpSAd}287&amb4Q2=V|ZJ4(^vC^=k^P zVzr6L7O?q^KhDSDN?t&6+OfW5XB-MNIb0?OckiknBFPn=T$fFMG4VYpCY2m;+%h}77k%IWdDz$g8L5RYqY-sD{=`}ll1^a{ zVXhMV60sLSQ*8uNC)vk6v~Q7_LdFa_!x(N7aSc^l<#THTKo47F4wO~wp_4u+)V&%2 zVds1H+ipKTJuc65AxUPb*a}vM`M}lhG}m^z6Jp^=L3vy3I4hP8Y(Rlci?6(Ss$nMT zMX^F(0%;Rv{Gd%Qj!IZ|olqwS2Wuj2Dzx4Z`~7zp56)BY21g&tC=T^%M9;0=7zFba zu&Fn({3v#7!8&&33&DyWX5h!{jY-uo;#D=G)`+uE5hyb;pGF5^l%~>2#}Ctr(0?yQ z={t0@*a`=;6H-R{7Ddnh6sEA*$gK(?2(2nKoLT2#AwVqX?Dt+10ntz=mI@cQlL2RzO=5Ph{A$BG2e3lo{5H{|z~%)Fs? z5PFT?B>hiB_|A`#oK+!M*<=xpo2({!vBkjK<73j1yAsg)jh%@vB+68`#cK&mr+Vr> zBaI>x|2bmJDi^#H^0=NJ_*Y>X1&#!P?oDcxaNx^xg!V}4aq&M_Djna z?YaLcZ2$*E5CHQm<2gEwne}h6g)6Ui$?yODKho+K88HF>IgemN@TkLb+EmmFIsZ*eaof|seGxq&&y-w?r=P;~TT z*yaMSKK>Cb<#a3j9yoDE%m<2p9eF+ipkN`7ZYP$cAHokx)3XpHC2T(JImi7^&ekc< z?9F!`Xt$N*maHm1JbKZ*W!3er%T&AL*o7{>1L(DyASy2KI9|;8C`Pyz!7krg`7AF!S~vh{ z`%1h74(JGzRO1=-yP02!67REE9~0vm80&aiZaXBx!@ z-dyj}(z|x4?}q)Imy1iTd2VaZFl83+;O6jtG3b#QReogiV>^r`0PjujTN-~qZGTRG zZ=X5SH9;48@JV4y0l65tHEf&vs$rq`V&eroJ%lfmg1`6Lz`Wq66^o{OQrk;f(qjO- zvin)f)DZ7uTcD27ha*##=!Y#(P5hWy=Js?CPA0-~e{%CuF_)!*RYnO^OXgpj+DuVA z)0OtmW`)SIh}L-f7e^>&G06MvuD<@Y{Q~l{@mFB`y>8LvJpn_vLLXQ*zZ!WhGOT1J zrN)~{e6S6TwMfF4jhPaHB)%b^ihW)T`VEcesOdub>r}+F!G2ZkOwU=J1vHms1L7L9@VHJINHo3$l_;D_Fj>;(0d z3{DXuLfMAUl6dibU)P%4=3GLP)hPh%d3@{(giWkJ$319}P+ROzBK!+c;)5cidXkQh)5+IyZei)0wYScNG zu3K2=Q&VD6G6n4fnYYR`ekXZzgb&+9cOPiBa78I4wQ>H zsoq^b-R$BrA0L*(#JaGwa*UYH^2JH|i}2;G9LkVJ=fN1FZN7Rd=Z09QPk)cdir_U{ zD5Ks`qPI2p;AJxgyXjfyf*Eh_wVQ={JLkv($mT*kf7%w95p@XqIx_jkV;pa{Pd6<( z4T(PSVx@;rkZk3r6Zg_~cFfX`e)=vbv4|eNXS|Aa2zSVS93U5P%X1%!24Qw_mmw9q z?nD`l>ml5A)ELW?Mmw9vAe~^gcfUr|jNcJv-ej-2A8C@tGYnh6mntD7<5#~~2`VTt zjL_S?meVv7U*Na+oI|#uZOo5p#nib7wh$l}F1bEZUyJ?Kto*5mezVf*%VRZW2W z_!qbWz$(P+EYF$xIG`^`g;8U+(U_z~60~Bf%u&_F3auKe%A|{cFJ^7if(wWnlDpTr zeA&1XC~N!=Jp;PPA^-o2T);evhVk{p48PBnz_@<$E%oy$h|)JX&yD(f<=OTlSw=lH z_t2^v^n@Od7zU|}lKcym#Q;EV|Cs9wTJ((8IWGJ=^yA1j!N(a+{V)Daw2E^HD4l;F z0!}j_FyKQ_FeTYM_3%BQV&D6}ia|LnLIy5`*Otgw>rxbC;tjr>LUt(8gGC5kc`f{> zkl%iRGL{LYx|;h9A$v0nOffQSBeBup34cK4NX2cdVU>k zKW#OjWGiHvfBLu$*97&|-bDXbxnv1be?!6g6-PlX7i+D+Bi+akXgRl;Y!TKcV_Z<* zX-`}XV$d7ZhjbhPT)B?hAj@hI3BEyD;SQ|hNcHu{!t`G%3{sb*d$}m^+{)~S%lJno zZ$mk{gmZYZyQ)&N1@#fBi>Zm$!<0&2nGN+2r@YkV>C1(4e#`gvyfm$2XIPzMb0-PS zZL(r#lQI{FC#aWP2{i0i$oRbDSx9IdJjWY1et$6i8RrmwfwYzmi@{rL%bd^3QKC54 zf3rY*HHdl)6WBr}-RxSo`5_`QLX-u(B`)l+)PQIruKeG^y_~?7<~}`4)+tDF1hk^K z{}!S|o$NgYPCn(od6&;a^%R~wmI^Xx*70AeZ;!PgIr%%l5dnlqA})spO6rVgGXA}1 zJCn1UZvq`{vL+o6`b5F{%rbWcW9F|>BZ_du*S}V>3cJCOE(+y*9PBNgd`J8#^|&yg zaCkd9d-+%GPmcdD?#n=TM?H>8m0TtU370=?2z@Rc3B#%pMakNT(T3p)RU#JY!h5f$ z1L22PW}*f}`J204d~m)+7_D$nLj&{M;-<_m;L3^w6RTK70p6P zG?^DjqyL3WA+j_vYf5;zCjMH`ME(3uACk^tlNN=ZVZIdInkE_<1+4Kmh@0mc&I=Z| z(@m9>orEA(#(Bq+?D_lHo*xwAA;g>`X~TfZ2XQhI3DFupQrX;Q*K}!o(Nr->%2FG| z6Zmz$QEI~g_%|U^2Il@mlnS;qY6I3x!0qg9Zl+CxNdIj@9!-f`2u-^}t1=|y`Zq3Q z1(VAS^j|EeGnB#uWGf%86IP+!t-10atPJW6r8=cE(aiS!Oyq2AUX&d!P^Voor8zdt*qyWdNrOCX= z3mqKSf_8i@#}%_*Nl^qTu&adtCtms@qb%pYo+|jlwhW?yfKLFO|=n|5) z>Hxu^wv8u6^M526Z7G4?yo`m>F^c<^@hkym->Ymkl`0w~no!9@99OyNcs) ztE}w<$uefw>dOW>q9-6~l=q}wrsrWt$w1fi!pi+jD_7}+^t3Yba6`3(R`|5x(!~|j zFk71&^EbVSk0n-USTdDop+tp5O(m`BZL}sA?Y)cHKh(0AfTfcoG|2AkSMl!K=51g7 zRMk(5$UUO^mH##X>uo2Iwg#xi0Tcx)Rvo}&F4zWoW;L>b{fVDm(JL!)kQsu7^{M4H z7F!wgCEgRVbv=f;&?*}?6)5RJ?h*H?ocIv_BO9_IaZT2iV!)PbfIXr@rxj3;5mVlS zu>=!NOpR@hE-1FhsF_)+>)l_=z=R2M0DNtvtKcYS*BP(2YdIcs?#V=DE=dcbZhOt9aSpC8=jz(Hlgy4U-nZ@Eg~D}$pp?=jC;}Jg5mVwp5-3AqSrAA%o zuQ~bU3l}WC{3P~+3|RJ`v$e-*iSvFTMr8ivwJ~gZBKWK%nc2%WxSzcKJl#cOOWAd# z$sRamxP$v-+{pt-7bWtyq4~^r**N;ulKx#|Kt{Ro9kVoRU z60>_H-p^)o^W^YQh|F%IJIJg8(mv#1st}H;%cg@gTsWYE$H6NQntWZ>o|>U*Cr{~- z{Dsoqv>AD05H`QezCG3JZ=NJCBX!7pym(qK7WiEKF_BkU0z7U`)}sVqBPAMTv>FWf zYg{nEckWo$9m3ydltO`+`ICnLK89&YbcR*{b<{A!;LY)>8-4tJXzT|fgomld@+FEm%6J5v=CZPgtWvCfh2`EO z4=I&VmI;m{R|a61O3-E(rPBj`ntZK-`@xN5b&P(^OeAZlk3N!3AAa ziCH=iThx;e@XX6u*qyq52i!!mmQuWVc(Drf%<<@YFy9bZ;jBK}Go*{$3ltpJ7z~uI60lY1PFW`mFO|lh zsEW3Yx^eB+bH(XLu3QtP?VsApds#BWu$)#4=$%G(T^H}5&vY7uT6gsVjz;YQm9IVn z^LBhE%d+L`#|T!{^8hH}82!*b{g1ZsXZ%ce)K< z9I_3N=P47ZA36yI*t$`*eyslMve?M{gXS#DWW$s(xY#w#c1TiIG}&hvDN_XnDWE2M z6Dl;29rB}&h`ZQQ{Ty3$484T|9-d-~z0s#TrC!?)U)W(V? zEb->;xZdKyERtpsA9qL+5TE$2XILtu^{CRDnNS&=tk!~LkduYRpDsm3PO*N#WW_!RUa_*8` zbY~HBD>9PjQ81<}#~ap;B$T^<~inVmg_!-x|>}&6jEPoMT3tLDT=nR-%k4f{ug=U?9|Us>XRhycuAZu@OlNy%WU&To6p3wOg18gE6f=aXQ7nAr$uA)^+#N0@k&Mu4 zR%9KHo}SuGIiAfrR&%`hEbgB;VL$0i7kfSk&LZz3of@v!58e5zp#YwE+LPxF?u8*T zd?m7R0%Vs({ARSg0SjddeGC3Wkw3L-=5s;XFo0or=bb@xNM*0Lqmh5;(pw;guju%N z;j9}9R(CG0 zNjuiUjn|6ZSFT=uPo4tBHOO~h>l}@Bxpwqc0rYgD-7v6RW2l9$4_%j9d)K!v1eUJ% zaASvCe=IG~)?Z+g?8pCD=UL3{kjzH;p9FMJZ}k5qAm~IMmf?FEhtD4?W|7G6rv|Om z7is}QLH;mOs1VHau4HQqq;F0Le%(nktzhe*S{->kqC!uTY&o&#Klf%iVDaK_nrKaa zVuWS~3=Lo6F>HF+mhciHsK1_a|3jm_)@Yl1&2W64lw#|RKC*7LZ8^5={%pCNT0;2k z!qryaW>ClM|%3p*LV&?9dZhF6D2zA zz(JS=o9+hsF%-#fVkCb~1S8WdA}2zvsK7*I2mF1;+OEaG{ID-R@J{=1!vwIraL;Ip zqP5(euOwaKZ7bQO8FjJPqwSl@B9r!?rEXlI-MXM=Ki}(G3l8dXLhz3;;!zUlxsnGu zwPUBC70`9}B@9jPC%ZZOQ}&plsfhcwRxVuska#|b@^9q0&dwYj z*KdX_3ilFQgIxI8PW3u1%iiF;Q2J+W-}<-)vi>L@_x*D-yaQfPRdOu*xq>p*GQtb9 z|KS!q)s+S(>}TzNo-8|G4e=NWgik(p~|JNEWhznEFRU6p0$CJ4t!_aC>mUXF*Nm%pD(|C zh}dBVhZ3fNpFkQ;UU=^#*Fn2q1;p$CslkDE{m=;z1K`K zLnGcV*Cguc^&Twg;ZYMWDdU&ci%?l;n#`_30cya;s2!Ffr^+s#q9$T@U6t9tO62YS z`GKYo(^+!kgSmE*S}YJCuSf(dfSF0VfpkQ{A{*ezBJ0+UUlm3z9E;i-f(D>1!27q= zUnUlpXZc-Zq8xvb^}-`RhP9WKt%-eql0`)!d0Uxm%hLHiseI#?6Tc`6r?#NG=*EHN z#ce+YQUO^@R89FN%#MlV;od$Z_hp6wg0=I~7b2o0N;30Qrt!;7?oWIzU{CCUKNmHz z0X|s~_$(Bi|%dVT*Wb%BhwDy91tj0d%70{bq z9!>WtpG)MgmG&dUC->)nav6?DJ7}cPPt!gYUCO|o4X<&J)`b4z*YZ{sQdLs5QlT+b zw#k~WWgXis0OYFGw}!kzV6M9yrX(5GZO@wRN7uB>!$o}F68 zW_lB`li1S=S8r!NMa*2)c>{F_^{%rG1eh(ZQ_u z&hdK>KO^_Ms7tLFpU89hz2X1PbiBa-f2O-5Y*geoPIdl$rB~hZqh~0Z3nS@QfJsnL z78FtUe$^nzEIlHg&@Z)->1lOg?M1abIF3Io3$$?>E|WG5jhG93_qReh@uhhBJBtfm zx<Er6HVv)b3{kLjJ}hj#41ulGO5=NI6{|GF85J>u`!*%Viai{0oGZl{C->PX+GL>=(Q$}xK* z^@idOaj~8dYdN`b@uV-{pGF?{G;bB1@f1!m-kee8(#f6DY~oIB19~b^criEEnr_m= zPfva+h?*01cj~4XOQu>jD^BnoP{qA)s|9f8G%9IGAt0pVe@E9(`uGBJsbO|~Y`P%} za2mf#5`b?Un3mxz7hfat^eEvMy5?Z7eU%oRhz$_J=1UXx9Qy4s&-cB007pNcne!=f z;3oo##9n`C)oSPJeZW>0*40^`)k;pPvnD>p)N)5GJhfFY1kW@hewr>1YhQsW;Bx}O9^Ht-Zr4*`G z=4tej^->8oLw$UcH1!N(sZ5K+J1(wk6)QDg@c;^qOXo(dMu?A5`!R}FAwV*)K>XYj zR+qwJdF_9}vr=?jrrcI=WOgb>`5Ef zqwt8~ARU^AgAer!4&0jd2&^1kN)TaPwzCfFA+VoLneF54d8bL50`*f3u=Ga`GE9u0 zV9Ij_JOS- z^b5&M6=fVyw29(=^gg-{-i&c)y_!Fp!k92me%)sBBNaTYD?`j-`K&1XH@5IMB@z=e z(*%o`1oF#jQ{pkp59%jn;AR~*$f4DT*%Gq$k?UO$l|BzRQ82w-n6km=h2TD#?a@ea zm?h}NumH~*k&x@@Yl(1?*oh)v3k>dx3#P9T%5gqD=$TGJ>a0`R*87%tNaq9cN<5f@ zktFOy88_KuMm;R@FIw&#UMossmEu&Px67P}@wH{X%<)T6vpT_Ww#u%LQ51+S>f#FJ zed!3=RJ~)mF^KU2;(y6*G?wf{%WpznyM&$OSwJ#a36Z7t;{EWx^A+Yw?g?W1mR+@J z?Z^v6YC%;;uy>6`v4-5Y&>!k>R$tbn%`V+Nk-3qPW(_?R0wt*WAC6wYR6hUXYh zr2_EP1|6NM(8slh$6k*Hyq?Vp)^KZ3d zz|(=CHq|RV1me)BsSXu^H}cVM(v@($VhoPFEk@(}F5q+jd|u-yk^aL$&znYfW(Y}k zh>Fn>Jf=I?l9`_Q8ZHL?T!J-rW8K2Tf^u;DGg_XCVL?avx7}}l@cR9IOuhzy^fPXd z{BrtVi~deoZQ6nHSz|902+1`{M_G&w96qDmrx ziIM3qwu0aa2O|zAV=8P2pdmXhqU4WmBq60cGxNq1o)Q(bSCFv>f9VA2EERXjoMgb- z#Xs88h8Z!|JwHK*esAnT+4{LbnP^@HjQq)6+{gqZgrnqrb2vh=P*+cir?~=_@!lPz zr`{6DR)KoL`f@HDZ>W?nb1V>&tf9uXRR&A&Ip3}frHjkjKT8GLP<1gE&v}|MojkD~ z86IHOYxJdNI6*0+BILpXS@kw*7>YBVvm+rg6=j+u^@Pk0C&$MApOy1~3aHD`t!ilj zRI$WMst8i2YNkT>G57pkpmNP|5l&MtHIZ-je$*t+w7mZpteL^`|1X_3QRj(0eh8mpBUi2{wHdV@q`%oi3`NCC9&2V2ygc(cEBvtge2vi8;ymK)_IH zJ%hN}RHARKRc5y#u)XC|pF`gk7u+Iubw|h*3%+w9Eh`|k!>6yx9y%-=s9N^TOk7koouYo&CO%Bi`? zL9KkVTl10=OC^a~KOr?hU6uQXp=%WW-kDxRlUYN;45Pp=L*NXFBoy8e8rYd-U zPjY4N1}KWtzIvKFh7av?%EnbemP7vw`z_XcqD5afdniVKA0o;gq)Dkeu1n!KQqGAU zr<_E(en~o(mwAA9z#GHN?Bbu{$sd6Wsbh^%zNp*z9c62b^bQL+%BlD5kv#UNi@o@K zvFLb&>(DN4?HV3BIr9MBB^O!gI5C$1zSclup$7;0Cmrmx;Vd(sFpG&B?&-_Gq2SE~ z!w6G8-32u3Z>?*Ua)XSh%JahCv*I&Qa;`7NdeQ3qD1;>&e?Se2GN?&fk?2Z%iRrLt zeVYY(JxYL&?#4A$I&A6-Ke++6gr7_2G4YJc%~3F$=3o_bDL zQ)Tz_k|*QBMfX3$_ej)eBnYJdMAEo_9K;~6k^wb`r8Mbs8I25v{HDIp_ei_5H18Zr`zHFy(u=bpGlE~XzwrF!+z-QOMBK0_C<|7bxfD0 z59VPVLcV141pLLt!Ttcs#})x}Yx5XDhhTyQ(y&T2EDKE&7Mo9`a8;p|G1k$&dn7Nv zk?}F?pE;+k_jT$SQ;8N_Lwtu?VL65BtZG8L?;7a#8_j~Tlt5FSMjEL!^Bm{4AL(iP zH??&Q^>MDwjq`+aXgyyHy{Tz1D@Ot{s4wE1T0(7V@Eftp{eMk4YMdaV&_aNSHposJ zsrOIsQ*N5p4hiBX9GlEw^%KbHJ3iIn|=%NqQ<5x3L`KccvQ~$4EDDn8-WUOe=AR=E- zu|-}_N~&mGhCS0Yw0Y;n6Ek_mtnG^`EBXRC)>Ly79e|;p7yqpnCHYH{9Gil@`C5J+ z?-z3L1Or?+(mhyoxuYlr8u6}dfY)o{nlEC;N!uaSq#1MWb&bUWHUTLBeIWh~qKXFN zk^uSOQFx+9f(V54(O zox$8r15Pi-v8NeENqd^Emfr8juLM{j&r^Hre{NLlPv?}M0LWG||( z-gdZ`1+z!H)kFR34fxGT=j{!zHBb%&BvP>>L4hlKP|hM_MeP}3+OK#%u{$t>uq@-M zp0ZLZ&zA9tWCv0lOVci9URs*0%@|fMrry>}kX^ym%r!wDaj81hd(C0q&uK_nc;lt8 zkKWO|81SNz!Wz*G819jG+h6@Vo4qG4CeJy&f4@#ja29`=8wK(8L?FjRqhRMV!59Rg z3@^L?0F{`3BSQZ3ov0>nPJT%&YD6@=26em4ftS-6nTg40!8wr}5uclrvz2GtjeYTS zu82j3n<$a>10zjt#cjrLS@SsScu9$YIvMFVRYeZ>EZ5sb_tVDtQRh>NQRI8oriI#s zjZxG%jDdN^`u-ImCoK7Q_%9R6cBF#VwCXy0e zKC%9eVV%~Zxsy7K$59a<4DJ&B=P?=Rn8koGVdc@YC>yXg%i>>%!FtL8S5-;e9Bh2W zkZJ!cGk*kE21~2bs6>8Oc3fmn)sg(g*2ou1`HZZx%UQ93>rb;urP)k2RCmeAyKpYVNXJcg5q%~IV{#z&agAY0OR`Rm>{UBq<^B8hdx>Qej(4;! zjLvocGF4nnn9xstNrSTueG60uKB+dd;n3wLi8!hTvoZvAL@Gx%6#P9YdvrYXM;Ko9 z4(Pc415>0#;SCpDnD;T0h5+KZ<%r`^-09?=U-3nY75r5jYx}3+y8i-v2o-kKB&=3~ z>4W>vG#-oc^zYOz2vu*^*ptdrAOFazL0s?j$C>TN1nxmcm4#HKYd&$ZEBap&320(L z+bj;^jCWUe0c#XC5Jkjpjf1o+bbX24B@eZ4jIGNij$+72;*9aVSBc@7y5zCaCye(g zCJ?zSDPVbmm%?*Gze8;)NFGAtCyV!(l|`>3EGg9dEC3fTsU=4LE>4&(!+PXPRxq(n zB^PZnQ?>f%vv0;M1*a004YAlfy=dz=Y`MnI&gZ!lRrXP9!lLAp*Ekfw8YyZKp#xK% z#bGnpX1s6@J3GLZh{MCTs5Y1^2lYe#qYIB$c9)sku~y#md)-jLv937-I)Q_pO+ z7<@gj%Nh!BM!a)!)B_$;w1B2VL^Qp1nYY7R;8qsfR>HZ+j2Mr8%}4( zw1cf1CUseQJx?njEvFNTzxZHfySK}ZCz#^9*rRL7V0IjyQ1_RxvYO>kqoeJ2JRGW3 zg3saD;mPp!@4-ttMnzj94EBNEnP*5grDtgc|JGVqaSXm_)DEeLOUYrZT3Sc>Hqmqr z!Wg@rM}5Cu|9Z~_r-2=Tla?x)KDL=&yd!a_-E?X%rx^*$47B%V>xy=7L~SvUD?L0H z1iB5d3n}nYA|i9#l2b`m?P8Ujx3Cp%^f}FL&LG6>oHUxsTYh;+XL(Izf%-LA4U2_nk74QcJ zPcW^O5Ohk|Io4D`7$hdwTqy$13Lzwg2$y-7dd!k-yxcLt%U)brAb={LM9sn_d%Jwk=~?Q!v+1r zpvq7Uv|_S3P-roYqO8^%tGn(b$J#SXvM;^s?fkdQzIx^|}y!LDLg6^YFkBuON%`SK(!GdZvc02qcvMu=Hd~ zlnR$y>GaPLviNHy7P7nf!o=97=$h}roX_2WEjPEe;2mWI$dCJm=u5nGr* ztV=0N=d-eRC6OA<3V^k7VOh3$u2n>pUmYXkH<nS#aCf`X!DU@RZec{$q4jMZ=jM%M* z$I3m;&9cKA(W@EU!m^N#4XI$C#VJyW9GpYqYA!x%aO2j{%^`}EuYDE=s8%o3#crjx z%`RM`kAk^SDXeiZs~TWjh6=qvKN*=JTT_}i23o`{o-x?vTf1%isppPCBo(XyxH~wd z*_V>0;};VvKmqY(u+;%X)awdKST`md;KcXz{qSw8@ek!Q%3-!n3-(5((}EU;8y-` z#%qelu@dJm8K}sNYQ5DcRMHWH^MdB-6}JaT;|`b(MYeC%_whQp5Bv@=_&XY5uiM)| zMel>M3@1p1qbFg$^~i}gxiGLwvc3LI6!)%GD?nV|81p1oB`+jm=N zpXbp4>YApKWQTnnUks=UQ0p3GZ9zfRR0LlsjA7_mfXTGwCal9P0uwrB<)|zkBVR*i@f3HCA-fi{{Yl|%@ zx;miGtO`DHmN+C;XjoIYXj@a~>9A=W^gm)$k;+m#P_+EP3t6GY6@}MJO$}cl?xH;movO`G7cm!rKrwfL4bS><0vF~du_#bb$yf)-amxPXGxlz4kR+q7Dur<@&d zM5MgyG`#V8p5mYU_v!6Z_SiJ=dJ=ha#{l{KN`qGZS@s+j#S~%Ou@LjE(kiK-FWsi< z=0EIc^Djp;R}7+?y1k=^J;E{5DFBOue0#&Fic17klVKi4_60MI<>UBDd6d%2CxvSQ z1x)PnU?pJf>XPay%sFO79`l=)+g4DGMN3@?sn7JO7lI!tMF?D*pQ-PynvV`kYOXm% z_=Cl!TpYt4;b+l(<~$4;{t1|~ST^4OjT_ki8#mv<|Hz)qntHwGHoOXerQ&Nr4x&Ij z)Y*8b*fAT8*h1j^(1YSZ@4PQ-pO_vabL7buDjQ06R9l;N@7jI+WU%+XjU%}fnXhba z?OD{~V+fTRiV;06y%4`n{R{Ff`fu0y*u;RhK$=J4pL}m&p(poQH5y< z>XnB-j~mk9s-OVf;ly$%7OZHu#4VQ9JXeYPDIz&{g*k7(2VL!-pQL$z$Q@GPH|$Ee zPquvP+Q75rPiT!ip^XGco9WiRjt-yKPZ0E! zQ3iZm@yN`HaYV-tdQm+KWPj{x0qhGZxr9i65E&Amqny!v3{bKFC7Y0oR5t4p)p#Bz z?0m;tkX=oq)bWS|mXHmGU`}`U-9STV2HT+_EF@NeXQP^Yx@gkOA)9>Wu~q_2+-bBl zHb^zLZ>7VO!fQmxtc?txz>Q*(Cu!Kgco$Kt252sA)Kr!V7WOflEVGc$w=?1|8XkhW zn46KH)KHqEsS2rtMMX8fayeA)Bdydnvqkjp_i98gP$-X#H=f9qDUul@_>3x=^M8;; z*EmZ627O*~%<0@+#QtgrNgWgh!!ad%yp-DU&@Dl4{hF*Pv@?lzKUcb%_vHE!{eTkft1^I2iyInz-{J+Xnc>}o@i zs{iNq=z@;a=I_sx_c*Vm=q)lE;f*b?w|hj22+21^x%6p=SDlN3IeD06V(`&x`y`qY z)mh+!m68_4VVz)(-;2d=jb$0K&%As|Ksgp}Lcb%}_Tl1rcY z`QD`JbH3cS;(`%_=0IFfdhzrmN*ak>nP&RC$pZ~6zK8@QiQwF5z{DD9w+@ivPrngE z%*Y&V$Fs^zGX%5zajgLCr3dOl$nUyAmOmSU`Mo=A*=GevU;_Ly z7Ifq%O0tl}qRVP@uKbV_62-jhzQQNL3mQ5~#ZR?PR35jc>&zoiL*nR+t9{uD zJ%R~C$aes7(cH>q5iM!Zw|_pYZL-wtg6NA0ZzaLbW~OrvJQv)aZQb&~yS8jl(U1v- z7giuPvNv)oF8!L1oY^H~_aZRmh~G17%b07J$xFo|10{Udqin7RFPZK0p#b$f7r6Ai zfp`{1p^R_;U7ZTUAGgM(yt~sC@f~6lJTKktG#qvPumgU$1{|<#6}<#tJZ-xRNS=10 z!6qD64prXqwTnosy>Z!~@(wtg6ZYdyxE)_Q7)D9kT<*1q>`;HDf zp>!X0?XsEjr^<$Wp(Ck&<^R!ij?s~}P1o*dCZ5=~or%qfZ5tC?6HIK|wr$%J+qT_b z-_N_g-~F%Gwa%*Ab=2Oii6b?ZKBiBaaeOcnjH#i#(6G6D%j ze(j*Ez-jF&HSnnT)4ON0{lp%K3<3PUmwjN9n1$FhG9#H z;xSQu6*uBUF+8Tne=Y!NF%+Dr*wM|ydsKw8IQe~yJcCOtZk7J@H=OdO|FBy<9TUkw zt(YtrMrzAeR6y{1p^YbeQ|n+@)RrCWvMlLU-#GorGp8giO;!hMl-(kNzL1t4;q(l@bh$BGr4E@quejGFNi{xuWu31Gtkj#U+N zHp#@+&8G{(0(G8xR^|m`wffCP??|&M*|f?- z;f5WK5%3v=ijPR;p=8sh$FZSAlG??zTR82kPGD`G&=ceyK3#KgUq~dL-L0t_{g`)-&Itcl9%Yh%AXQ1N4W`MwrpOVcpx>gVX|+p_%iIz!Zhvx67B zD$v`=NsM1;c}H!C1ZUceA>0qhVc#PQiEmIkvEbqjBbPR7mA|uRbY7`rCp3uP^Vz)) zEdK}F#7y&_vQktucnQ1&KavpO}@ja`T&_^0| zRf5^rl4q)CK;@K(Fhyl3IS*y-OEDhiq`r0w?D@0nNRd~bHbt#g?1!XUrzPCxsiGC& z+-U;GF&DerVPmNKLchbmyKCFuExAC;zm*QuRyd?$mvcj(VOt93B&&>hXDwl#z|a+% zA6oM>>HLwS2((=mn;x~`#%`17K@08^w=E*Ky(*JMOLmB#?YjzL#-@mFk`nAVfZ+H4*xr1m5+-X3o*AZ6VX}SBp zs~V0pW@9@)`)aNBY2);%l>3BD0&x2P$8Z`5Nn91$ zRgd#4eVSy-cxSN(^(4q}>I8&|ME6>LQ_c@Dlx;STiR0huf0xML(G66s(IJX%mn(&P z_t&~4ExC%8s@I7hQHIP8zryQawxVI_dmWsa4&I*E!O1PGJ>rOmI!~J0 zV*a^^bKPn;2|fTt=-o+56mtQGOHvWEL3mq4U%{`wBm!il1umT(SXsrqW$^c&yRVQH zAUX<{C(GP;Qtj)Jn{T-!x!vw9bqx2ZRQgoJEUvRk13hePHLZ9*r}d+jGX*$BckT*t z++VDM-{@hrsTL7&Ja_*U53D7VQ7nD#gt?Shuk>*z#dxGJS+Ok6bRKrT1e6;oMICk= z<;eYqJ^xFw<6Q$GC_r51!R$ABrT(cxt(+fF_Na+8)u;2+8rSjLEsu(MuG zawa*oVHxpQH2ej+y0nrw4PhVCB9Fxntj3q372|?N3okkj)mC2r`?C7PC%d95%T+yw z4;L{t)if?*F=KqO_rE_@xPxyE`s|A>Hi;W-E{n%&1tfJI^V5l7ZFwugWaLeTQ_4ka zf%);KD65fpZI4E1kN4Kq8oj@2oi3%oGudKc>d<|ERa532JSiBPvD*9-mC_Oa2)V?9 zov=8xkJwqPgRUlyy!yJj9&C~6TdvTNj~LkQX~UX<*EewG=&O9x4&S_#X7bEET|JpC z85bw89^gVLBKeazlprVjkd2W`=t^PYrej$Z${p^oVMkUpI@$|+I>Y(2>ZS!ZM85{l z_m07%k=2d?>IoE28Gc6HvB(GBL)Vr+Wp$Yrg4~yx=sF*e=MbU1mfmh%g zcBMHLijbYvu+>IRe$g9r-fnV{YG(C!S+B(L@)~ z1ZIZTuEbU77D!&IOQFuN8%9_H?C#Ah7$kvTz_nTn-trppz|>Ld!hsxqRS${DAAdaI z&GDMRL`t_eH5UL2YH<&j&?Jxgp%=cFvqCB15!cNdPrDyq4pjF6-^{4Pz7Tu<(U7Ah zx*95}q<4#0CyaikV=~AQt|1q!ZD(!!9LN1c8aPl}wi#h4b2w#N4kV~|a))dp5xWqu zk?e{inbcA%1QsRxcw?8jU5cIrBFAV16mDN@E$T~&lSx|J1n$v#%&Nk{gf`l)$lT-o zc)xw_Pl)I2r&Rxn)r`5=tPL<}l8BC6Le$sX+uv%?jWTtd^4A?t%KMcz#FXp5L}ccBcGT`W?^`>IOhJPNpvE< zftl`E^Zknwcn!i7WvnCEE%WKl?5fO^X0!@*^bIJ!(<>$N?AYf)%Wjz1 zmX~5#q;SCB=ib-=I?ZYPY+cjGdHjlAp^4GxHqlOCTAJI8uJ&2iiJe@bj-PBTnfz1q z#nTE8W9T4yKxP0Pmh5=IB`5v|7+`~1848*5+M|Ni3k5w1vo2jEmy9isG!+eN_*x1~ z2LT2pVE=J$zEI+SSx6jlYZaQdjBQ3$xQ#}B+!8nc{(OtX_JYY&W#+;gCpJXgH=+1h zdk;RNdC4wLuUD5}N5T%uqIq2x$H0`xv~Jx6y~^WMJHPK?fc>WUaW!Tibt9e{}}gXLu@xV~T3t_n9ObhMHO4s5qV}bu=1Ta8%vHL0!2xwV>Lz zA6c3Ms{|pkt32{;MWeq1>KWbWd_@SW*Wxe*7cR$#%|x+M%$yj27q7PCE_2c; zzn`VV;)1aznP)52yA8fe3|HoD2^;5){yA?(C{-R9QW9Q_)F9mN4-IsLm?}qOQ$_zk z>ApP%(t#bN6VKm3dwy@ZYu;|GLPi^~!mt4gooZ*E$-d6-f_+-dHH5zxBhiA9H*qTuqzsw0;w^lDd(6W?!E_%D*f@wBXw2Th9u~o$TV)j0gqJI;z~(W{X6r!T-{H67)fYN?eWT~Gj<>rV!@M-; zGmm`S>v0dI4@O26VJ1eF6~%r%B<<`*eZJ=ySEs-t{8k>;@gu;q1m#EUrbp}O^s{ckstGD zz?&RD+T)vA8k8zCl+Broe`;vfhqB7~TG+UiQyY~rKEtaVCEx2|#Pb?-i@P*G!uc-^ z*PBL>)t*^eeR)-KPbQ*rNpm}1^OvZaHXHrXwq=7lDuOz?4$J1|MWWECRRBalobO6A zFvSPmhJL1U^u#JzH7RGFPBWj!3&Vy)LyDw{{H`R)-o^fSzu6_gD|AsAmnBTU4j+Me z-d(ni#*~yx<5vtWN57rkW|vu0V&&<+jpS=BJ#o=g^Iy;VE}=^#!caDhI-r9tqub)N zFe_{#v}zS?h3j7_{z^{fu)>uKCK3+DzQbtW$do+MN*Q*cKhEpCngkjy&gf=q2^QQ< z2n@Z5zGbI3)bP5M+)qR@-sG{^bwflGlxQB=;pn>3_ zUEQ&=HP6WHLF3wWZtwXeCx3&wmDx1e(w2s)^u^B(%8?z9EFNuCRICoDm;@?8Upk?s zeyO5MF_9Yv?===8DVMHqA18Z!jMZ}<+U@e>=A?Hh6Y1$Mg2^|)p=CaCSExaTHbh*UjXtYUxb_OMgk-jLHYS91`5CnDD zu7AiNWIGN-19a)JQGX=B67W|^`Y&A;3_DtLy7dsdN?x?IR!Y|Cv#Jlx?8Xi3J=J24 z@PDnvG$Nh55waBBn>hYiF2_fxuh)^^NyYRSlo_s|tn@R6R{ zrl*r#AFUll=56C40MThVRqVYADwKMs!*JEd1Y|oW2X`VlRV25NnK>Hm6g_TOtr%q` z&>4T;udmU%8u1LI;Reu_-T z*_$Cbg=-TZ&$wOyrQT|8pb0p5zlI4jbzVg_b;2%=>G#V*VOi1Cg{Ss~LM~eEvL9tQ z!3?CpdX?isUnA>)8EruQTG$Zt$hR83!>T!YmYCC0YFkBcE6wnB7i#sYzu5-(Qkjbz z&mQ}?Uik`ZdP0e21G^5wO76mm;)!6pB521c?`%2LI*JebCktX};J6 z@3;Rqh#UxvLhkBo5U_lmEt^lSNPABs=7jg=DW$3&Meqn;-DEbgsNq?PbzkAWZ;E!PFy3Wx+xx(&L|S}m7R64l0FekE^8V1OR$8l3KWL+xx@3Jqfq zku+j4KJV0ndhya61+h=*8DY?%wET@%@c;eQ8TS&kw&YY zW2}c?4~HnC7k{R#02a;VEnTmYzv=^+A{=UcOC}wuwf7;E)pS#iC#Tr|Z zJ2Ri&ZMQq6ml73y^AW5kAA8juownH#77gulMFl-$NVD+VX+I_DG7tj4;p?zuzlp6^xR@-#%i=Agv-6=Q zJa~p*Pq3qqBpz7Y8YPd}*=5l!o|6(dOIW$fqS3@bO>+Q4cl15S#q}v#k7Q|`i&(_R z;TKE1&)<6#io%R6*W!4?sYnct`*iH0l|L&eA0#>8=fW3A7_v)hX#9wy z$kNB65OgGFYE120_4n|%a6jp$YMO8p;=hai84wP=nE$=LpuHJp;>eL0X_#c*(s$b9$(a?A++ z+x}jV0WaK5e*dBbOHQdWD$GWP2PvWq22YndMynHMw@&0d;uEOs)I%FpLg;oKS_v3jGre zA@hzm-{-u{!y0J6?-9XP0Hxl*q7W`Un5+|Q&tG+LZo)z5o2x|3`HOHmx-qbxOh{A1 z`wH2=5+YBcN=dRA3NbZ9%Y{df*>5-(W|WC2{&9kCi@49im6!4LeMlO6#h#Sl6JeN_ z{2yqr_7Xn#pI9U1V_lVcze%Gi)M-8dTba{d>emBp*}mF$En2A9(UoR9H^ ze8!`5#q*Q>`mgs-K;CYc_C7DoHtopPfWX1)Yq7U+(bgdi`hmk8NLzDY!JoXq8C^aK4E8^}#`Z*Bssz(B%6mEx%%?W6!PYE;wDXEg; zcx}z&Ni)+U8#FGhdQD`; zKEfRa+b%lsp%@7z?k45cuyMGuKCc;)I%#@+oCl~bXVzV{rk>LHjUgkYU0+Ig^|^dt zaS0;90Z@`2>}YeEa9lL{s~3Y@!$H$|$FGOwm&#?Z+{?nsJMHah6g?KNEJ5N)T91v_ z3dJ&rS-}H#5jtb9ck=FmD*3fbNse_UR6diknS3a}NLAIZnXP1MIF2+SVuY1m&{bdU zP#=+_(a;VrPkfK=+VR~WGzLLR;W{yHrL_$6Z>E%r5b;pYF48EA3#*?3^*|q)44bUK zvv(7$7#6~v6)Od*FY2GX;M#S6IQPfEQKNUw*u!#0btJU@jL|?cRh(gh@{S#t{xcta z0p?YvX84U08CC5K7*E|#{93PTodRuMvf2JCGl@1)z2M@0%pNl!RfC7OBnmvj4v&ja z=jfKsC*aX(^QT?HocEG@qZG_WGq{B>lA7W*F+k*MDNR0acZsK;vY6|ev(31<@shK}6GU-95E25uh(-YK*AmZjah+Fq$< zklksh$iIxgrM!<&eROSqS`Xo&6PC%C5<3p^y{zN9M3w&PM$1)<6sI@WX*|}X*(nZk z>%c)D^05f3Z^KcOkU1G&cT=j=^Zyw!+D}@owaY25kBtyig48gQnl47Tusc<6N{~Mf zAKvQn%!p2R0}w)!gHe5hwTn_IJv@%G+icGiYM1Fbk=^$u^k<0XE9jFQz%f3_7SwI1 z$0p0!&Ao*#ApwUye*E^HpTH>pReHP0p6<|BB#pjf?2NW%jd8o{^oQizxMY>x*6hUV z_;}X8odyhe?k=ux2Vp?bw`+v&GD7j(KbSn8qXl;xRpRO zZBpPnu9ic^<}-ec*LaaRKz2E!DvEbIKX7<(Yeo2r|DB`Z);B3zSNn?TA$eZO*wnoio)We+gw&rK4?|XQm-y>SO{rB!PV3(-9$e8Lo-SRo)b=Xe-NB{9o#6(HGRKO= z`>@{6Y1)IJZ#UwX(TUD{BN%g#7-$AJ95)DXo;LzMM8<6BGgCdpXM@9 zu2#J!R|ji&>r{ajRTUr+iTPV%q$dET8fjIP7GNP>obr>?oD!_tw#^rG&{{<)`qYE> zdZ5u}R}?DBsDbU!)R^+UX9C!6x?$}-M(soOl*g;TIR&~CLX#qgQc@LyZRJBRwW~u? z4Pp>g>EFL0w}hoR?IB@)FDYQ)u$&7ErA=Sryj7^E{k5fq88k~V%M2edSpKb7K3^f! ztBYyp74+DsnFeY!&?oL*(mAgq7Z!UCQk=y;h|9yOwp~J7@mf{b=L3;E;Q%Iopy?Ro zs;W&s@k0n6W;r)RF!qyk#b}lQOb(!*K>!1{{;BTz5j8pc3ArtK&#yNfZrO3BBL$-u zHj-eCmOz}UP2`2|m(0Ndlifb4OJQt3SufOm1K!`3U2M?#8ay$nw&c9 zmP+?Y??tw?n2nGFBCkPP7gjD)wJmL}ntGKkTgkmNx#*(O1N0U0;?CrCw{4Q7^qpoS z^HyRz%^@6^0F}MseFYdHQBFe7oZP!L^WQK{(j~dD!+BF3f2sR>WjYtKa<7)4oyPI4 zgwnc8$=DAW0~=N!#g1A@BvVD+U|WppZ}Q-d8-~O-Q64s-T^5K75cTW00~^H045she zytQ9_!m$bbzyV?s9++E*y5R)M*(vH~(9_z@SptuFj#(>F`_=m3e;MejVyU&x%h4U} zflkf;ax$Cp1~te1oO~wvCxA+>i^gizD;cW*&!ByLeVt4sYAcDwMXxZNDO}h;O9llB znlI=sFe?;iq=9JAd{+Gfzop`6Um4x1n65q5kBetCmzm~GiZa(a9ZaN7yukcQWqBix z3F_~;yA2Mx(=$}>%z4E)=duR;?hKnrR7xxLS*m^6=2Pz`aULL86#m1rBLDjTw^yk# zd>#9geBkLshWbp(+r^~w`w1!-?(@A^L;T%luXkpedODa;C5hfjTN8abj>h?c#@nqi zQC{~B@7M&>8R8(8Af;h}F7%qhg>@a;cuhp5i(mdx&=v17Pl6*S<`j&jE31X@hfo-7 zo!w>xZl3~}pL=i3=lXM2fnW*^ePG00^rikwulv)73ND(>1317g$!O%Oq$Mq`>y{80 z5eiNEnwJW>=gD|>^Uk?-^>aV0uK&l^1EKmiD}X3c3>1KQ2e)9J*%4n+*=MSg)8qQC zE@M%y6jB&`gIjH+>uN*Q7dg;_H$$7XHG5E%yjKbn_PHhFF5NR_B`vz?s`8uZW}>d~ z?9AF21Y4OntPa0^9mu(fVA;v{C|yHs>yNGDMCs4lFv$s1(np%c1>DD*SP9V!Bua#u zulJZUg*SH(#3cC>gso{y^2mbxZ!^zO0SO_D=GkKtRQJ)|9An<+qqE1qe+c;Gqu?Ba z--Ul4c+P`?(tqXXr0X-pn^+giN81D?p>3FJk*?ckHInEwLPFZe=~+ zNOE>y)^TM?OMzi~YU0aa>{+Z*3;k;{aG5^6>{VFavtLiEbTvN2uL>I-kcBF;^>Npp zWi`}t;=6@uXl6LS85@h0oxQIQnq^-eaw&GL!2Is?_Tg;ztm}{R1Di;4GnvCRu3y65 z7T-o;-6y6AM0Hyfx`PlRDS%7QzPAB3KV2=H{_w5o*0&-8TkMR@>(fW|4Ln@nI%R2- zBYM$p<9Xc#P5Q?~&FA8r9vt0vRGn9?FvgKL+fyzQ&FKZ}6JGC&vqE;J%^ttgo+%H< zu^7H1H1+WWtl2H*CFhXLVBQ-nHoNPe%eCW5?HP@~ZLNG<@p`#wkqfgt&AV-1$^igU zSq$!TjE*VYa5JW6z_ACG0jD3kDdU>wrVg<@T)ZFfXzUT91`l zSHr9g;)qSD@^|r&Umv9xx1D%Q?4~eI@^K-Bxh7U>0YlRm0N(q=Wx&F6TJ)M-9l)UT zTdrm#l&0!~HgATt+IYXoY1P@PW~l0Fh2SifcQy4zw$|g&UgQ#{2dRT-wU&3-qskv; z1PtRx; zKHg}l2STCz_aDSicK;QI^b+*$Qffpz>thF>=Q{vqrS9=gblx&g&{`O7u91FE># zlE%Ev$~K?KU+CtS*PKQP!AMEN-D0q`muOZ@Ruz(wz;G?V&e|k#wC2M@%dbA$C-1G=rg8&bDs!P9RBp1*Q`dTfraDxFqngI4IoOJSkNYn$ReZv?r) z={}}$MGZOy_^$tif)5YP*~W} zKDR4doyN;@fkA*t`%OEAeW%KYK36qfb*4tlog`Q-%^Cg1f=Sml$fA z?333^*t&}PV%D?X3`2-iZ`67n+(aE#w0uU!@v|+p!9L|P!7B4AUWcuc`id-p*4UR> zXZ*-$kz3W1ru%*ZM)62HjOvxQzd#Jqlvw)I`OVQmjMXHk`~Ng3oQf}zbuGr%vy}ik z2s(5+tVeASfJKy^l(I16<*yi^8ELY&MDx&KHX>Udj%*nHq3-ra^fAF;U*P=YiRwn9 z-M#!RAH~>PY>D-2(X!&Z#`PU!c_O}}dpTjfa_Ni|Vrl~hKzV&ztGA=$gYYZTjmxk@ zn!8Pa<%{$Kybfp$2EZq`R_d^z!dvaH4up+3cjJG+moV}auWMV8^I3@`@okFvBuo&= z{%SLn5O~LG;+JypY&0Gs8A?JG=#RXP>UttEd$%a(ro6&`j1mAI|5q@!feF5|GiERl zZEwG%UNd(qxHi*AWFM>*x00stg*;__+1a<&E5CV(CZ)Nrqs)f`t*G-57|f_Okc!~) zqyh>t7iee6-h}3MS76LLs;)``dGX3PwraC3kw#O!cAiy@Ul-V{);nzk?8d9G7)7td z)}QMz=We`rg*@8y|Dc|2!omGud>E>f(B-0j>&kS$D|1iYn){#zww> zXa{YZ=UpHO+5CGPozY$IA{uLh@W>@xAfAHW6J$6~iT)}cK_&IH3{7$%=^kYyd_@?d zJv9m5LdPtJxCI4+t0aya(OJ+elj$n54}@yjtLDNavAm5h<>n{VmXV1aWgRo|o)oms z*zjC@3H{lJYQcG1BRc zaEdx|$sA=cKz_qi>ibLsuUfeC)@czS38X_)^nJvQ@d0V~c8I(!AlEmWy|V zcvTEcIBx0Q2{mD&;W051=zv2jcCQkOrOgI*h2LTV`<|#8BghKQOZGNYlA~=&qAcZy*MyZm)LaR{ z`c|f3Y+xG;W>!6EM)J4&${;8}Qq=o8}B6w(O{JyWVewD+Lww?p|Q z*ICRdxLvFK*hpCAlsGi!z3oc7ZH4#;8rM~vFw1XR(G@6W3?Z5>R-~r#)lSO1iJ9Nd zB@cBL0cu0HgHNa}eWmCz=up$|tknp-`!I;an3Q@AId;5gN@n6zxg6Zu!7qpzMdS2m1+;JI;Fp56E+v75KAbWal^*Y3!5|K?c`y4x z+vdYy)nLA4h8+Jtjv=rNY#tO|r07U7E`$k?F6nji>W z_?mK~xe5F8jI?XI%X)mT0kh}4wdIj~_HG4bTp%(++;HmA0PIE19n=9t;atEy9L!Id%J`oBYu*fjYUL3 z)HbJDb!lajja^pjN~3q`p?_h9Y})?He~|8y9gKg;^Dj7y+C{vxJ|`Wv&0jkB=??nl zaA`mRV8ic}Mz&ud)J01*)x@E`C3WyxUc4^FsWw`UCKG*D@`0T%>l3a(Gq$2j@X9+YapAe?XkJE;JS8{rbM(f(JS%4zR7ym$v3Ff0k7RalHT9@z{ zhbsd3xfw3l23Z)MC$owls~xLt)Qi^Qc0CVFUs=Te!*?N51ee2k-)o$spGBctMS&+f zsLUehZ9%%D`C!c^G1zA|#MW&4R*C7|pCe;Fh4vKz^RU->3yj3h0sjxa{X(bvR@Hs*ta>Q%hu^N_he7Gvs|9m>;pp(K+ z|J=%?F02j9EB!mQJVgoIGcLy%96%f|`z-4B_tT>*+pzT9C`wW^B56d3Z-iOJZVysd zTP%Jr9)({#@A@hRML*=Rk(Kc~?gTy^Xq1Z)s1j;iwUaocRol%2e*6v5q|Lb2c&(>` z5(zCMnt3CF-}tC#&iF$j{*qS0%zYijYtB;>W54GG(LpVl_0pa6(qYBx$WC!}EvcOK zdMoGlr~hwlQj-YeD$Op#@#3x<6#+8yL-&^zfx=UAi!CX(BY8;~0N@AsB`Tz{RypNA z=%qlXK{Ap$k2M4rZ$XZoVDT&S!74j>34G!AJau3cK);sv6SsNhQ?irPMfeQ1>t)rp zz=u!xy3`&$Mw&~}Cz~u}23<{ra<&i%<3|aIHSP*S!l?&&548=N2V(9|mvQK#h9H zw;3A9|Is$26mH}x1@h+vjnHoXfDH?skM^-!}LqI zrNfmmQPswE1&$vIHZ#Z%U4mD5X(OUpxixut=@{??KE?P(y1fWaU%A$&P^nqt(tI@$ z)U9wYzh7FNQ=r!gX*GXdCgM|eN#t@DnnEvu8_}ZK*f&&<`GIMTfC~Xvb%(j>a@bR^ zJt*at?b)@9lo_8C$mL*PFxRSl0X&P3I5|ZndsT=_I14qqN#1drO-$VX)iSYDC~}kW zQA-W-hY<%P2jlggyUr(WaQ~Kugpn;`qmlY$5;0y^ismYD*b!6U$^DM^h~6B&W=Wcu zs0AQ;{t)9yktc>OjwF%9-7GUr%IzVwMTk+ohr8;cjgwg$x|5W(?L2`hF7(*Y z7O=FY79{z|2`LTj+e7gq%iZP#v|G`M>UsvY2U4S5%o)(NxUBOGz~sg=$Ed;@4LfN@ z5_9s#$9C7(wM8$OSNxIJFPr=#k6mMebog|`RmHa7LAeh(V#v@w?ArX3?z#Xj)k)*;rGhe! zh4st>eN%Y08&x)&u1@H?D{5{MGVBMo8iOE&TxhAhr-wt{G+_rUSj|j04o_kMe}~t4kfi_ykQ$XI3B<{IP`4(PvOd93}tIcJN#7 zk-gh2HrMrj85Y-Q%tMk76pBpyAl9G#3P!d(%KgbW+mp&O^Hc{+cy45K=5UE7ao>}h zmHeW;whIIIo4J_40YHg)kczWLQJ}C4y%i4#hZ;auQ7JGz8&A0~5+!^Rk2KEn)_NrJ6 zdXD}>)R>4yCuWv}N%aLJ_qZSRyz0-an7JaOWDltQ2_|D2msI(@0`*>qSfE)@9%>EJ z%7yhD&uy8S7ID?$z}S;FUizf z<5Le6-5^CbekaeEqm^IHKAcXhs?_wIO$7G~(;MeJ+l&s5f*F#$p%7c@PK9N8!-pLn zgXNu5hlnLQ>uCVeqH{h~c}vqt2H^*R&PrdDzk03-84H<=f*jAr0SM%=iI7U&C7N{e z*I~a)zX`6J(f$hSfFtm|lwcd?LjBQ^m5(N`IJ;EV1^2g&T}u}Zkoi>ssb^=QXQLb@ zOb6IO#gUgEud&u;ZXtm~UR;k^-AMgcpG{6=(GBClx^rYH1#fZ1-!JI}lY^VQu+x>q>247wI;6|gHu3ldSf z1VeT~bPRgwvXZdLk1of}`S9?#dsz%E8re@DIy}{Qi%oj2EV}extJM7aQEK>=1elUqQ1;BxRzWnaMv|0yQHJvD*KsC&q>=eBk!&YdhNe0XUEQ7Cv;tq_`Emd^bh3Gz|F|a zN~kb9)B!h>YMHr|5o>qk3SM;8)Nx_;poMU4kwDYZ4m7XlhsZ1AWUj;B8j3+b_oIFW zRYXc~V!r&~J<<bM6Z>-|DIg8N6<)N3NtpJE17&#@i_#;-pH zpaXV9Yq@VImq))}&;wpB{;5Ii2q_{c?;UdRMDkITAIOy}#6~n#Y1C*{YbT7h$0mz6 z-0CjyXr+9=Eis=G-}%A^FL1%o3>ObbhADg2Vi-EEJSqe1z$^h4(24WDf!=Is=Y>HZ zF6aNw(ItB8UyZ?AyFv!1x#tEns7FK3HK13T+FTA%gU8v(m|G|I*2}32g~w8iDRz{_9CtlgpQ)nN_GwW|Hu1p zj9CZT^2}q+%-X7I4gypq9gq$spRex5nAU)K;d(l?PC0fY!aTsuKZ=C#$1zetpnR=R zf;N>IjQXCu5w{aI21-57Ynkn)cq?vj1;x3!j}z==A^txQ^nVpf=3bo$Y*4i;X{YKc z)pveD)oct!0lhmJ$2*{gB!>h+0~f^Ukg zH->371Xeu3AQ?W_Us8lt$WPQA3A}F2Z0n;X6_djA{)EwE zT%?uoP!5!<85=6O@B{b$ttYx090winexJTGsjsJ?J1(f-kk9i&DF>eGJwX?J5UL=( zi=&o{s=r_*$`=Ks5`0JxTw_R3Mk}6ukol_;saFCZG~4Y;%xG2e+R7S{eEKhve>0J! zL~8%5)EY33n}#kEO$ZkyR7}0g$G;Xd7C)m+B$^B4GdHJerDHGnMp50P^vJ#~koY3+ z;VEBAN(_H4yKWHX_MCQz#_(Cs)D?%Qp|I3!7J+#bshsXg#dQXw$SsSa4UrD>KwsnA zygp%K5iLaf|%M}iF4&=FaPSve$STeEk&IJ za>9866m)-~VBPi=jL;kBVy}B;ZiRpP5&8#FILTd!m{1u_kL}y<@%K}|R*o$b4}$w8 zN>&HrZmJQu{gyFRrQp=IhMr?~OBW_jQqwv+V@h$uTQn%nVvi(JdGf77)xd#e+`-hZ zClxx85B@5QOX~!POusw1+G~<%i++g;=Xc5rxp+L`T4kh&TvoTHzofH(80*VE@0dfr zD&yTzN*gr+e4M<_#7S1B7iABFRb7KjsAcfK{lrMiOh3!-Hx%`Y= z`wA+hafU7bsTVrRl@Z#C1nTD{F!HNq8R%hPBL`UkA^c%E+h;!&N?UEbBu8o_7IwlE zYBmrSju}J|PA`b!)3tEs?RXGl)aawoj>7vGhB_LDl#)okFX3p-Nf%<|D}9XQ*_8ou z`F&dYXo7tXFMQDfWZKf6{62B~noau)pe3$Ve^I`f72>zE43K!5HN8G9dZtk$N4V{T zbE=BOpPxqUNQnk$?LF77+{sxH()Pq79nI0ecdS5mVQZcs?kR2NIs$uDb{l@^2PiYJ za~mxxOMj(%HyXP_dNxc}-pP*in~jy5V8L9s?9Ad5PyskqTEEbfZo2kMg<`PZ!CVT1 zV@-y!dl}a>O{U8A2(@I&R--p%%<;x5k|Run+e-YVMUC3xlTs%1E}MyYj7nz2EO|}L zEm>$4M`zNY#h!c}(>)b+tB^&35$gMSlRll1jH%M^uhE~rv9JL5rsK<#ITuz^Mdws= zx0 zL(K^vQeJ3PXWk4|BaZvga_j+A4@~MabqsXC?=Y+eJf+d<{AwIw1Y+@p4Ig1GOjp=b zYUbus+AIr*$Z4qc?k0f<$KQ+G9Z(U`oU%b{5ADfM_FTrBydpJ?kyK^}i zwS4E1mjK!RL>a<%;t?b!rH@K|yby{GPMT#{xQJg>!bA&q=EpcO*sT2QAgvyeU!$2B zr}pK%N6U=>i5AitV!6{`v0Wpr{>)^{FlfgBFJq$L>;kdYtJVRTNoIu+YbrX2MLD|X z_WP)zGn{}mIqe<2KKnOb@XB0y(=v+sTrVS*@~btlxYSWvaSef0(5{Pv4Z6!}Z#Qj1zF)JOW&-onwzOIeGP1wD`_$nTR5(9z|5) zbvM*5mNtLCmUiUB11YGZ!7kVp*bs%=xmJXZu2_|~5@+!nRzm`Q5unrDpms34|GM3r z*Z_-e^nSQW&G~1~LS!eCo9k~C6C?kb&N{@^!*;!!tM?;QOXNbRA&@o{KMrxYR!s4*(_(VeCl z=nm`1YO#)9AN58Z{qJyh7}*~?i0YME!zE0{G*GQf=lb^#*$OdZ*Vby^W-~6;R2&AH z?PH}PnFo2AUuk6*q1Zu2L+N`_ntDYlBMo`b2b{=*yZIGYvaH;&>qt7_*qGd+v{`#e zj3K&dV&{r(WfhM)4r&ix8#3y6;AYJI)a%C4K~o?{-rj=Z?Sp{-3cv%7Um{CnXr*is zJ*gGO5^9}PrIG1azqw1Rbx1FpF?}tGLGS2?U`2zT@pdu7LRRPb7Zhy-1~h#i9SIiv z9D%ZXR+6Ii)I;V!=ik&xk7dGVX;mbLh)H%4f1WEa3*?G@hIMD`t^TU66Gl!z1r0yo>On1s~qWBMoJArK)fY|u@srcs> zj-2`AmAbpmn_4BymL1gH1E%-wu9xM?BY(>vEH9NnIR&K197nBJvT{2AUxO_u*W0^) z^mVian(+%1-S#?|m<3Md8lC5W4kw)0wrv{|8xu}!Yhv5BZQHgrv28oM zpLZX7f4Kiachyy^R-McFAe_u1K1`~hef=G)=@U2!oS>=%@kWkX z(d>SjA4!*n44$gKyEkN9jg*eN4p}e-x;-Pi)$TkhD+mUFD*eO!bmOEs)p|2*R(pWB zzf+g3%DcNE7nf~4USWat2ioH%3Ga5HagZNk-viz{aeI0JXvFoU&4T@)xc^}3>zda} zbC7P!W)SIF98P&sR-Ov|01j0`unF&mr@QsJ1@cytmycSNL9z(}&%H*N%5zV7%yPs* z%@ACfHv1&bTJQb~mTOh`PLC_CvzR(=b3!Hx&%MI#8-+^t^K?EWx5Jq1 zLCJOig-oXiqESw?$V}8eItU6Vd)O3=S|M9Z>Q@X1L1OdDiA@g95_Xr0w0Ju!7L)z? zUY-TB_j8VIU8L4p?tL85SWq+0BWSQ;bpwQJ(DSkhr8U@R>hH{^NQ0!xn}Sq_ChHLd ziRm(fTpwM;Iw6;{5!(h7WP7`}{k!Cu`>FbWT-<3On2B>oUvULFU!dsZ(>2H>S~HK= zGJqE6AFc%0`f3UcZ|qwr7E3eqM#)N~w)eH`_giBYm@lqDJrK9iyeB?xn3ytjt!`by zL5lMI<6iw%v~xRsBV4mu5+#v~ri|a(w2|$;F)K)$>o%-In=j`q|AO{I$eq=i(>!Am zI(u??g8GeI@3#07zv^Qo-CpGNWB2-dD%_Y)$lX4!R!sCr4S#~)Sc{4#50gjvDi9a? z*}?0W5rS-HT`rR#5D(?nYQGwC%D^t%p0$E2S~EZHA^wBlFF#$a%U(d@b<6>P+t2h? z$G9#1uQI;-Q|KA;?g~*MC?Lp8{Sw!AImzDVzC%D2m9PsG9}Urj?`=r z&lKie??wcGS|I;kNUSp{dq{di@N%uQ&aO4L>qh371}m2sKt6xq-h>KJ8UCBuulNzH zFf_lt5_E4c@@Y*@alKXtxmGXfKZp}{fz}ZDh4!10Y-cxki_qWa1O)2!-r?x+s-4Ko znK|*cltWGf#Ft*sjNl26aZ{#n=J#E8%MOP5;%b_CdWjF+pm5RJ`X!p;lUjR$aC%W$ zBBq_0MZuYQRlCaE{D6yZSqM1|n-S3?X)x8$&)w#h>rZuc5+v4(%jYkbf%^VR?9k7$ ztI4PZbZ+xQMESx{Tc#$Y+VoBW;i(0RB96rG=rWtb2EGEvb?S}Zt~Xr@_apmZ2YILr zUjBpJ`vT-bd}!`7(cH2m>#*6?wfpB8uz<5lf{^Ya58{^Jm0o^F7<3$+DQZ|%oKjlL zYEAU=WtTaR#GaPlfqDNM2{;rSfg{0Ve*O0dEMQOgf=Walmz?y>M{KGezutNVVA-f; z%sddi`U;q07mxpBNQQ%L;Y69vS-yLoYw_7L!Gzt8vO$oxE~DS^x98{%ZF67+zARrk z3=t6TJ+;JSiN&wAKph9CN zk*iJvK{ud)%NaU{OQ=4)zfYjP7Bbw##}43Q1TjXl;V;gcuk}d_D=F6K zF0)4ka-Zs~f^ARj3tMVL^{CIs!P7bgah@j}>g(AJpny4sVmsP$OBTE(X!rV3x(#v* z*CH{}Y7+aXn=9fLIA$ z5YBz$s^Dwne8Ke@%;Lm^yS(||PgKISpVam~KNQVB7m&)_qE!Gpq~%iGDNQ$Wt{UOq z=9^SgRTYSKZ%rxcV&30Sk9xCNVy?-|7$t~gnP-`<=$#DZUwk~=8n$^UOXs1ZrO!oV z^WSePXcI%)tL`9z<8z);3h#f4PyxB&Oe~Eu0w>ceRU*sn*0t$}Kew*dtBt4bg4fW0 z3wWeGc!t8|yj_309%`bFs>XT_$!UqL>$U86w-K?3HTR{H*&)HT{odc0A|g$Z{i}pz z$7E|Zkl_*-2iJDe>|^F(JI8p5G(f?SeEE%l*6t&0>~;-B-Qzj@C4o1hEBYEnst>^w zy^8+_-=%eFY2@zSy5c1&xxpVYeaQ3nFAsHty7$IsX8%{s)skADtQ%#O`?AZ0yUG32 zw=@R8)5M2V&p`CSvDunz8r1|a9;n9}TD2~_?Raj=VavN>H6$T@evz2|c^o_jx{I=` zK)UPCWwxO({^ay;gU|1qI?1PF0)hNEZrxoJHLt%>P)n+P5Nua-q~r3V6QKVG-q&>7 z1(8i7MPUU>0v<QXaulB^lbKlm%QvOiooZAw;{2PK10 zJWwC|#oZ^S=_~ZKvEy;Sm0|rR6@8}u3se1%vh)L2sV~OLlw=Yr)A1X_k}EpoeJrHv zOvmn7y62Io%0C1V7#e83m1Wru%z<08PNXH>HK57hZ#E7m3U7$!&2`t6R2~*NB?)r z0+8O;!Ex=W#nd_hcJP(1S{@2rSfK_+=pY^xe!5S=o3*t=E*1HA{kt`rz&w?)QhjZ>VB;`iZ=#|%Y`-2ObQ7fqib3exG#^P*pjl}G0fmtkDw zyW}i@-H1!!KFZew<-*u`^Y+1i^dlc?yV(dy8TpL|ZXXZD0K9m4jJY>meKuT~JekOm zCiBjX3!Kg1^K63yM_$S+nF%zur%;h7a#1&c@QS5{^RsWH+X~{6F3NPSKnxM4;UfC;nG12n1u+IEiFE4F z(>m!PEE*moTqZ#(7bsV8CwZ+`%?qvJ-_R^hR2B+tG(N`A@t{Ujmi`~2kM)Qmf8TVS zS27@C%C2zK&WkE<(iOigo87?K__SFDD`{OTdu610QF6w;wph-3gmaXjsuF*xP$vH6 z9%MR~sX0lKkxet)eEPNrDRSIu)X`WBNmrnvOUxy$7|f{2fl_S(ZU9yVdh3ke?qQYD zjQK|@TLRMEl-nyXl0JKC0ff~<-NX_Xl32bwROp%p8t$|f7*T3&|5gV+%FwE?u#g(0 z&Z*8prQ>Co>1c$T24CKo)<()!5drnLL4xR)XN@t#ZSpMo?zy7SksUF`q zpbjNlu5`fhAZNC<`SCkXMhb$s+Z@M_VQOkGLKkq8mqiNTmBs86sgOvBT}>tl<@a!2 zFTkTA6+UyicgriIb&S@nYAP->N~c%K_bQD@2E-^3%L)M|rPsy;C$0`D;_c?2EG54t zgp0*gQy1c#t`mfnj!Ii~sz*?42 zt(qv66sdmLb6mA(8jt|eJ%@*r>M%GpKd52ZuEBgt7j|2RDI?uIFB;-hG276s zpI!OUhxF8=AQIhGx;x$_Y893~Rlzo)(+*(tEah3|ajO52GR~QCeJ3(Nmi#BhVyTg2 zu3iLqm7V+<53r(S9f>DFEvrEF@}Dr*T9L^t`q*L z!3C1b{Ks7}jc#2iYLRU5(9jI8EL8L(Txw&RYOv%5dt_q%a{6OV{}+PxCT^t&CaQU2 z7lnwl@Q|65aH3As4vP3jL(Z5a;tMyrP8I}<3yf(MWI&x@!VLuqZUj_B&>V(5*riSn z8{S6F=_DVP)B(7jU^OxEVCOL8{#>{e_F%; zS^yTNOZoL6hhUo_U#Cr=;#Uw>-*svp^JX;UihA-70%|_HNtl!WH1cX}<#K-GVW1Qx zLdwmnk@JF2{4}N^BxPT8Ab8i1CicGb?Csk{qb?O&kr3+JwIdZ2ILNF*F2k-yN~XT$ zWALrsQsPdvF45WZ4xk3?=+vItb0+ng9raT!|92v0vDu6`(BCn4_sQt1WuUN=yBKL)@b8XE9vm|yU!g$V;baap>&2OC|g1! zB9n*H(i3dV?gTuI4kA;(0P0OXgUh>P&i3RNK@3mKz%^rF9yVa>(4qxN8a&IVdj0V` zYU;x0^uCJtry5=>6oF8B3Dv&aM0B_#E9_T!3)Ah8#Bmh6Rg9fZ%&J-bkmeEVGm?~h zX6HPdh-4i?iYo6Pg!GCQHpG<67YH>DY^rG6%kQSCcVpeUtZ-K1|MV?Ga(s9Q07+jE zrtj<{e;-?!dCAK-f8P?66ffwkK-_rI6=*>iM&<+S zG;=_bj--V`m}=8OA>Lf>Pa&&TNE&H4IPVp?kjPQv^)J1e*!btJn`a$7N`ReCO8gS41}5YZ?mm)o zL2}&dX6mpC_6dS*)vJ+}K{c36YD5HCadJYXhqhPNNi3EpkXf;>4hKfcKaD>c@RRy8 zhoH)~)9Vn~4$&8M(10z1gbnaJ7lrz9doCl05B08+VHN)eE&NK<#>`#>RGm})DiS8? z50+kdhw8ou1GdFGA{Ife_;+IhQS?NhcR=?H22hT~X*i>>;EkfF95#m{VKqxJG8wUZ zEX&gj#bdEqE@Y(ehkQ&bg(=dD#OH+TvwU?>iU|*Kd_jx@+T87f2}Pi7q9g`Y|p_P0Vdj3X4R!U9T*0 z)BMo!W%Y#K(vHpks^H*1Or#eUq0XcCUX6F`HX$duKq2|U;}R^+Qe2#%jrQ?(^-`EF zzofM!KZhG^$r8{BCwSrGY{1mLsp)+EG9~FE#|07VgACztL20? zvdReQ=ncmu*Mf@)Q}eRVM_?2E16y33V2|@>mnOV>X$g=z&xw}uTGv!D`F4s#1xPY2 z>oZf+&wtK&;Ol3G0#z_DMsW51YQG|nb9h%Y;9OPFD6=>L-Y)i6aB(qFROX=1XFP6R z-uCyS`I)Y`9_$Z``@F36jY<7pTCVNO!e!d#u+lY^0^ z+dyYVUU2}!?M6s44P%8-$UNl|9uIF{O!d{eV!_m{Q=rcPFDUD`#qr{H?WeujK-%|h zMGBq5cY6}SsAwdrd<+g;UVVFtI9c3`Te)ILYd-{4oUcx8%vu?$>t!Ls@*o>5_QM;V z)F;Vh2(9wdg~?e@r2S+mkR{HkdC8Z?VA|(xBGv7V&7W)JnbP^{TKXOb#6DC6K5=oN*X7j0fR1U^Wvf- zwQeb7s`aQP(&j6@&KUI_+q54p?@lXOBx+7|(b?!N9Xad;EvdCf`9|X9L0~>h6-X&_ z`!I4!FDkUftfOe348N%JBq35lN}2RBksawqwiVs4km+LiJH6V6dfdUsjmEcdJ=Kp? zS*X!g5;@FgIN~R4^2IEK`L=8im#Njy@DXO}w^h2G^>fM?at)qH(>;BT*FPvgLjT%c z_VW$Zj^H!jjw8xvnf*&b>_nd4&EMSv2x*OO1MK+jw`RTidl7m-q3lMu{KSZeqUB1n z|825ywTtmZmLWgQYeFM_Y1w?N=>;?st@kN9+Cyxp2VMr&Ngw)Yv&UB--`6U>q`aIX zUEQk???AD_21-h~VA}{k{B_^VKC7_$;jP6--y92Rm|}?P{emHoOpzOHk({smQ+@|~ zXp>$`sY;VkuF}gn{TZ@H0LU&um9V3f53}`Er2M)HR|VsUklOLgmth5$yL6UVDM*<1 zdX8L4EL54IhVMg>l={%`pQji_wwZ@&aBNzC*JDyZ;Eoy0Dk0o5g{p%T?CR6nX)y2X z403z{yB#BufM{?UI!2`55Eq( z@!6QSBMiegNEjsVs8023ca+IeJjSLuO16Rd)NqdZCyW;Ao*PRQ*42xYz)i2Sa{B2D$H zChq3^kq0m0X@6557~txx3#*EXqHV^eWY2bdj-wVoIK#FM^DHj086jJa$QPtO%qy;f zT3DSt33MtvAgvqVZY zS4DKP(Qx1*q|wb`dGzZbspLL^6wv-l5pWsQ1+d-cfjTT^%RJrixaM9w`@h>%qez&2(?-P-J12jGnK1VLKrxF%UgebIvWGo&-AAZfpwJ^?xXKj50ME z)gqb+@E$od=rE=p!9|6D(*L$26!*iVJ(Ngmh9j82>&y8f5opR9!c^tz3H;wm&_NqCRDT_|BRwaXGxU?g3odGUOLS??2hz(FBg>O>DT>7M{z+(WZ;Xyex@ zCKW(m2h&uNrxQ~jyc~TY3?xoo09*&D8w@F8-u`)}{o+CadK;Hqo>XBe!l{ ziWTKWKCS=e{Fs6u6sJ=d+VI(%)})XQ=T-aZhMj`L-`MrBOeYk)GVB=R`eRX^XaJ5# zNjq5tepa<`$*3YiI%-5*KQ&PD`#(G7wp``x%D)$7F5>j?AL(8O?o633{rM z0X>xNQ6S*`mHssdeGiF}@&S3CEZ|2BASbBpLK*X2TX<-&h68ux*ZQI80n?Z0R&7md z#>t;4&^&hx@JeqlU~Tt^1QvH?kPV%GC^H%I9Tv1Sw9x2i>i-0%1GM8zE;Ps*YkB!i z*R%FiGMmA`fl~w(YlQgNh1+w$w*(R~0zMmy2$E!HnR0UixY~r4-dBYvoox0D6cuBC zfl8bP!K*(s3SRbEHSLd{-3f76eiJsXEi2tKpaPWQ%!6Pv zpg^hx>C()dAxHIsnY?;^!bLUSl>_q8q6xXYKAQ5l=&J9}l9Btu5A4xuBu_!7U?T`vW1 z)S6Rv?qQQP;-93Yl|<3{14$d>E%cUO`K|s{R$#o&kLXP>9X?MWmK=OR@b%S=Ayt}Uw3_xVfG!j)DmC94kY(|h6 zwQjAB3-9Rk9qGR86XsX3nhZL5lGlbN{6V>ZmTLwe79ab@y%HI(9my0fF zfW~Qt4nr;X8t0O{mevLl_WoIc`?~??#+e=^lwOP$}W|lJ{5sTt*x$gbD?KLaI#w$!~ zh|AA$6OUq*88R_#CThm;L{i~Arh-Sbzhv2TNg;<{>W@3*#O=0wG8{B+$rA(XWryeJ ztw5j{&tIxZOz)H=dg7zJ{+F0i)~l-g_#smugJdqoE-#!^KgBdCL$^*gH?7L`lG2y; zH2qX-Fk^x=b0!$n7nQz3u?cB=L9wegEcEIR4BRqhegP!Dgn~#)N8sDZj1@gVp)sLF ze8!9hku|1X$27{xe)+7C?~y_J%OJ%lu?X8*`k$?af}56&`Qn^JR`=GNzQvxEv;uRA z8r42k!Z5*L5AiP(VzT1?0P~4F@ndQW4Tk(`JZQEPY{js59*9kWX)j2KzE<-|N>)HO zJGS5vE;G5c-Pp##$srpLs<3#XnrBILXyh&gU=Gr4AsV6GDg;{cEFCE%)M6l^Q17KSQ+Ts`jKHf78`{q8iuXZBC|B(+{%Tq?!N;k9 z!7!Jil09D=R^$W_sQS@=V&@gU<*v3wbxl%MneKlkCd)aLnLrUTYj~cl<%Q}3QW*4c zF1-4+9WYIjcU(mb%opDxQfino`xSF(^&IshYNiJ3P{r@Jn0}V@Wq%LuycczF=$h@C z8q<`~3`bIAtl242r(t?(mm?$bl$ylhJGCtzI0SQMYW1jX!{=I(&3|@S#q16&JudR* z!)F_ftk3kze`SJ^pd(aMHReMqS;(%ELgCzp3Gw!y`$Uh1I>st2%}(#i&gU#4glVaWKX!KN!Sb~^GNRrsnsYs(oQ`)h82VB(V z%bA3KAM-AFKPT(e`&LF$jw!8o2Jz-Q55WNF<*Gq26@9zjsyLMST5 zt^K?u%xzqM|GeXik0{rz?;fP`u1FqWL{9-|)7YTTKeN^vO`&%hm+>DFNaY?CAPZQ~ zY%6FBI?zea*QvtDRTYlfxg<*5%AuX#pV22Ouw-f)`-K=O|ys-x3U zuw`2d(52@fXklucRKPgCi%sKQV5q#evj6N zE8}Njq=d;~jBVb70_wh10SaR>`*ugq?W$oDva_xC6ZR8DbNFp^(YoJ7D{*0^Fpe3L z+WSWz_l=N4TlFb&>OT7u7k1sR zdQ9Gl$4K=TU+xR>t~2M$YFt7J*%}ClJI}(&#w`#=sg; zdjHE0ZLL zB*eADs!sz(z_)zucSTMrXaHL{rlMiYeksUgmYCO`DSLZ-+!z19>&GuI7&|$R|6}DE=4!dtS&$(D6S@hQnl=kS`ALYb2x;gmjv%(S))4x z&G3MMa;zkSmN5L(V}9@>@!49OLP2G;)CTbQE`3mw;blX>0v4sa%`AO=fQr& z2j)VObpR8j`8pS$iEVtTQj0Y8AIulmn2J;VaOdYTey{faQ~Y%ex_CJW zapXoli#B$UKgTwAoU=}Bi!Ti)*0+LXNnV^`J(_edwUSbRK7~FY>PJ|3*dTp4t)a)t z2Yj8*t9M?cTNe@iTWDFEWXNLL|D_M~0lk>%6!E0%)IIVv|Ec0EwrnO#y^vGG*7iyU ze`t;Lw)!`-wiW)^{2$sOmZ=gKTs}C|1A{>`Rs44Lar;9ci-=lFty4*?I1%88F}j&y zud6RSc_=|DU>e?{oRu6F$}tz9%j6C1(!=ZN*>6HmM$X^B+2#+u8Yg4%5tzE9Oq*(x zct2Z7EeK4d`GJ41o&kNmN^k7Idn3k|Soy+SfWnf?8V1R<_}hB}gt?{OYJk3yiPBSQ}L& z!$G+f-BSyI-EWKXRCR^gRZEBY#EYyjHXP$d+MqrbO#pWJmoI>HNWp|=|nG|^0H&H zD)G@f+BG30Wf(~%leIIoOXrQ|-1uI)2y%^1K%7%746_@shfrrL6({UTqeB-&b=kS8 zL}Dbhnb(rF)h>^Bf3l*JiH`zox8G}4 zW6Oc3`c&<5Wl}M!_Mc+wiF=-uF39%*0!2)PtjYS{>S32zcoglTDl7(S4T@^fZPbC_ zUHdp{YlAd|)ZzD6LK}a9^Bwd_#Y!b;a#$G1$7pkju|d6*#hj^9fea80C?h)MT;!xK z>jnP@Myrv2);y~E+*#Q8y9C=eHHgnh$ZqD)P4~DK4It_YsVUV){KadUr0-wJ4=25x z;$|$1eaU1YY$@I}CZRC(NG0wOi8Fd;qef0`E+kitWtt)%-0Zmi^M5#SQ-Q13aphV^ z8{liqh=V>vYNN9g0S2&f`>et}Y+9x4yn;4>w(czr0pJ!FEcvlfSAb@tY0rsn>jcJx zkro^RYC4*RC1Mp>4i;3-=!%$B$^`Mq?-8)Z1?^m?ki+tMSUcKbgt*;&d5=b5Xuuo_ z({{5kh852mcvgN%20TNni|W7mFDt{=`6)@@4QSuBUxUagxuHeN5e+XPc54BB_ZgH; z;5f4>1{E#oaO&PDI(es!1Z$1)nO_CidcD>dtRsuV0GvP;#sk8qFd4Z&2^GIj;kiR} z;{$5CxHe!DY|6NexR&zV_P<1}FGUNhQ=`jcO9;&$Pk~igbn(yxoa&0nU+RrOI6Rp) ziq)qj06Xd*GOtquD|LepH<0!TLoMsmq8Ro?0)%u5lG*e?3I^k{2df+^fb=3d+0z2t zh~4x{e2a@}b&F|Kc|w{`=>Va-dsryDeNWgS@=UKL!HDqzfbF{bN`?N>hVJvjAg1Y= z!mZi?kQZE4pZ@V|%e%!-Li!yw{=J&jFB|5h&EsquVU%M>)s-?ucb|4X?JIh%mbL}iNsqSXNV)smrfwQ3M6SjghBW$4#d*LymO@gafD)_8PNx= z_v?X&fF9ei*wc5pYN|xX3g493%PD_lwgWrXmE?zlNqN0qvWV2uvsJ$6j2~B z<2*(@pn8^Y5Dip^XjaS&u{-rV{Aqb5VWZd$8Cwa|1g@Bfh)~m(QF)=b zQFb(Cz8HQo;_-+!`RP6LKJ)n1bMBag!0mqbHS?JF_@ZHE>wLnas;Px09kSXIS=Qtm zx0T&I)^xs^zWfafG7>S7*@dtGbOGvcDN(^dlSvr+`9_-xU=|4yO-N5atR@X7sryg` zH4Tb;a~uFDfq&S_<0r}N;B7Ynee+M-!JC_rxiQfkqlYS@$INa_$3MNli^I&kR!512 z+q1*Ox%S#GNuSfH6<>9(cLB!|=)85TTh0TAnzr2Kg;j2p?CAiD>5TG|-{<{;R+$_NCOv zh-rI#yEimv76caEiU&VT2?erb5~>Z0OB5}TQ$4v!(%^jXlMN6B%bJX&A!4vpWZ#;= zvb|*AV+=ZFdoSKZ(4Gz3YukzM;j~yYoI5n!7%PJzZBI(1C9mw_jq&Rv)qst-dczF& zx1zT{an>W$vA#Wd$a-O$=~GWgH?LBYQ0+L0JQSa*tQpP*y@qtO9-MtiGMvdb4@j5u z3theGw3zNiQfV`W*%lVf=CWChnZw(Pm?N9SVW_;={8L&tV8?-Uj@=yP+UFR9!hoT_ z59nRuXIHL&9p6uWH7t8};YaS=Qx36FUqW*5xj3r*T6W@e> z3SnX6Y@8fKGLpXHYbwlM5v5*Rz3-m2>s=lT5?z>V=Togq$GF01{IbX;hJV~_BnI5P zG^maZwR}wxe1cmDlN;vK<@BQa97UOB57I=wWkH)^Lo^vcnS^JKD?IDA@7 z@LyF0g^%Vx*O|i~aRyR1GJciZd+?0TScB<}G zk_e3m+)$gh0SG=r+tf^F2akToH@oR(kj=w%u6ZEy8RH{|7vIHzT=72$8XJdc8Wyu!rmY6o0gqc1sB>5j>2wLjcBifiK3OM8F3PPqS1cnAfzz zcn&$s09nR_V4v}k1j-f*JS1BXs-ORPWcWm#tg%-K<||wnOC22kHnTpe{R~Jk5*dM% zTr3nwksoth5@L;&8&5Z6x>5B*p}BprLU!gggL$jY{5Uk>?v}ebcx|80i;H~?1Rp( zG*E%ht*=Ep0otGR;Cfes`Pa0HyVg}@8wF3O5C%ez%rwTbqH^p&RmORZ%)&$A<*ONG zC-+=c1z`z!%MlXZfTP&$%Z)YBj3-ch5gt>k)f?0i3TR zFIYJ^{&p5N0KqztiQnU35D6+9uY6quTfQrG!5Jdj@43ek%vAhRQFoIQIZ4Bp)gNM6 zC(sPnjI)b8ZZtF&f6;}A)46fdU{%KvyM=GDP0ZXs@wgp2G#&f8;Gk=Er$IhDYi8N^ ziz@`h9bS8%)lO&OB!bJ%n%U1Z|EnaT)1Thq{vrAABQgZM{Ln3~beN+E1fYautr|v# zR^-De>KAwU`3hy+h9EA}0V5$B05joa);d!S7Fnlo6Tzg=>9aUO!>ki(%GGFsCT=RG za)*Vuza~t-XQ@VVlri@2QN?uFo6F*5e*mszMPYn9I^|*rw%8!;chi!$?NMy z{u|4d;4y&0hrYg|4w?Qd#MS^jSLb6KSg{cqe_?sUsa)WsA=P_{_34FkDx^2-Fe-e| z+?{XMe2V6EU_+xoE`acnCezD;x!N{wF5M>RbqYlJ9^H!m+8?LuL>>e027d>)6Wxy1 z(PS|QiHZ9o{YJ3j@7;~<0VL6ILa#YjABjgSE$z{VyDoQVM^}wMq~jXqF~q1?j~c*F>$Q7zr%9b2=Pd(c1p;qR`-w}#^o zYy7VCKUi(QooFREl0Ws1_f71w^NDD2$F$G?oPMwAgOF)Ryqw2jd2*mb&9tT%D0&V# zDL}*9hC>f|@}gOiI`z@c9FXhQ(h_4pL^ax<9ynN$moq+C`6hYkzN_JRlZ)X3vEaPWCG45xr1VB0%05lzeLp$%p!LcKE8Af=79;G9%-5;E zXNhEz?m>}&XudsOf0D$<+B-DRR#AseCrr0<+M@U}<#FK2J`1{`z~=lku_ddn#8SNc z1-zT$@4jCmpfS-*;GG`s=Ic~rQkYDU>El8QQ>LQF4r78OC|#IsT?!SpW)e-i3*WyJ zN@zcy03_}gW!Z81+5X+PAd=<7^tgkHr?8m;{uJ~ndOby@3@evKxlPWCN{5Bw3knE6 zIciA$e6+wG^$zIZ-`>rx5b`3P5Q+4$J?7R|Q?CQ{LPrY#xR_<(AsT90D1gt>{D*gc zw%Ed53?VN%CuGa|vBq`OoOh|74D9=^(c<`cW9*MCVXJdNxMkY)_N{VuaLIG0wct$X z7DWn_a(w=lfqKd!FzDzcJ#Ht;5B+Dz?*n!JPfU)6ROQTmup2r(lW4<}C zIIhHa3Noc}niMN~Fcf+g0gD@cdpHXibC4|vhC_wQ*5yu3tnYlD_S~Lo(R}gfI$XKC zj6|r6OkX8|rl*FRCmsQVOhyn@KyDF7pmrWzA6nuW(@8OzL!k}~%(-^uG7$q#ji~oR z92Nv12}JT3igI=PA+on26#9TEh!!wA@Fw5BgWxC`f3-&;y3P5DJl{<={GY1uRxVj)eD`Lb`$sozccpf z_`mPpYX{`aiz}(2HY|X@>#$sowD6*(7@#i)FPL2h3g~&M-hF&;nJki5aZ7_pvz18O z=%`~@eqDv+LRq0k>(qz)Rm(A2I;C+?8upbLiR~LvCu_+eI!4av-L3*_CptXr)T<&F z+YjD(i}5}bKR@F@F!i}?&N_{UA+fOu1UauXyuB@D%E-#EWCsMhXw>eM_4BjYVV@O^ z#t$kBhL87iVa!>4jgyLqFqO=5enb!+f=9LgNcz0i*6R-w>N_2ToEE8uIA%ZYtx?{M za_Yaoy-}Srn;D5`g;M&315W6U#c}+3{gEHB6PK^=aBlSAVyw)GCD&pQ1*E{FX$ZjX zR!-{EaVvE7aNW$NN{k~TzrZ+n9cl^G5sNycz z1=S>2R>*~9UiTeFgiVACLe69)7!e%ym;Cgz` z_lJl)TbXOvC};^%?bA`6V;#X~AcFd#{#fzi4@rCfTQP{DV~YfN(jX00!i((Z2C{cRwj69vzC`^FrN0SazTHWx21yjE5eLYt=NEpd=^?F)f%w||&R8Km zgw0Orj2i7Ib(}}#-)6W>ez*dU%8UGl$Mj2RMsgbT*K0loM4iz+SK*A~gLk6v)Ne-zkdSP&8e#ZBz}lS-9X znzj`5;(q((1t8xk91g^lG-rgwuv{=x`nF{6bqZP0RUOHOLJkir?h}+?N@epB%lT3k zyjR8)j6uw!z@Ssrj$h#vI)oBO@k*kZ=unB|ZU{PixT;Ut73M=xEV5}hXNG`Q6IfrI z%IVa9{z*R3q)-)+g!gEhWLRQAG2RiE6vW7dPt8LXjL-%{kk4}KK-#(y%8Mf=-uAdD zx&14uSQ{O(Hn~(KeR?YOi`S$%?;IsKP$K1%34?Z(j&K->t!9v$6553I4PrNd*OcD| z_x)ePPM&Ufs6L12v<<@%co**j8&nL0`;LO0F<)^FPSqyx78MBcg)~6WI3Zj5)K47| z5qihQe|QV+HS{yITkwho*>1gIZi^W#UdQCcY{49$9;zAZ(*oJzSed-=nWaVaJxus> z#Fc!2`?5r@1uwXtF;f>pF$ruBF=-lmnL&tH^@^bz8?my#KUqFz z3yE#T4btLSUUs`y@s)cFxGMmH3BNsT!}UjcdK+d-D^LgDw_hQ2#{x6d6x(RqepB-( z-l%>ll5vfU`VAkZ=#k7h9et4@*Q@y@A190(N`cy0LGXNLqMKj=B%6&8$GvuIjHF5U z$`S3TnEZmhH%M+=rbS5*jth{6Sms9Wn|9Xz@M~|%6y))%<)=A0?kGEevHttO8Q=nz z;mj}R-B(~4e*L7`{rlPhJ@cZc39w_J?i;qqKN9pnCt_()0_5u5-VZ}<$euhp3xVZB zh$b_;*#vf<_ghPNZG?l5IDXbQC81BlHAAzuT^rsITv@(=k;j|iMPfyX`N$0|8)3Jw zz4s958-f)G<0@fSgNz+RRIiO4rT)!f5M(d(7}+ zV#&$D*8KA6j-hHjZbFuOP~~Kz;^Pq_Q)_EPR3@F@HkZkxml z9!Te(*u!B6!Gt&1tgbs^SqG|vF$|DseCQq1K)KYYY+DvneM(KNzR_64J(y{Om=clg z!Of^EX{-U=-mSY};*4TPnI7fJoU+_0H!UW2FmXeyRz4C@AN9EPyK2W2bJqyQ2J56M zGlVObu9Nd46~TCgX7)(5&Zp!}{!=X71$@)!MdCt2TFCw3XEY--dZ82e*pdH&&dFMT z9sGyUdocSW8}Hu<#Rb2cacDF>Gt1w(6vLTcU8q8pu)+W^{xG~=z|P~YnLeEWRvvv1 z=MG;!Ean!&R*p!%rgDf^wCS{wIE#u|svcslS3FeFUyVp8`t+#W_a?+V4C0_LqLEey zaY@x~Pfk>4Sl?l@RtNr+y{lGU@9qDmR)nC;KX7*CL~5vDOgP9_O6C>yb<|=e_LV`A z#p4A$E)_9a#_Wo!0L~jGp#)5~LBK#eQ1*lCLIwuF_P!Z|^sN=*E-_2UZvpOnw zhEF|(aiPxOLdkl(boF^*2&dVI{+!Z_DVn8O$m$aa;u^vXw^8f!?NqCFq+534vaREY zF`0rh`>Sn%jpfshP1X!Y#5IrcUPU^{DbS1U%i@Ivpz9mTw>_2FWX0MtXLgO9*~Ij| z4aByiW_D#$;m51MHK)uD`{a1B`}oq-cyT!)Id(>9UxgO~p}**tjI8hrQQS3o*>G2L8x2)qDQh$&-U zC`F5LuNfSmDkOMXyf;qzV?*=4^AG&~L(rjM*tjw~zGSdtI=b1%r_<%(-1hrt&x@56 z>?DdkPtu6dlTUHGi(*%-JO{`l*eL5Puvt3=8I9(iXsG+Lk{;muwK$Ted#A>%rQIu% zy+Yb8F%neU6z^V)uu^j{6Yw*wh!yEIgC3ij^gF(-1RX!u1pfC?9A5MDUiUyputESv zjb?oR0VMS`@tOeo#_)p50N){IWhq;X#I8V_c9iwD4QkC89mc>EVr6)--1$~|wa4Ea z@7pNbru_^}*EWZT_rZ^ow0wYAyqX4|gK*sz;7+io}BY@6@h@9+H^&N*}DnR#X&vS?l#JR*h7 zu{W*<2tAtJfAAjP>|Mj#i&lvi7dwHuU zvvv9DkyLw4+e+LK`p_dth-*@04-oRW$Wt9RtddC;lI5}I&kG4tghh{#)%3zM*gy8yZ) zb#`yK1?%?as$y3VTky@%|Gj_J(j37-G?4##(@k1aja#+;&MP(Wac65sjQFd}l|feL zq~C;o$(Q;sHQ?cx^xeQxTmXj)ArdOzw*g(mYGw)d?F;$8GpM2_uNa#aEAqc*!2%;b zp;qPW#;{_`{&LZ0_jPSSN!#Y@n#t4X3!F>E?@PHr z_Bmv!|6CP1^w1UIW-@;j^NNv;uP|GDK9Z>^&}?wl7Lvb?{2> z5X&}Ky1yG|!%C-kov+|8v?CZE&Qv=Zf`&rPC$}(tlY|*=@p6vw0jEMEs0o@uHd1<& z$5ilWJ9H&F-2TcDV(fU3iRj`B``5f5XT-$lBBOtS)lK5(JxJ`S{H7sp^v}qz1J|*L zP{gvGHxCg|qofnk4=A_FlBAA;Qac?CJ2I~Crwey;w+8BABO+zx3|^yBb^R!2baVFk z84X~a$q+acKKS`14CI9OoaK%H1oAR^*~;{aFJ@G(D6HrJ5_JLyuko9WfjMf5fA9t_pXTr>#L5u&vJ6$tAa5BGkkwh(tvlnx14>G@XNdZ|t47B>n~; zN)57qk5+tCJBvg1T<-DWEdi1Kc&c)Dz6A08dyR=CVgwCKm>1VM?OVfhzQni7K=sV@ z>a~VSX0KWkoKR;ysX=tl*LlHY6Lue1>SK**FSlMazCU$l&?l~O5_d2LK2lqd(HFkR zv0m0TZa*U?-W_h_sY@4Ti#0c)jAFlJ4&^2(*@L@PLl33y8yzGLLCYl4h;JwPVO7!O zYc8O~jgvp$%?2C{B+lRL#?Fub5TDt7qpt$izybcQ9icP;KHN^-i7QC(024J(BRGu! z@x8)!;yJG-_mU-OMWzcEk=s1FGB?PPu$|W~onLoW*~^HLA(ZALTO&GK8SCtq)(Q(Y zNeHpPC07sOSg0UF6VdMz4OeD;**e=nIFP$Otz??QuJ0u2x%0PBY+BBBN8DHI_jDp>Bvl?&j?zmWZN>FOWWHnmJ?Z#XV-F(*<6f9|c) z&-fc&6_qa6fE2`?A{?>5v~kMGgK8~Qx(GA)*2^bAu2d5(ESYO{4x0|5;V6ETtf?>x z4xMgJ=LC03Rg7{kmfWtmg;j$%dF;&Sa$`tBo4nBs(I(XuRB!m4CbyjgIf9@2Q?c3a zgkh8vE#gGNE4-Lar%}KxCeiM1%qMq8Vy|Dr_ja&2N1;rt*-9R?X2^1Pu0lk@md)m4 zeL|hn)O>{W$Ud|sH@VcVCf`=i28$|G2mZqrR9+nr381?N$w*%=#v$@ElhM-WRgmc0 zw15(x^^oAN^f6)@$`_eVXlh+mQY6iD8bZ&vdTC#2#|Ys`kIXI$-41ckys$oP$0v%F zn+GDrUw)oCXe2QAUu5nrXDkh1|0NA^2$eUmc2wfDs=Y9W2pzUU1U|(=E_FjFxVjnf)-V z0!n75Sopj1+p7qQECF9{Nzxd#6dDY)u(m#kDCVss z8a_R+w5rFXS6$prI7&JzKjozR%yB-d)k@C||6uVe#Ana$a&%>^RaDJrCy->T>EgW> z88BdG&c7LT8c6?;5_VwGu*xgd9#d423#u`3OjJq3X*4RTfhYetwz8PU0QjW!-Y0+m z;U?sgQs3=rL%3lp>KU@KF7(P~2UA-tb+}?U5*N4_p7!TsRYvd85+P|4lgq)#;vtG5 zUJNe@5I#U)CMe=yS8$cg7DA*5z155Z*4cAEM1wRdRv1TFVz<_enH#S~&N>BenH42r zFwe>Z<;G+!VPf5{_4wyl-DRL?oK&pZ?*si>*dB+oM*P|$1))x)$44{8)ESsRR0?tH z2A?YnV&isqheLM7^Pb&!>}^vR^#lp9gtq;0mA1M#z9bArN6E_%CUc|L&ivfojP_Ev zj_uuB(K}r;--wT*^u+PKuejvlIlH$QgPu*yGQepl<&FjwuMWR6dTB@l-p z^dg3=^|&^SOQSQ9E7l-4379An*bB28K`G@&#yHXWq+lRo8sh}6_x+>WR^p}d68yuE zKQM**tJbMgbh|p$->ct;8A#)}qU0wfkCqPvqDzj|e`VI$$0DtDIVRLLgmh&4_z=Sd zfgzBraYXeg=ekJ67&8!A7(XU$h$3{@>lb1I)0u>q{ONz7|AXm)Oxl89Lg{>Eh#rGk zkr}3~W`tiorcDTaX;YbX9IQf%Cd3|M<~t!M?K?}@k8^)%>S6zP$d)|e&(J%|;&ZKR zJp=lw$E;i@!QQ2jM=sc>Y#G15_b5e%iFUw7t7aQo810Z;fakEicA^yYN}SY zt(UJ1JuhES&Fv&b*srF1!EgBq0<_=Q*|8$Rh_dH%kv`+BIcq=O+oYbmVHsPpQDDSh z*`)Rspv`G$3Oh3{b<;G?oBk43@LoaS- zxTdOhow5lE~} zZ834L`#{A$13;l3Q##C2pPsS>9cJ2RcEBf_eTZSS`;U|Hs?T?OAR;>1G91k?f1y)A zH)N1}k<{zvNv=Jta~~(fMw%ssT;UHOS9GDnl{JM zAhN75yFYAb8<(KG;1+XD~sgOi4bkCU1)SWw-ky&xE7S%MMk`D9iXRr3JAI zZ4PXqsi3X#1YD7ObNGHx83$E0mS<68IER+1o; z8^fL9mw9s6r1-HJJEFxxTOlWgw02LF-jk#P`eP}(!u(vFm-AQjwz<(0&4_YvEg2>p2Ob#9>d4yhj&g;4LVUhs+BT=Lx2%X%PZ#1o|b;$iH*smhJU7n zn$>S5P4Ksgp^A*O;Iz8sq{z7|7NF?T=ai6cDAAYmO{V?4KOdeo0LoE+tSh(1?M*fX zC&SIB;3ck#TP8&X28Z&QFwj3d_lY0O#*xB>4&Q?#Ec06=WV%? z@Z6qz6m3X46l!-Kig{gJ5Q_Pka^yyf@Dsy(dnWrF6#kN9)yfs7NQ`L58eB4hNSl{S z&hUcWRTzWr3rO1Lie(C10$(`MGLS%hMT${b6)yD>e4ky0Iy`G&pp5uejF5%h8~DD6 z)EN{C;p7N1IKBFGKU0d$=7&$RN`s8!-TCjHwIVKWKW+nch!+HBc6Ufs8ci)fOCLt2 zYa0eX$PCZnMZX$#2g(V)D4=98*$CB+pTm1iTkwYsk3|5ArL1792Ifa+qH$Ccx3Y2A~e6dK+ja zP*NJ*02f3qvPS_5((R|#1a3nktA7E zSF|4M;_wt?UehPIJrb^r=kF&2agL!<&& z{P6#D5m5sOVBghf@i6noqeOGI^~&%Bc%gI-)ZtE#!<+BUpoU2vRRfW;vyhX6n9ET^Z~EHr!q1 zS1jsC--h^dTFmc=*kZy0d2}XD&BmcaEtW5;pIXmYdd2U~4IupL-i#68^*9Tumggc) zD~MHw!-okkJFMjoxQIA}fy36YrYw7EtAWMEcn0_)s>egmuqM7h1oF?)1l0y+^M@wS z6ocMO*vswmTfYglw>tBH)`1fJ7fPG2L_<)Z=-w!QS5_vJlY;hE$> z9mluFXtuuE;`v>0DF*l9(1e>6>G_a-kWVkjza4O+DoYZ$_s)6YB~EuL9XCMA5isz{ z8Y*bzNy5s+u(P-nWQ+WW-N_~XaihQ5eXX$@X9{intLNhz)x|32jLP2zi0N#D7UbH2 z*0p-srg{`V+p!wslaZnh5I4E1^B%W0U+>rvDOyV$Nt06*xckBRx@|sk&+~Nh6jW|T zbiw>_wQ4hJDBL9Z4ZD0%ZYzY|jI}3~RXg0qSojMk6afn8x+n>cTm8EUNb5mmcu7}q z#WyyhTD^25NYqdG-q!oZHSjwxbP`FlnB_Ti2=rvy4X5S@9F0moODVR++Wo=Ck}x@jv~peBbmzPdXV$T)I9(}{zt??Se2C~hQ5mje$x(XHR? z#LFk*^i)D$+wdCulbS<4Qr^hu_&6I$Pd8k0i`Q_H7wa_Bm3-3Ot4Ba;YWZ0OKm)#u zP5zGUoNSK$iMd22WcoG^EGb^1E2S&2n1ND^Q=KbD@{;S8gjWhKo$h>l=)OS-m)@)I zI4g_5XL+>Qj@oQ3e~NrvSd*@b%p4k#v$K8o@Gq6FQc1}}s&nvbU)cmHJ>5Ns&g3vq zCzVEKQ#Y(|P~loek70sOc;0kA?R=p)kup>9WBxFTq9fmL;Ea%?%6ZJ{UwkNJs=xfC zi1W#r^v91$O5lAH>t)dVMlixCIkeZO8HjQcN^)acJl>A4QZ(`F#2@MV0HoG=xr41) zr|Y`M4R)1qwPutwEpOEMk0Xg`-$ExovzR+p;(SDOIP!>&c6Dp^@FL%ol?hro42t)6 zhg_AaGRJ+z=UkB37h01t92Mmj# zIQp3h8EBacnVI3B(Vi&Vt5ARTC9gZECQuY8hT#N>!1ppSnQhq=ZU zeIhDyahCPcC8Cfe$5tePqU9d_Ufa7}11p1dWo9x0Eb|%6V=5&Q#^BF!jM_~EG~(A5 zfBScC_!`gzaC}c?ano&}?KHe>Oic>U?ZU9?Kzg0SW`hhWwD$Bhg>n}r8pzCf-Ch}T zFY9D*&zd{ySXGWsj6F}Hc={F7Z^QqOZ@ax-yqbJaxZsZl z2p+EG4l?4`$8ZGE{8Uy8eeBx&K&b=mMYjdHJeze_(xzWoZ@zuj>f>(kkKOd| z)d?CLWp2f^3~3GQBzUi?zIZ<`C~9jknt6Wj_lHHJvB!$zhhLqHd{!QgXqQa*jU}wh zz~2?~#ZOR!{zh5$f{_{EL}B%to*VJu%aUZ*LT|v?N1aLBqfM%6mGzIgsX^ocK{S3) zvL=ztKNp~*8uI@AwWb%|_?TkHC0n-CrYUTNHZeN#4ASNp1!;5yq2??iu2JHMz)x>& z5>6eXyL6xxoTQ$^_II4ku&T<&HAbt6zC{Gq=ICGxruc}|FWc_b_OpwI+iOpnP0I=6 zeerFu2XSK4QeQK#FOMe4hVL$T{4zsj!>22irsmwIwltLyjcH#nu{`6EFd8l-tI6nj zu<~NS9*Q7N8jE%X%kEC{<7k2%Xu=7R|06(Ouwpm5XjCMpx|xMj{(=-}IP-6#Bn{gr zs#m$U^!U?o!D&|6ve?~$&qeawi0r74{wHWjUNP?C8RullJI)&g_SD-lCG~!%pQ+l1 zo7E}asvyEx2j&$&=6fH>(vFFOD8FVluCB(PKsZk@qZelQ!U-;U`b zUi{U+LtP=p%V2LrRp`ngD+riuIxfy4;%E`7u?o5Z(~Bi6Y==q6YZb{qp4tgxqbdMtbaf96Arx&&egq&|KziDGLG$P zGLHGVH`lp_@AT8>tEleSmCtFUds|JO*kL9=#Kw$!^1jC&q9<7JUw^LUbK>>?nqI1` zZ!9-?rpZ;n^|W#NkaZfeR}qu3JXD=zx3S2vKC2ju5I)b11wXa*4H*(|YxDDU(H;s% znTx=F-PH#@)rgH4t{XsxarIURQTAOR~M-#uhcH!VxSX3!) z3jee{xiTh2)DWwNhsA4J%$YAEEg&=F1eYmmu&3Iv!6q$7fPPo`o7CVtyVrUB!)mAx zzJ2-_Pn`Pw$3IuzK&*ZVa2ZTZTCaqsm-tq{A;o2F~fVeBm+VpOh}Us}G|q3WV|E`>>Kf`^A>Ko0UK}9tfSkCl)Tde@bR? z-)&JiKp8Erq4hK4buqn^1VB_VQuAH~fSkPszL>xP^542&-~cAi`_s3NZYb9U;J8ac zT{AXNLs}XHNg)S=q5Z(9&(b61j<6 z_B85J63isJA&Xhn$pS(p#5@Vk+nk?p?%8HE^@0AH+whE#3Xt(b9o*94&JPif@lG`# zJA)}>lU81LpH@VnDOC9ID89)!;fGD>G7>$C`_{oXP-akYNUO=%by!8nA>6}Ryk6Sq z?GUnNDky_HumYEDthYFU(gMJ_@(K3_<)VGzy#D&+mH{W3V^NZrKdut{KR4Y-t{PU3 zpR(l7QaUCdwUmw{7b&gnOc!@#jpF@O4c?_s6+$MSAR2P}ileapq@XCh42U;g?Z1mh z15B1t)DiS@ibG|h=yrMJIGT)O)J3f-&7HQ9RC$S{zT>@>k6)j;WFYHbB>z^iT}(TR z?-OSWp0+pFqSFk;AmGL-ddR%_Ea;;ue0H5y(a$y~q>jz_8$%8sPS;DwW3G2(BrUid zF^VkGsNr=9GI_@&b%)e-;s12&Wc;(;83}6mGe6z{e0}Hr3tPik!;e;*VLsjz#o`(< z#3Y7g602RxX?P;hu@bC>B!z=M;YVSGdfq=F-6j85xzlW)MTbQb4}`iJj{&@B=`b;l zbjyACeWj_g@w0HmFvZ%bg&h)h6wC6Ty$a}MTRDC(@7B%MVssposY~DcfWuHcW61uY zAJ#V63*@c~_6%4vQ$)zgv z&{Mr-ydRu#0|~1O{2v_sQ+#$OuH*-WH4t$Rq~X5@YvQ3pNVikNd}O?!4PxHy3_8N+ zTg4hgFW_3Yw90cm2&`o3--J z_NPrg-w2!bV@%%nMm9>%aS^rq{-10)=g^PHs&PKgB9jI3JG}W|ol0+^BF3hH^Y*m^ zAaC-4;lieMWZrz;=G#Wb?**yvP z@vz%FPflm5fG=2L{W9oP20!Yo7K)?0PdRpQXdud!0GA>!c06cI9PfDPb1(wd*X9YZ z`ULXw77p?{Z%6+QCmsSzC^r-aoC5*yy?J@-OOroB0-_MGOmBzBcG1(nH#roWP9NU9 z4g&6R6+;7MbI6Uh!jlNeP%xkW9E-mcn2Ni+O%KT?SyL0}qsO1xDXR=Zcl;(={Imw( z#klrZ=talp-kn3W#VC(BH*RyWsD}?OG{tNE6MOdcx${|Qox?sK*DR&2m#tD-%nIV~bB0Hn2WN?*vT$B62q}=LsqQ