Unverified Commit f5b0a10d authored by ApoloApps's avatar ApoloApps Committed by GitHub

Transform Matrix* to value classes (#1205)

It transforms Matrix* classes to be value classes so that we avoid
double allocation in these simple classes (1 fo FloatArray and 1 for the
Matrix class itself)
https://github.com/JetBrains/skiko/pull/1137 followup (at least partly)

Fixes
[SKIKO-1140](https://youtrack.jetbrains.com/issue/SKIKO-1140/Change-Matrix-to-value-classes)

**Next**
Follow-up PR in Compose Core to make use of the internal float array
constructor to reuse if coming from another FLoatArray

---------
Co-authored-by: 's avatarIvan Matkov <matkov.ivan@gmail.com>
parent 59642ebe
...@@ -3,31 +3,32 @@ package org.jetbrains.skia ...@@ -3,31 +3,32 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.InteropPointer import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.InteropScope import org.jetbrains.skia.impl.InteropScope
import org.jetbrains.skia.impl.withResult import org.jetbrains.skia.impl.withResult
import kotlin.jvm.JvmInline
/** /**
* 2x2 matrix. * 2x2 matrix.
* @param mat 4 elements in row-major order
*/ */
class Matrix22(vararg mat: Float) { @JvmInline
value class Matrix22 internal constructor(val mat: FloatArray) {
constructor(
m00: Float, m01: Float,
m10: Float, m11: Float
) : this(
floatArrayOf(
m00, m01,
m10, m11
)
)
/** /**
* Matrix elements are in row-major order. * The constructor parameters are in row-major order.
*/ */
val mat: FloatArray init {
require(mat.size == 4) { "Expected 4 elements, got ${mat.size}" }
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Matrix22) return false
return mat.contentEquals(other.mat)
}
override fun hashCode(): Int {
val PRIME = 59
var result = 1
result = result * PRIME + mat.contentHashCode()
return result
} }
override fun toString(): String { override fun toString(): String {
return "Matrix22(_mat=$mat)" return "Matrix22(mat=${mat.contentToString()})"
} }
companion object { companion object {
...@@ -35,15 +36,7 @@ class Matrix22(vararg mat: Float) { ...@@ -35,15 +36,7 @@ class Matrix22(vararg mat: Float) {
internal fun fromInteropPointer(block: InteropScope.(InteropPointer) -> Unit): Matrix22 { internal fun fromInteropPointer(block: InteropScope.(InteropPointer) -> Unit): Matrix22 {
val result = withResult(FloatArray(4), block) val result = withResult(FloatArray(4), block)
return Matrix22(*result) return Matrix22(result)
} }
} }
/**
* The constructor parameters are in row-major order.
*/
init {
require(mat.size == 4) { "Expected 4 elements, got ${mat.size}" }
this.mat = mat
}
} }
package org.jetbrains.skia package org.jetbrains.skia
import kotlin.jvm.JvmInline
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
internal fun Float.toRadians(): Double = this.toDouble() / 180 * PI private const val radiansToDegrees = 180.0 / PI
private const val tolerance = (1.0f / (1 shl 12)).toDouble()
internal inline fun Float.toRadians(): Double = this.toDouble() * radiansToDegrees
/** /**
* *
...@@ -16,21 +19,35 @@ internal fun Float.toRadians(): Double = this.toDouble() / 180 * PI ...@@ -16,21 +19,35 @@ internal fun Float.toRadians(): Double = this.toDouble() / 180 * PI
* *
* Matrix includes a hidden variable that classifies the type of matrix to * Matrix includes a hidden variable that classifies the type of matrix to
* improve performance. Matrix is not thread safe unless getType() is called first. * improve performance. Matrix is not thread safe unless getType() is called first.
*
* @param mat 9-element array of floats representing the matrix in row-major order
*
* <pre>`
* | scaleX skewX transX |
* | skewY scaleY transY |
* | persp0 persp1 persp2 |
`</pre> *
* *
* @see [https://fiddle.skia.org/c/@Matrix_063](https://fiddle.skia.org/c/@Matrix_063) * @see [https://fiddle.skia.org/c/@Matrix_063](https://fiddle.skia.org/c/@Matrix_063)
*/ */
class Matrix33(vararg mat: Float) { @JvmInline
/** value class Matrix33 internal constructor(val mat: FloatArray) {
*
* Matrix33 elements are in row-major order. constructor(
* m00: Float, m01: Float, m02: Float,
* <pre>` m10: Float, m11: Float, m12: Float,
* | scaleX skewX transX | m20: Float, m21: Float, m22: Float,
* | skewY scaleY transY | ) : this(
* | persp0 persp1 persp2 | floatArrayOf(
`</pre> * m00, m01, m02,
*/ m10, m11, m12,
val mat: FloatArray m20, m21, m22,
)
)
init {
require(mat.size == 9) { "Expected 9 elements, got ${mat.size}" }
}
fun makePreScale(sx: Float, sy: Float): Matrix33 { fun makePreScale(sx: Float, sy: Float): Matrix33 {
return Matrix33( return Matrix33(
mat[0] * sx, mat[0] * sx,
...@@ -100,21 +117,8 @@ class Matrix33(vararg mat: Float) { ...@@ -100,21 +117,8 @@ class Matrix33(vararg mat: Float) {
return Matrix44(mat[0], mat[1], 0f, mat[2], mat[3], mat[4], 0f, mat[5], 0f, 0f, 1f, 0f, mat[6], mat[7], 0f, mat[8]) return Matrix44(mat[0], mat[1], 0f, mat[2], mat[3], mat[4], 0f, mat[5], 0f, 0f, 1f, 0f, mat[6], mat[7], 0f, mat[8])
} }
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Matrix33) return false
return mat.contentEquals(other.mat)
}
override fun hashCode(): Int {
val PRIME = 59
var result = 1
result = result * PRIME + mat.contentHashCode()
return result
}
override fun toString(): String { override fun toString(): String {
return "Matrix33(_mat=$mat)" return "Matrix33(mat=${mat.contentToString()})"
} }
companion object { companion object {
...@@ -192,7 +196,7 @@ class Matrix33(vararg mat: Float) { ...@@ -192,7 +196,7 @@ class Matrix33(vararg mat: Float) {
val rad = deg.toRadians() val rad = deg.toRadians()
var sin = sin(rad) var sin = sin(rad)
var cos = cos(rad) var cos = cos(rad)
val tolerance = (1.0f / (1 shl 12)).toDouble() val tolerance = tolerance
if (abs(sin) <= tolerance) sin = 0.0 if (abs(sin) <= tolerance) sin = 0.0
if (abs(cos) <= tolerance) cos = 0.0 if (abs(cos) <= tolerance) cos = 0.0
return Matrix33( return Matrix33(
...@@ -231,7 +235,7 @@ class Matrix33(vararg mat: Float) { ...@@ -231,7 +235,7 @@ class Matrix33(vararg mat: Float) {
val rad = deg.toRadians() val rad = deg.toRadians()
var sin = sin(rad) var sin = sin(rad)
var cos = cos(rad) var cos = cos(rad)
val tolerance = (1.0f / (1 shl 12)).toDouble() val tolerance = tolerance
if (abs(sin) <= tolerance) sin = 0.0 if (abs(sin) <= tolerance) sin = 0.0
if (abs(cos) <= tolerance) cos = 0.0 if (abs(cos) <= tolerance) cos = 0.0
return Matrix33( return Matrix33(
...@@ -265,9 +269,4 @@ class Matrix33(vararg mat: Float) { ...@@ -265,9 +269,4 @@ class Matrix33(vararg mat: Float) {
return Matrix33(1f, sx, 0f, sy, 1f, 0f, 0f, 0f, 1f) return Matrix33(1f, sx, 0f, sy, 1f, 0f, 0f, 0f, 1f)
} }
} }
init {
require(mat.size == 9) { "Expected 9 elements, got ${mat.size}" }
this.mat = mat
}
} }
...@@ -3,6 +3,7 @@ package org.jetbrains.skia ...@@ -3,6 +3,7 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.InteropPointer import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.InteropScope import org.jetbrains.skia.impl.InteropScope
import org.jetbrains.skia.impl.withResult import org.jetbrains.skia.impl.withResult
import kotlin.jvm.JvmInline
/** /**
* *
...@@ -12,13 +13,30 @@ import org.jetbrains.skia.impl.withResult ...@@ -12,13 +13,30 @@ import org.jetbrains.skia.impl.withResult
* +X goes to the right * +X goes to the right
* +Y goes down * +Y goes down
* +Z goes into the screen (away from the viewer) * +Z goes into the screen (away from the viewer)
*
* @param mat 16 elements in row-major order
*/ */
class Matrix44(vararg mat: Float) { @JvmInline
value class Matrix44 internal constructor(val mat: FloatArray) {
constructor(
m00: Float, m01: Float, m02: Float, m03: Float,
m10: Float, m11: Float, m12: Float, m13: Float,
m20: Float, m21: Float, m22: Float, m23: Float,
m30: Float, m31: Float, m32: Float, m33: Float
) : this(
floatArrayOf(
m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33,
)
)
/** /**
* Matrix elements are in row-major order. * The constructor parameters are in row-major order.
*/ */
val mat: FloatArray init {
require(mat.size == 16) { "Expected 16 elements, got ${mat.size}" }
}
/** /**
* *
* When converting from Matrix44 to Matrix33, the third row and * When converting from Matrix44 to Matrix33, the third row and
...@@ -35,21 +53,8 @@ class Matrix44(vararg mat: Float) { ...@@ -35,21 +53,8 @@ class Matrix44(vararg mat: Float) {
return Matrix33(mat[0], mat[1], mat[3], mat[4], mat[5], mat[7], mat[12], mat[13], mat[15]) return Matrix33(mat[0], mat[1], mat[3], mat[4], mat[5], mat[7], mat[12], mat[13], mat[15])
} }
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Matrix44) return false
return mat.contentEquals(other.mat)
}
override fun hashCode(): Int {
val PRIME = 59
var result = 1
result = result * PRIME + mat.contentHashCode()
return result
}
override fun toString(): String { override fun toString(): String {
return "Matrix44(_mat=$mat)" return "Matrix44(mat=${mat.contentToString()})"
} }
companion object { companion object {
...@@ -57,15 +62,7 @@ class Matrix44(vararg mat: Float) { ...@@ -57,15 +62,7 @@ class Matrix44(vararg mat: Float) {
internal fun fromInteropPointer(block: InteropScope.(InteropPointer) -> Unit): Matrix44 { internal fun fromInteropPointer(block: InteropScope.(InteropPointer) -> Unit): Matrix44 {
val result = withResult(FloatArray(16), block) val result = withResult(FloatArray(16), block)
return Matrix44(*result) return Matrix44(result)
} }
} }
/**
* The constructor parameters are in row-major order.
*/
init {
require(mat.size == 16) { "Expected 16 elements, got ${mat.size}" }
this.mat = mat
}
} }
...@@ -145,17 +145,7 @@ class PathMeasure internal constructor(ptr: NativePointer) : Managed(ptr, _Final ...@@ -145,17 +145,7 @@ class PathMeasure internal constructor(ptr: NativePointer) : Managed(ptr, _Final
withNullableResult(FloatArray(9)) { withNullableResult(FloatArray(9)) {
_nGetMatrix(_ptr, distance, getPosition, getTangent, it) _nGetMatrix(_ptr, distance, getPosition, getTangent, it)
}?.let { data -> }?.let { data ->
Matrix33( Matrix33(data)
data[0],
data[1],
data[2],
data[3],
data[4],
data[5],
data[6],
data[7],
data[8]
)
} }
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment