Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add UniformBlockData & UniformBlockBuffer #1174

Merged
merged 1 commit into from
Dec 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 59 additions & 15 deletions korgw/src/commonMain/kotlin/com/soywiz/korag/shader/shaders.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
package com.soywiz.korag.shader

import com.soywiz.kds.*
import com.soywiz.kmem.nextAlignedTo
import com.soywiz.kmem.*
import com.soywiz.korag.*
import com.soywiz.korag.annotation.KoragExperimental
import com.soywiz.korio.lang.Closeable
import com.soywiz.korio.lang.invalidOp
Expand Down Expand Up @@ -1038,38 +1039,81 @@ inline fun FragmentShader(callback: Program.Builder.() -> Unit): FragmentShader
return FragmentShader(builder._buildFuncs())
}

typealias UniformLayout = ProgramLayout<Uniform>
typealias VertexLayout = ProgramLayout<Attribute>

open class ProgramLayout<TVariable : VariableWithOffset>(attr: List<TVariable>, private val layoutSize: Int?) {
private val myattr = attr
val attributes = attr
inline val ProgramLayout<Attribute>.attributes: List<Attribute> get() = items
inline val ProgramLayout<Attribute>.attributePositions: IntArrayList get() = _positions

open class ProgramLayout<TVariable : VariableWithOffset>(
@PublishedApi internal val items: List<TVariable>,
private val layoutSize: Int?
) {
constructor(attributes: List<TVariable>) : this(attributes, null)
constructor(vararg attributes: TVariable) : this(attributes.toFastList(), null)
constructor(vararg attributes: TVariable, layoutSize: Int? = null) : this(attributes.toFastList(), layoutSize)

private var _lastPos: Int = 0

val alignments = myattr.map {
val alignments: IntArrayList = items.mapInt {
val a = it.type.kind.bytesSize
if (a <= 1) 1 else a
}

val attributePositions = myattr.mapInt {
if (it.offset != null) {
_lastPos = it.offset
} else {
_lastPos = _lastPos.nextAlignedTo(it.type.kind.bytesSize)
}
@PublishedApi internal val _positions: IntArrayList = items.mapInt {
_lastPos = when {
it.offset != null -> it.offset
else -> _lastPos.nextAlignedTo(it.type.kind.bytesSize)
}
val out = _lastPos
_lastPos += it.type.bytesSize
out
}

val maxAlignment = alignments.maxOrNull() ?: 1
val maxAlignment: Int = alignments.maxOrNull() ?: 1
/** Size in bytes for each vertex */
val totalSize: Int = layoutSize ?: _lastPos.nextAlignedTo(maxAlignment)

protected fun names(): String = myattr.joinToString(", ") { it.name }
protected fun names(): String = items.joinToString(", ") { it.name }
override fun toString(): String = "VertexLayout[${names()}]"
}

typealias UniformLayout = ProgramLayout<Uniform>
typealias UniformBlock = ProgramLayout<Uniform>
inline val ProgramLayout<Uniform>.uniforms: List<Uniform> get() = items
inline val ProgramLayout<Uniform>.uniformPositions: IntArrayList get() = _positions

class UniformBlockData(val block: UniformBlock) {
val data = Buffer(block.totalSize)
val values = (0 until block.uniformPositions.size).map { index ->
val uniform = block.uniforms[index]
val position = block.uniformPositions[index]
val size = uniform.type.bytesSize
AGUniformValue(uniform, data.sliceWithSize(position, size), null, AGTextureUnitInfo.DEFAULT)
}
val valuesByUniform = values.associateBy { it.uniform }
operator fun get(uniform: Uniform): AGUniformValue = valuesByUniform[uniform] ?: error("Can't get uniform $uniform in $this")
}

class UniformBlockBuffer(val block: UniformBlock, val maxElements: Int) {
val buffer = Buffer(block.totalSize * maxElements)
operator fun set(index: Int, data: UniformBlockData) {
if (data.block != block) error("${data.block} != $block")
arraycopy(data.data, 0, this.buffer, index * block.totalSize, block.totalSize)
}
fun copyIndexTo(index: Int, data: UniformBlockData) {
if (data.block != block) error("${data.block} != $block")
arraycopy(this.buffer, index * block.totalSize, data.data, 0, block.totalSize)
}

var lastIndex = 0
private set

fun reset() {
lastIndex = 0
}

fun put(data: UniformBlockData): Int {
val index = lastIndex++
this[index] = data
return index
}
}
35 changes: 35 additions & 0 deletions korgw/src/commonTest/kotlin/com/soywiz/korgw/AGUniformsTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.soywiz.korgw

import com.soywiz.kmem.*
import com.soywiz.korag.shader.*
import com.soywiz.korma.geom.*
import kotlin.test.*

class AGUniformsTest {
@Test
fun testUniformBlockDataAndBuffer() {
val projMatrix by Uniform(VarType.Mat4)
val viewMatrix by Uniform(VarType.Mat4)
val color1 by Uniform(VarType.UByte4)
val block = UniformBlock(projMatrix, viewMatrix, color1, layoutSize = null)
val data = UniformBlockData(block)
val buffer = UniformBlockBuffer(block, 2)
data[projMatrix].set(Matrix3D().multiply(2f))
val index1 = buffer.put(data)
data[projMatrix].set(Matrix3D().multiply(3f))
val index2 = buffer.put(data)
//println(buffer.buffer.f32.toFloatArray().toList())

assertEquals(listOf(0, 1), listOf(index1, index2))

buffer.copyIndexTo(index1, data)
assertEquals(Matrix3D().multiply(2f), Matrix3D().setColumns4x4(data[projMatrix].data.f32.toFloatArray(), 0))

buffer.copyIndexTo(index2, data)
assertEquals(Matrix3D().multiply(3f), Matrix3D().setColumns4x4(data[projMatrix].data.f32.toFloatArray(), 0))

//block.attributePositions
//println(block.totalSize)
}

}
9 changes: 5 additions & 4 deletions korma/src/commonMain/kotlin/com/soywiz/korma/geom/Matrix3D.kt
Original file line number Diff line number Diff line change
Expand Up @@ -119,21 +119,21 @@ class Matrix3D {
return this
}

fun setColumns4x4(f: FloatArray, offset: Int) = setColumns(
fun setColumns4x4(f: FloatArray, offset: Int): Matrix3D = setColumns(
f[offset + 0], f[offset + 1], f[offset + 2], f[offset + 3],
f[offset + 4], f[offset + 5], f[offset + 6], f[offset + 7],
f[offset + 8], f[offset + 9], f[offset + 10], f[offset + 11],
f[offset + 12], f[offset + 13], f[offset + 14], f[offset + 15]
)

fun setRows4x4(f: FloatArray, offset: Int) = setRows(
fun setRows4x4(f: FloatArray, offset: Int): Matrix3D = setRows(
f[offset + 0], f[offset + 1], f[offset + 2], f[offset + 3],
f[offset + 4], f[offset + 5], f[offset + 6], f[offset + 7],
f[offset + 8], f[offset + 9], f[offset + 10], f[offset + 11],
f[offset + 12], f[offset + 13], f[offset + 14], f[offset + 15]
)

fun setColumns3x3(f: FloatArray, offset: Int) = setColumns(
fun setColumns3x3(f: FloatArray, offset: Int): Matrix3D = setColumns(
f[offset + 0], f[offset + 1], f[offset + 2], 0f,
f[offset + 3], f[offset + 4], f[offset + 5], 0f,
f[offset + 6], f[offset + 7], f[offset + 8], 0f,
Expand Down Expand Up @@ -419,8 +419,9 @@ class Matrix3D {
rv30.toFloat(), rv31.toFloat(), rv32.toFloat(), rv33.toFloat(),
)

fun multiply(scale: Float, l: Matrix3D = this) = this.apply {
fun multiply(scale: Float, l: Matrix3D = this): Matrix3D {
for (n in 0 until 16) this.data[n] = l.data[n] * scale
return this
}

fun copyFrom(that: Matrix3D): Matrix3D {
Expand Down