1245 lines
48 KiB
Kotlin
1245 lines
48 KiB
Kotlin
/*
|
|
* Copyright (C) 2021 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// TODO Rename to something better
|
|
package com.example.testapp
|
|
|
|
import android.content.Context
|
|
import android.graphics.Bitmap
|
|
import android.graphics.BitmapFactory
|
|
import android.renderscript.RenderScript
|
|
import android.renderscript.toolkit.BlendingMode
|
|
import android.renderscript.toolkit.LookupTable
|
|
import android.renderscript.toolkit.Range2d
|
|
import android.renderscript.toolkit.Rgba3dArray
|
|
import android.renderscript.toolkit.Toolkit
|
|
import android.renderscript.toolkit.YuvFormat
|
|
import kotlin.math.abs
|
|
import kotlin.math.min
|
|
|
|
data class TestLayout(
|
|
val sizeX: Int,
|
|
val sizeY: Int,
|
|
val restriction: Range2d?
|
|
)
|
|
|
|
// List of dimensions (sizeX, sizeY) to try when generating random data.
|
|
val commonLayoutsToTry = listOf(
|
|
// Small layouts to start with
|
|
TestLayout(3, 4, null),
|
|
TestLayout(3, 4, Range2d(0, 1, 0, 3)),
|
|
TestLayout(3, 4, Range2d(2, 3, 1, 4)),
|
|
TestLayout(10, 14, null),
|
|
TestLayout(10, 14, Range2d(2, 3, 8, 14)),
|
|
// The size of most CTS intrinsic tests
|
|
TestLayout(160, 100, null),
|
|
TestLayout(125, 227, Range2d(50, 125, 100, 227)),
|
|
// A larger one
|
|
TestLayout(800, 600, null),
|
|
// Weirdly shaped ones
|
|
TestLayout(1, 1, null), // A single item
|
|
// TODO This size makes Intrinsic Blur fail.
|
|
TestLayout(16000, 1, null), // A single item
|
|
TestLayout(1, 16000, null), // One large row
|
|
// A very large test
|
|
TestLayout(1024, 2048, null),
|
|
)
|
|
|
|
|
|
class Tester(context: Context, private val validate: Boolean) {
|
|
private val renderscriptContext = RenderScript.create(context)
|
|
private val toolkit = Toolkit()
|
|
private val testImage1 = BitmapFactory.decodeResource(context.resources, R.drawable.img800x450a)
|
|
private val testImage2 = BitmapFactory.decodeResource(context.resources, R.drawable.img800x450b)
|
|
|
|
init {
|
|
validateTestImage(testImage1)
|
|
validateTestImage(testImage2)
|
|
}
|
|
|
|
/**
|
|
* Verify that the test images are in format that works for our tests.
|
|
*/
|
|
private fun validateTestImage(bitmap: Bitmap) {
|
|
require(bitmap.config == Bitmap.Config.ARGB_8888)
|
|
require(bitmap.rowBytes == bitmap.width * 4) {
|
|
"Can't handle bitmaps that have extra padding. " +
|
|
"${bitmap.rowBytes} != ${bitmap.width} * 4." }
|
|
require(bitmap.byteCount == bitmap.rowBytes * bitmap.height)
|
|
}
|
|
|
|
fun destroy() {
|
|
renderscriptContext.destroy()
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
fun testAll(timer: TimingTracker): String {
|
|
val tests = listOf(
|
|
Pair("blend", ::testBlend),
|
|
Pair("blur", ::testBlur),
|
|
Pair("colorMatrix", ::testColorMatrix),
|
|
Pair("convolve", ::testConvolve),
|
|
Pair("histogram", ::testHistogram),
|
|
Pair("lut", ::testLut),
|
|
Pair("lut3d", ::testLut3d),
|
|
Pair("resize", ::testResize),
|
|
Pair("yuvToRgb", ::testYuvToRgb),
|
|
)
|
|
val results = Array(tests.size) { "" }
|
|
for (i in tests.indices) {
|
|
val (name, test) = tests[i]
|
|
println("Doing $name")
|
|
val success = test(timer)
|
|
results[i] = "$name " + if (success) "succeeded" else "FAILED! FAILED! FAILED! FAILED!"
|
|
println(" ${results[i]}")
|
|
}
|
|
|
|
return results.joinToString("\n")
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testBlend(timer: TimingTracker): Boolean {
|
|
return BlendingMode.values().all { mode ->
|
|
testOneBitmapBlend(timer, testImage1, testImage2, mode, null) and
|
|
testOneBitmapBlend(
|
|
timer, testImage1, testImage2, mode,
|
|
Range2d(6, 23, 2, 4)
|
|
) and
|
|
commonLayoutsToTry.all { (sizeX, sizeY, restriction) ->
|
|
testOneRandomBlend(timer, sizeX, sizeY, mode, restriction)
|
|
}
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomBlend(
|
|
timer: TimingTracker,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
mode: BlendingMode,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val sourceArray = randomByteArray(0x50521f0, sizeX, sizeY, 4)
|
|
val destArray = randomByteArray(0x2932147, sizeX, sizeY, 4)
|
|
// Make clones because these will be modified by the blend.
|
|
val intrinsicDestArray = destArray.clone()
|
|
val referenceDestArray = destArray.clone()
|
|
val toolkitDestArray = destArray.clone()
|
|
|
|
timer.measure("IntrinsicBlend") {
|
|
intrinsicBlend(
|
|
renderscriptContext, mode, sourceArray, intrinsicDestArray, sizeX, sizeY,
|
|
restriction
|
|
)
|
|
}
|
|
timer.measure("ToolkitBlend") {
|
|
toolkit.blend(mode, sourceArray, toolkitDestArray, sizeX, sizeY, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
timer.measure("ReferenceBlend") {
|
|
referenceBlend(mode, sourceArray, referenceDestArray, sizeX, sizeY, restriction)
|
|
}
|
|
|
|
return validateSame(
|
|
"Blend_$mode", intrinsicDestArray, referenceDestArray, toolkitDestArray
|
|
) {
|
|
println("blend $mode ($sizeX, $sizeY) $restriction")
|
|
logArray("Blend_$mode src", sourceArray, 48)
|
|
logArray("Blend_$mode dst", destArray, 48)
|
|
logArray("Blend_$mode reference out", referenceDestArray, 48)
|
|
logArray("Blend_$mode intrinsic out", intrinsicDestArray, 48)
|
|
logArray("Blend_$mode toolkit out", toolkitDestArray, 48)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneBitmapBlend(
|
|
timer: TimingTracker,
|
|
sourceBitmap: Bitmap,
|
|
destBitmap: Bitmap,
|
|
mode: BlendingMode,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
// Make clones because these will be modified by the blend.
|
|
val intrinsicDestBitmap = duplicateBitmap(destBitmap)
|
|
val toolkitDestBitmap = duplicateBitmap(destBitmap)
|
|
val referenceDestBitmap = duplicateBitmap(destBitmap)
|
|
|
|
timer.measure("IntrinsicBlend") {
|
|
intrinsicBlend(
|
|
renderscriptContext, mode, sourceBitmap, intrinsicDestBitmap, restriction
|
|
)
|
|
}
|
|
timer.measure("ToolkitBlend") {
|
|
toolkit.blend(mode, sourceBitmap, toolkitDestBitmap, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceDestArray = getBitmapBytes(referenceDestBitmap)
|
|
timer.measure("ReferenceBlend") {
|
|
referenceBlend(
|
|
mode, getBitmapBytes(sourceBitmap), referenceDestArray, sourceBitmap.width,
|
|
sourceBitmap.height, restriction
|
|
)
|
|
}
|
|
|
|
val intrinsicDestArray = getBitmapBytes(intrinsicDestBitmap)
|
|
val toolkitDestArray = getBitmapBytes(toolkitDestBitmap)
|
|
return validateSame(
|
|
"BlendBitmap_$mode", intrinsicDestArray, referenceDestArray, toolkitDestArray
|
|
) {
|
|
println("BlendBitmap $mode $restriction")
|
|
//logArray("BlendBitmap_$mode src", sourceArray, 48)
|
|
//logArray("BlendBitmap_$mode dst", destArray, 48)
|
|
logArray("BlendBitmap_$mode reference out", referenceDestArray, 48)
|
|
logArray("BlendBitmap_$mode intrinsic out", intrinsicDestArray, 48)
|
|
logArray("BlendBitmap_$mode toolkit out", toolkitDestArray, 48)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testBlur(timer: TimingTracker): Boolean {
|
|
return arrayOf(1, 3, 8, 25).all { radius ->
|
|
testOneBitmapBlur(timer, testImage1, radius, null) and
|
|
testOneBitmapBlur(timer, testImage1, radius, Range2d(6, 23, 2, 4)) and
|
|
commonLayoutsToTry.all { (sizeX, sizeY, restriction) ->
|
|
arrayOf(1, 4).all { vectorSize ->
|
|
testOneRandomBlur(timer, vectorSize, sizeX, sizeY, radius, restriction)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomBlur(
|
|
timer: TimingTracker,
|
|
vectorSize: Int,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
radius: Int,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, vectorSize)
|
|
val intrinsicOutArray = timer.measure("IntrinsicBlur") {
|
|
intrinsicBlur(
|
|
renderscriptContext, inputArray, vectorSize, sizeX, sizeY, radius, restriction
|
|
)
|
|
}
|
|
val toolkitOutArray = timer.measure("ToolkitBlur") {
|
|
toolkit.blur(inputArray, vectorSize, sizeX, sizeY, radius, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceBlur") {
|
|
referenceBlur(inputArray, vectorSize, sizeX, sizeY, radius, restriction)
|
|
}
|
|
return validateSame("blur", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("blur $vectorSize ($sizeX, $sizeY) radius = $radius $restriction")
|
|
logArray("blur input ", inputArray)
|
|
logArray("blur reference out", referenceOutArray)
|
|
logArray("blur intrinsic out", intrinsicOutArray)
|
|
logArray("blur toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneBitmapBlur(
|
|
timer: TimingTracker,
|
|
bitmap: Bitmap,
|
|
radius: Int,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val intrinsicOutArray = timer.measure("IntrinsicBlur") {
|
|
intrinsicBlur(renderscriptContext, bitmap, radius, restriction)
|
|
}
|
|
|
|
val toolkitOutBitmap = timer.measure("ToolkitBlur") {
|
|
toolkit.blur(bitmap, radius, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceBlur") {
|
|
referenceBlur(
|
|
getBitmapBytes(bitmap),
|
|
vectorSizeOfBitmap(bitmap),
|
|
bitmap.width,
|
|
bitmap.height,
|
|
radius,
|
|
restriction
|
|
)
|
|
}
|
|
|
|
val toolkitOutArray = getBitmapBytes(toolkitOutBitmap)
|
|
return validateSame("blur", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("BlurBitmap ${bitmap.config} $radius $restriction")
|
|
logArray("blur reference out", referenceOutArray)
|
|
logArray("blur intrinsic out", intrinsicOutArray)
|
|
logArray("blur toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
enum class ColorMatrixConversionType {
|
|
RGB_TO_YUV,
|
|
YUV_TO_RGB,
|
|
GREYSCALE,
|
|
RANDOM
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testColorMatrix(timer: TimingTracker): Boolean {
|
|
return ColorMatrixConversionType.values().all { conversion ->
|
|
testOneBitmapColorMatrix(timer, testImage1, conversion, null) and
|
|
testOneBitmapColorMatrix(
|
|
timer,
|
|
testImage1,
|
|
conversion,
|
|
Range2d(6, 23, 2, 4)
|
|
) and
|
|
commonLayoutsToTry.all { (sizeX, sizeY, restriction) ->
|
|
(1..4).all { inputVectorSize ->
|
|
(1..4).all { outputVectorSize ->
|
|
testOneRandomColorMatrix(
|
|
timer,
|
|
inputVectorSize,
|
|
sizeX,
|
|
sizeY,
|
|
outputVectorSize,
|
|
conversion,
|
|
restriction
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomColorMatrix(
|
|
timer: TimingTracker,
|
|
inputVectorSize: Int,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
outputVectorSize: Int,
|
|
conversion: ColorMatrixConversionType,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, paddedSize(inputVectorSize))
|
|
val addVector = randomFloatArray(0x243238, 4, 1, 1, 0.3f)
|
|
val matrix = when (conversion) {
|
|
ColorMatrixConversionType.RGB_TO_YUV -> toolkit.rgbToYuvMatrix
|
|
ColorMatrixConversionType.YUV_TO_RGB -> toolkit.yuvToRgbMatrix
|
|
ColorMatrixConversionType.GREYSCALE -> toolkit.greyScaleColorMatrix
|
|
ColorMatrixConversionType.RANDOM -> randomFloatArray(0x234348, 4, 4, 1)
|
|
}
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicColorMatrix") {
|
|
intrinsicColorMatrix(
|
|
renderscriptContext,
|
|
conversion,
|
|
inputArray,
|
|
inputVectorSize,
|
|
sizeX,
|
|
sizeY,
|
|
outputVectorSize,
|
|
matrix,
|
|
addVector,
|
|
restriction
|
|
)
|
|
}
|
|
val toolkitOutArray = timer.measure("ToolkitColorMatrix") {
|
|
toolkit.colorMatrix(
|
|
inputArray,
|
|
inputVectorSize,
|
|
sizeX,
|
|
sizeY,
|
|
outputVectorSize,
|
|
matrix,
|
|
addVector,
|
|
restriction
|
|
)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceColorMatrix") {
|
|
referenceColorMatrix(
|
|
inputArray, inputVectorSize, sizeX, sizeY, outputVectorSize, matrix, addVector,
|
|
restriction
|
|
)
|
|
}
|
|
|
|
return validateSame("colorMatrix", intrinsicOutArray, referenceOutArray, toolkitOutArray,
|
|
outputVectorSize == 3) {
|
|
println("colorMatrix ($sizeX, $sizeY) $inputVectorSize->$outputVectorSize $restriction")
|
|
logArray("colorMatrix matrix ", matrix, 16)
|
|
logArray("colorMatrix addVector", addVector, 4)
|
|
logArray("colorMatrix in ", inputArray)
|
|
logArray("colorMatrix reference out", referenceOutArray, 300)
|
|
logArray("colorMatrix intrinsic out", intrinsicOutArray, 300)
|
|
logArray("colorMatrix toolkit out", toolkitOutArray, 300)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneBitmapColorMatrix(
|
|
timer: TimingTracker,
|
|
bitmap: Bitmap,
|
|
conversion: ColorMatrixConversionType,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val addVector = randomFloatArray(0x243238, 4, 1, 1, 0.3f)
|
|
val matrix = when (conversion) {
|
|
ColorMatrixConversionType.RGB_TO_YUV -> toolkit.rgbToYuvMatrix
|
|
ColorMatrixConversionType.YUV_TO_RGB -> toolkit.yuvToRgbMatrix
|
|
ColorMatrixConversionType.GREYSCALE -> toolkit.greyScaleColorMatrix
|
|
ColorMatrixConversionType.RANDOM -> randomFloatArray(0x234348, 4, 4, 1)
|
|
}
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicColorMatrix") {
|
|
intrinsicColorMatrix(
|
|
renderscriptContext, conversion, bitmap, matrix, addVector, restriction
|
|
)
|
|
}
|
|
val toolkitOutBitmap = timer.measure("ToolkitColorMatrix") {
|
|
toolkit.colorMatrix(bitmap, matrix, addVector, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceColorMatrix") {
|
|
referenceColorMatrix(
|
|
getBitmapBytes(bitmap), vectorSizeOfBitmap(bitmap), bitmap.width, bitmap.height,
|
|
vectorSizeOfBitmap(bitmap), matrix, addVector, restriction
|
|
)
|
|
}
|
|
|
|
val toolkitOutArray = getBitmapBytes(toolkitOutBitmap)
|
|
return validateSame("ColorMatrix", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("colorMatrixBitmap $restriction")
|
|
logArray("colorMatrixBitmap matrix ", matrix, 16)
|
|
logArray("colorMatrixBitmap addVector", addVector, 4)
|
|
logArray("colorMatrixBitmap reference out", referenceOutArray)
|
|
logArray("colorMatrixBitmap intrinsic out", intrinsicOutArray)
|
|
logArray("colorMatrixBitmap toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testConvolve(timer: TimingTracker): Boolean {
|
|
val coefficientsToTry = listOf(
|
|
randomFloatArray(0x2937021, 3, 3, 1, 0.1f),
|
|
randomFloatArray(0x2937021, 5, 5, 1, 0.05f)
|
|
)
|
|
return coefficientsToTry.all { coefficients ->
|
|
testOneBitmapConvolve(timer, testImage1, coefficients, null) and
|
|
testOneBitmapConvolve(timer, testImage1, coefficients, Range2d(6, 23, 2, 4)) and
|
|
|
|
commonLayoutsToTry.all { (sizeX, sizeY, restriction) ->
|
|
(1..4).all { vectorSize ->
|
|
testOneRandomConvolve(
|
|
timer,
|
|
vectorSize,
|
|
sizeX,
|
|
sizeY,
|
|
coefficients,
|
|
restriction
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomConvolve(
|
|
timer: TimingTracker,
|
|
vectorSize: Int,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
coefficients: FloatArray,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, paddedSize(vectorSize))
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicConvolve") {
|
|
intrinsicConvolve(
|
|
renderscriptContext, inputArray, vectorSize, sizeX, sizeY, coefficients, restriction
|
|
)
|
|
}
|
|
val toolkitOutArray = timer.measure("ToolkitConvolve") {
|
|
toolkit.convolve(inputArray, vectorSize, sizeX, sizeY, coefficients, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceConvolve") {
|
|
referenceConvolve(inputArray, vectorSize, sizeX, sizeY, coefficients, restriction)
|
|
}
|
|
|
|
val task = if (coefficients.size == 9) "convolve3x3 $vectorSize" else "convolve5x5 $vectorSize"
|
|
return validateSame(task, intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("Convolve $vectorSize ($sizeX, $sizeY) $restriction")
|
|
logArray("Convolve coefficients", coefficients, 25)
|
|
logArray("Convolve in ", inputArray)
|
|
logArray("Convolve reference out", referenceOutArray)
|
|
logArray("Convolve intrinsic out", intrinsicOutArray)
|
|
logArray("Convolve toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneBitmapConvolve(
|
|
timer: TimingTracker,
|
|
bitmap: Bitmap,
|
|
coefficients: FloatArray,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val intrinsicOutArray = timer.measure("IntrinsicConvolve") {
|
|
intrinsicConvolve(renderscriptContext, bitmap, coefficients, restriction)
|
|
}
|
|
val toolkitOutBitmap = timer.measure("ToolkitConvolve") {
|
|
toolkit.convolve(bitmap, coefficients, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceConvolve") {
|
|
referenceConvolve(
|
|
getBitmapBytes(bitmap), vectorSizeOfBitmap(bitmap), bitmap.width, bitmap.height,
|
|
coefficients, restriction
|
|
)
|
|
}
|
|
|
|
val task = if (coefficients.size == 9) "convolve3x3" else "convolve5x5"
|
|
val toolkitOutArray = getBitmapBytes(toolkitOutBitmap)
|
|
return validateSame(task, intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("ConvolveBitmap $restriction")
|
|
logArray("ConvolveBitmap coefficients", coefficients, 25)
|
|
//logArray("ConvolveBitmap in ", inputArray)
|
|
logArray("ConvolveBitmap reference out", referenceOutArray)
|
|
logArray("ConvolveBitmap intrinsic out", intrinsicOutArray)
|
|
logArray("ConvolveBitmap toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testHistogram(timer: TimingTracker): Boolean {
|
|
val coefficients = floatArrayOf(0.1f, 0.3f, 0.5f, 0.05f)
|
|
return testOneBitmapHistogram(timer, testImage1, null) and
|
|
testOneBitmapHistogram(timer, testImage1, Range2d(6, 23, 2, 4)) and
|
|
testOneBitmapHistogramDot(timer, testImage1, null, null) and
|
|
testOneBitmapHistogramDot(timer, testImage1, coefficients, null) and
|
|
testOneBitmapHistogramDot(timer, testImage1, coefficients, Range2d(6, 23, 2, 4)) and
|
|
commonLayoutsToTry.all { (sizeX, sizeY, restriction) ->
|
|
(1..4).all { vectorSize ->
|
|
testOneRandomHistogram(timer, vectorSize, sizeX, sizeY, restriction) &&
|
|
testOneRandomHistogramDot(
|
|
timer,
|
|
vectorSize,
|
|
sizeX,
|
|
sizeY,
|
|
null,
|
|
restriction
|
|
) &&
|
|
testOneRandomHistogramDot(
|
|
timer,
|
|
vectorSize,
|
|
sizeX,
|
|
sizeY,
|
|
coefficients.sliceArray(0 until vectorSize),
|
|
restriction
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomHistogram(
|
|
timer: TimingTracker,
|
|
vectorSize: Int,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, paddedSize(vectorSize))
|
|
|
|
val intrinsicOutput = timer.measure("IntrinsicHistogram") {
|
|
intrinsicHistogram(
|
|
renderscriptContext, inputArray, vectorSize, sizeX, sizeY, restriction
|
|
)
|
|
}
|
|
val toolkitOutput = timer.measure("ToolkitHistogram") {
|
|
toolkit.histogram(inputArray, vectorSize, sizeX, sizeY, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutput = timer.measure("ReferenceHistogram") {
|
|
referenceHistogram(
|
|
inputArray, vectorSize, sizeX, sizeY, restriction
|
|
)
|
|
}
|
|
|
|
return validateSame("histogram", intrinsicOutput, referenceOutput, toolkitOutput, 0) {
|
|
println("histogram $vectorSize ($sizeX, $sizeY) $restriction")
|
|
logArray("histogram in ", inputArray, 200)
|
|
logArray("histogram reference out", referenceOutput, 200)
|
|
logArray("histogram intrinsic out", intrinsicOutput, 200)
|
|
logArray("histogram toolkit out", toolkitOutput, 200)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneBitmapHistogram(
|
|
timer: TimingTracker,
|
|
bitmap: Bitmap,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val intrinsicOutput = timer.measure("IntrinsicHistogram") {
|
|
intrinsicHistogram(renderscriptContext, bitmap, restriction)
|
|
}
|
|
val toolkitOutput = timer.measure("ToolkitHistogram") {
|
|
toolkit.histogram(bitmap, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutput = timer.measure("ReferenceHistogram") {
|
|
referenceHistogram(
|
|
getBitmapBytes(bitmap), vectorSizeOfBitmap(bitmap), bitmap.width, bitmap.height,
|
|
restriction
|
|
)
|
|
}
|
|
|
|
return validateSame("histogram", intrinsicOutput, referenceOutput, toolkitOutput, 0) {
|
|
println("HistogramBitmap $restriction")
|
|
logArray("HistogramBitmap reference out", referenceOutput)
|
|
logArray("HistogramBitmap intrinsic out", intrinsicOutput)
|
|
logArray("HistogramBitmap toolkit out", toolkitOutput)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomHistogramDot(
|
|
timer: TimingTracker,
|
|
vectorSize: Int,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
coefficients: FloatArray?, restriction: Range2d?
|
|
): Boolean {
|
|
val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, paddedSize(vectorSize))
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicHistogramDot") {
|
|
intrinsicHistogramDot(
|
|
renderscriptContext, inputArray, vectorSize, sizeX, sizeY, coefficients, restriction
|
|
)
|
|
}
|
|
val toolkitOutArray = timer.measure("ToolkitHistogramDot") {
|
|
toolkit.histogramDot(
|
|
inputArray, vectorSize, sizeX, sizeY, coefficients, restriction
|
|
)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceHistogramDot") {
|
|
referenceHistogramDot(inputArray, vectorSize, sizeX, sizeY, coefficients, restriction)
|
|
}
|
|
|
|
return validateSame("histogramDot", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("histogramDot $vectorSize ($sizeX, $sizeY) $restriction")
|
|
logArray("histogramDot coefficients ", coefficients)
|
|
logArray("histogramDot in ", inputArray)
|
|
logArray("histogramDot reference out", referenceOutArray, 256)
|
|
logArray("histogramDot intrinsic out", intrinsicOutArray, 256)
|
|
logArray("histogramDot toolkit out", toolkitOutArray, 256)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneBitmapHistogramDot(
|
|
timer: TimingTracker,
|
|
bitmap: Bitmap,
|
|
coefficients: FloatArray?,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val intrinsicOutArray = timer.measure("IntrinsicHistogramDot") {
|
|
intrinsicHistogramDot(renderscriptContext, bitmap, coefficients, restriction)
|
|
}
|
|
val toolkitOutArray = timer.measure("ToolkitHistogramDot") {
|
|
toolkit.histogramDot(bitmap, coefficients, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceHistogramDot") {
|
|
referenceHistogramDot(
|
|
getBitmapBytes(bitmap),
|
|
vectorSizeOfBitmap(bitmap),
|
|
bitmap.width,
|
|
bitmap.height,
|
|
coefficients,
|
|
restriction
|
|
)
|
|
}
|
|
|
|
return validateSame(
|
|
"HistogramDotBitmap",
|
|
intrinsicOutArray,
|
|
referenceOutArray,
|
|
toolkitOutArray
|
|
) {
|
|
println("HistogramDotBitmap $restriction")
|
|
logArray("HistogramDotBitmap coefficients ", coefficients)
|
|
//logArray("HistogramDotBitmap in ", inputArray)
|
|
logArray("HistogramDotBitmap reference out", referenceOutArray, 256)
|
|
logArray("HistogramDotBitmap intrinsic out", intrinsicOutArray, 256)
|
|
logArray("HistogramDotBitmap toolkit out", toolkitOutArray, 256)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testLut(timer: TimingTracker): Boolean {
|
|
return testOneBitmapLut(timer, testImage1, null) and
|
|
testOneBitmapLut(timer, testImage1, Range2d(6, 23, 2, 4)) and
|
|
commonLayoutsToTry.all { (sizeX, sizeY, restriction) ->
|
|
testOneRandomLut(timer, sizeX, sizeY, restriction)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomLut(
|
|
timer: TimingTracker,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, 4)
|
|
val newRed = randomByteArray(0x32425, 256, 1, 1)
|
|
val newGreen = randomByteArray(0x1F3225, 256, 1, 1)
|
|
val newBlue = randomByteArray(0x32D4F27, 256, 1, 1)
|
|
val newAlpha = randomByteArray(0x3A20001, 256, 1, 1)
|
|
val table = LookupTable()
|
|
table.red = newRed
|
|
table.blue = newBlue
|
|
table.green = newGreen
|
|
table.alpha = newAlpha
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicLUT") {
|
|
intrinsicLut(
|
|
renderscriptContext, inputArray, sizeX, sizeY, newRed, newGreen, newBlue, newAlpha,
|
|
restriction
|
|
)
|
|
}
|
|
val toolkitOutArray = timer.measure("ToolkitLUT") {
|
|
toolkit.lut(inputArray, sizeX, sizeY, table, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceLUT") {
|
|
referenceLut(inputArray, sizeX, sizeY, table, restriction)
|
|
}
|
|
|
|
return validateSame("LUT", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("lut ($sizeX, $sizeY) $restriction")
|
|
logArray("LUT red ", newRed, 256)
|
|
logArray("LUT green", newGreen, 256)
|
|
logArray("LUT blue ", newBlue, 256)
|
|
logArray("LUT alpha", newAlpha, 256)
|
|
logArray("LUT in ", inputArray)
|
|
logArray("LUT reference out", referenceOutArray)
|
|
logArray("LUT intrinsic out", intrinsicOutArray)
|
|
logArray("LUT toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneBitmapLut(
|
|
timer: TimingTracker,
|
|
bitmap: Bitmap,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val newRed = randomByteArray(0x32425, 256, 1, 1)
|
|
val newGreen = randomByteArray(0x1F3225, 256, 1, 1)
|
|
val newBlue = randomByteArray(0x32D4F27, 256, 1, 1)
|
|
val newAlpha = randomByteArray(0x3A20001, 256, 1, 1)
|
|
val table = LookupTable()
|
|
table.red = newRed
|
|
table.blue = newBlue
|
|
table.green = newGreen
|
|
table.alpha = newAlpha
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicLUT") {
|
|
intrinsicLut(
|
|
renderscriptContext, bitmap, newRed, newGreen, newBlue, newAlpha, restriction
|
|
)
|
|
}
|
|
val toolkitOutBitmap = timer.measure("ToolkitLUT") {
|
|
toolkit.lut(bitmap, table, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceLUT") {
|
|
referenceLut(
|
|
getBitmapBytes(bitmap),
|
|
bitmap.width,
|
|
bitmap.height,
|
|
table,
|
|
restriction
|
|
)
|
|
}
|
|
|
|
val toolkitOutArray = getBitmapBytes(toolkitOutBitmap)
|
|
return validateSame("LutBitmap", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("LutBitmap $restriction")
|
|
logArray("LutBitmap red ", newRed, 256)
|
|
logArray("LutBitmap green", newGreen, 256)
|
|
logArray("LutBitmap blue ", newBlue, 256)
|
|
logArray("LutBitmap alpha", newAlpha, 256)
|
|
//logArray("LutBitmap in ", inputArray, 80)
|
|
logArray("LutBitmap reference out", referenceOutArray)
|
|
logArray("LutBitmap intrinsic out", intrinsicOutArray)
|
|
logArray("LutBitmap toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testLut3d(timer: TimingTracker): Boolean {
|
|
val cubeSizesToTry = listOf(
|
|
Dimension(2, 2, 2),
|
|
Dimension(32, 32, 16),
|
|
Dimension(256, 256, 256)
|
|
)
|
|
return cubeSizesToTry.all { cubeSize ->
|
|
val identityCube = identityCube(cubeSize)
|
|
val randomCube = randomCube(0x23424, cubeSize)
|
|
testOneBitmapLut3d(timer, testImage1, cubeSize, identityCube, 1, null) and
|
|
testOneBitmapLut3d(timer, testImage2, cubeSize, randomCube, 3, null) and
|
|
testOneBitmapLut3d(timer, testImage2, cubeSize, randomCube, 3, Range2d(6, 23, 2, 4)) and
|
|
commonLayoutsToTry.all { (sizeX, sizeY, restriction) ->
|
|
testOneRandomLut3d(timer, sizeX, sizeY, cubeSize, identityCube, 1, restriction) &&
|
|
testOneRandomLut3d(
|
|
timer,
|
|
sizeX,
|
|
sizeY,
|
|
cubeSize,
|
|
randomCube,
|
|
3,
|
|
restriction
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomLut3d(
|
|
timer: TimingTracker,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
cubeSize: Dimension,
|
|
cubeArray: ByteArray,
|
|
allowedIntError: Int, restriction: Range2d?
|
|
): Boolean {
|
|
val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, 4)
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicLut3d") {
|
|
intrinsicLut3d(
|
|
renderscriptContext, inputArray, sizeX, sizeY, cubeArray, cubeSize, restriction
|
|
)
|
|
}
|
|
val toolkitOutArray = timer.measure("ToolkitLut3d") {
|
|
val toolkitCube = Rgba3dArray(cubeArray, cubeSize.sizeX, cubeSize.sizeY, cubeSize.sizeZ)
|
|
toolkit.lut3d(inputArray, sizeX, sizeY, toolkitCube, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceLut3d") {
|
|
val cube = Rgba3dArray(cubeArray, cubeSize.sizeX, cubeSize.sizeY, cubeSize.sizeZ)
|
|
referenceLut3d(inputArray, sizeX, sizeY, cube, restriction)
|
|
}
|
|
|
|
return validateSame(
|
|
"lut3d",
|
|
intrinsicOutArray,
|
|
referenceOutArray,
|
|
toolkitOutArray,
|
|
false,
|
|
allowedIntError
|
|
) {
|
|
println("lut3d ($sizeX, $sizeY) $restriction")
|
|
logArray("lut3d cube", cubeArray, 256)
|
|
logArray("lut3d in ", inputArray, 64)
|
|
logArray("lut3d reference out", referenceOutArray, 64)
|
|
logArray("lut3d intrinsic out", intrinsicOutArray, 64)
|
|
logArray("lut3d toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneBitmapLut3d(
|
|
timer: TimingTracker,
|
|
bitmap: Bitmap,
|
|
cubeSize: Dimension,
|
|
cubeArray: ByteArray,
|
|
allowedIntError: Int, restriction: Range2d?
|
|
): Boolean {
|
|
val intrinsicOutArray = timer.measure("IntrinsicLut3d") {
|
|
intrinsicLut3d(renderscriptContext, bitmap, cubeArray, cubeSize, restriction)
|
|
}
|
|
val toolkitOutBitmap = timer.measure("ToolkitLut3d") {
|
|
val toolkitCube = Rgba3dArray(cubeArray, cubeSize.sizeX, cubeSize.sizeY, cubeSize.sizeZ)
|
|
toolkit.lut3d(bitmap, toolkitCube, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceLut3d") {
|
|
val cube = Rgba3dArray(cubeArray, cubeSize.sizeX, cubeSize.sizeY, cubeSize.sizeZ)
|
|
referenceLut3d(getBitmapBytes(bitmap), bitmap.width, bitmap.height, cube, restriction)
|
|
}
|
|
|
|
val toolkitOutArray = getBitmapBytes(toolkitOutBitmap)
|
|
return validateSame(
|
|
"Lut3dBitmap",
|
|
intrinsicOutArray,
|
|
referenceOutArray,
|
|
toolkitOutArray,
|
|
false,
|
|
allowedIntError
|
|
) {
|
|
println("Lut3dBitmap $restriction")
|
|
logArray("Lut3dBitmap cube", cubeArray, 256)
|
|
//logArray("Lut3dBitmap in ", inputArray, 64)
|
|
logArray("Lut3dBitmap reference out", referenceOutArray, 64)
|
|
logArray("Lut3dBitmap intrinsic out", intrinsicOutArray, 64)
|
|
logArray("Lut3dBitmap toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testResize(timer: TimingTracker): Boolean {
|
|
val factorsToTry = listOf(
|
|
Pair(1f, 1f),
|
|
Pair(0.5f, 1f),
|
|
Pair(2f, 2f),
|
|
Pair(0.5f, 2f),
|
|
Pair(2f, 0.5f),
|
|
// The RenderScript Intrinsic tests used the above factors. It's tempting to use
|
|
// less regular ones like Pair(6.37f, 0.17f) however this creates small offset
|
|
// errors between the result provided by the C++ code and the SIMD code. This is
|
|
// due to the SIMD code using a scaled integer to increment going from one pixel to the
|
|
// next, while the C++ code uses float operations.
|
|
)
|
|
val layoutsToTry = listOf(
|
|
TestLayout(37, 47, null),
|
|
TestLayout(60, 10, null),
|
|
TestLayout(6, 4, Range2d(1, 3, 0, 2)),
|
|
TestLayout(10, 14, Range2d(2, 3, 3, 7)),
|
|
)
|
|
|
|
return factorsToTry.all { (scaleX, scaleY) ->
|
|
// Do one resize that's greater than 4x, as that's used in the code but don't do it
|
|
// for everything, as some images will get very large
|
|
testOneRandomResize(timer, 1, 25, 30, 6f, 6f, null) and
|
|
testOneBitmapResize(timer, testImage1, scaleX, scaleY, null) and
|
|
testOneBitmapResize(timer, testImage1, scaleX, scaleY, Range2d(6, 23, 2, 4)) and
|
|
layoutsToTry.all { (sizeX, sizeY, restriction) ->
|
|
(1..4).all { vectorSize ->
|
|
testOneRandomResize(
|
|
timer,
|
|
vectorSize,
|
|
sizeX,
|
|
sizeY,
|
|
scaleX,
|
|
scaleY,
|
|
restriction
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomResize(
|
|
timer: TimingTracker,
|
|
vectorSize: Int,
|
|
inSizeX: Int,
|
|
inSizeY: Int,
|
|
scaleX: Float,
|
|
scaleY: Float,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
val inputArray = randomByteArray(0x50521f0, inSizeX, inSizeY, paddedSize(vectorSize))
|
|
val outSizeX = (inSizeX * scaleX).toInt()
|
|
val outSizeY = (inSizeY * scaleY).toInt()
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicResize") {
|
|
intrinsicResize(
|
|
renderscriptContext, inputArray, vectorSize, inSizeX, inSizeY, outSizeX, outSizeY,
|
|
restriction
|
|
)
|
|
}
|
|
val toolkitOutArray = timer.measure("ToolkitResize") {
|
|
toolkit.resize(
|
|
inputArray, vectorSize, inSizeX, inSizeY, outSizeX, outSizeY, restriction
|
|
)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceResize") {
|
|
referenceResize(
|
|
inputArray, vectorSize, inSizeX, inSizeY, outSizeX, outSizeY, restriction
|
|
)
|
|
}
|
|
|
|
return validateSame("resize", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("resize $vectorSize ($inSizeX, $inSizeY) by ($scaleX, $scaleY) to ($outSizeX, $outSizeY), $restriction")
|
|
logArray("resize in ", inputArray)
|
|
logArray("resize reference out", referenceOutArray)
|
|
logArray("resize intrinsic out", intrinsicOutArray)
|
|
logArray("resize toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneBitmapResize(
|
|
timer: TimingTracker,
|
|
bitmap: Bitmap,
|
|
scaleX: Float,
|
|
scaleY: Float,
|
|
restriction: Range2d?
|
|
): Boolean {
|
|
// println("Doing resize $inSizeX x $inSizeY x $vectorSize, $scaleX x $scaleY, $restriction")
|
|
val outSizeX = (bitmap.width * scaleX).toInt()
|
|
val outSizeY = (bitmap.height * scaleY).toInt()
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicResize") {
|
|
intrinsicResize(renderscriptContext, bitmap, outSizeX, outSizeY, restriction)
|
|
}
|
|
val toolkitOutBitmap = timer.measure("ToolkitResize") {
|
|
toolkit.resize(bitmap, outSizeX, outSizeY, restriction)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceResize") {
|
|
referenceResize(
|
|
getBitmapBytes(bitmap),
|
|
vectorSizeOfBitmap(bitmap),
|
|
bitmap.width,
|
|
bitmap.height,
|
|
outSizeX,
|
|
outSizeY,
|
|
restriction
|
|
)
|
|
}
|
|
|
|
val toolkitOutArray = getBitmapBytes(toolkitOutBitmap)
|
|
return validateSame("ResizeBitmap", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("ResizeBitmap by ($scaleX, $scaleY) to ($outSizeX, $outSizeY), $restriction")
|
|
//logArray("ResizeBitmap in ", inputArray, 100)
|
|
logArray("ResizeBitmap reference out", referenceOutArray)
|
|
logArray("ResizeBitmap intrinsic out", intrinsicOutArray)
|
|
logArray("ResizeBitmap toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testYuvToRgb(timer: TimingTracker): Boolean {
|
|
val layoutsToTry = listOf(
|
|
// Don't try sizeX with odd values. That's not allowed by definition of some
|
|
// of the video formats.
|
|
TestLayout(10, 14, null),
|
|
TestLayout(64, 40, null),
|
|
TestLayout(96, 94, null),
|
|
)
|
|
return layoutsToTry.all { (sizeX, sizeY, _) ->
|
|
YuvFormat.values().all { format ->
|
|
testOneRandomYuvToRgb(timer, sizeX, sizeY, format) and
|
|
testOneRandomYuvToRgbBitmap(timer, sizeX, sizeY, format)
|
|
}
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomYuvToRgb(
|
|
timer: TimingTracker,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
format: YuvFormat
|
|
): Boolean {
|
|
// The RenderScript Intrinsic does not handle this combination correctly.
|
|
if (format == YuvFormat.YV12 && sizeX % 32 != 0) {
|
|
return true
|
|
}
|
|
val inputArray = randomYuvArray(0x50521f0, sizeX, sizeY, format)
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicYuvToRgb") {
|
|
intrinsicYuvToRgb(renderscriptContext, inputArray, sizeX, sizeY, format)
|
|
}
|
|
val toolkitOutArray = timer.measure("ToolkitYuvToRgb") {
|
|
toolkit.yuvToRgb(inputArray, sizeX, sizeY, format)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceYuvToRgb") {
|
|
referenceYuvToRgb(inputArray, sizeX, sizeY, format)
|
|
}
|
|
|
|
return validateSame("yuvToRgb", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("yuvToRgb ($sizeX, $sizeY) $format")
|
|
logArray("yuvToRgb in ", inputArray)
|
|
logArray("yuvToRgb reference out", referenceOutArray)
|
|
logArray("yuvToRgb intrinsic out", intrinsicOutArray)
|
|
logArray("yuvToRgb toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun testOneRandomYuvToRgbBitmap(
|
|
timer: TimingTracker,
|
|
sizeX: Int,
|
|
sizeY: Int,
|
|
format: YuvFormat
|
|
): Boolean {
|
|
// The RenderScript Intrinsic does not handle this combination correctly.
|
|
if (format == YuvFormat.YV12 && sizeX % 32 != 0) {
|
|
return true
|
|
}
|
|
val inputArray = randomYuvArray(0x50521f0, sizeX, sizeY, format)
|
|
|
|
val intrinsicOutArray = timer.measure("IntrinsicYuvToRgb") {
|
|
intrinsicYuvToRgb(renderscriptContext, inputArray, sizeX, sizeY, format)
|
|
}
|
|
val toolkitOutBitmap = timer.measure("ToolkitYuvToRgb") {
|
|
toolkit.yuvToRgbBitmap(inputArray, sizeX, sizeY, format)
|
|
}
|
|
if (!validate) return true
|
|
|
|
val referenceOutArray = timer.measure("ReferenceYuvToRgb") {
|
|
referenceYuvToRgb(inputArray, sizeX, sizeY, format)
|
|
}
|
|
|
|
val toolkitOutArray = getBitmapBytes(toolkitOutBitmap)
|
|
return validateSame("yuvToRgb", intrinsicOutArray, referenceOutArray, toolkitOutArray) {
|
|
println("yuvToRgb ($sizeX, $sizeY) $format")
|
|
logArray("yuvToRgb in ", inputArray)
|
|
logArray("yuvToRgb reference out", referenceOutArray)
|
|
logArray("yuvToRgb intrinsic out", intrinsicOutArray)
|
|
logArray("yuvToRgb toolkit out", toolkitOutArray)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verifies that the arrays returned by the Intrinsic, the reference code, and the Toolkit
|
|
* are all within a margin of error.
|
|
*
|
|
* RenderScript Intrinsic test (rc/android/cts/rscpp/RSCppTest.java) used 3 for ints.
|
|
* For floats, rc/android/cts/rscpp/verify.rscript uses 0.0001f.
|
|
*/
|
|
@ExperimentalUnsignedTypes
|
|
private fun validateSame(
|
|
task: String,
|
|
intrinsic: ByteArray,
|
|
reference: ByteArray,
|
|
toolkit: ByteArray,
|
|
skipFourth: Boolean = false,
|
|
allowedIntDelta: Int = 3,
|
|
errorLogging: () -> Unit
|
|
): Boolean {
|
|
val success = validateAgainstReference(
|
|
task, reference, "Intrinsic", intrinsic, skipFourth, allowedIntDelta
|
|
) and validateAgainstReference(
|
|
task, reference, "Toolkit", toolkit, skipFourth, allowedIntDelta
|
|
)
|
|
if (!success) {
|
|
println("$task FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!")
|
|
errorLogging()
|
|
}
|
|
return success
|
|
}
|
|
|
|
private fun validateSame(
|
|
task: String,
|
|
intrinsic: IntArray,
|
|
reference: IntArray,
|
|
toolkit: IntArray,
|
|
allowedIntDelta: Int = 3,
|
|
errorLogging: () -> Unit
|
|
): Boolean {
|
|
val success = validateAgainstReference(
|
|
task, reference, "Intrinsic", intrinsic, allowedIntDelta
|
|
) and validateAgainstReference(
|
|
task, reference, "Toolkit", toolkit, allowedIntDelta
|
|
)
|
|
if (!success) {
|
|
println("$task FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!")
|
|
errorLogging()
|
|
}
|
|
return success
|
|
}
|
|
|
|
@ExperimentalUnsignedTypes
|
|
private fun validateAgainstReference(
|
|
task: String,
|
|
in1: ByteArray,
|
|
name2: String,
|
|
in2: ByteArray,
|
|
skipFourth: Boolean,
|
|
allowedIntDelta: Int
|
|
): Boolean {
|
|
if (in1.size != in2.size) {
|
|
println("$task. Sizes don't match: Reference ${in1.size}, $name2 ${in2.size}")
|
|
return false
|
|
}
|
|
var same = true
|
|
val maxDetails = 80
|
|
val diffs = CharArray(min(in1.size, maxDetails)) {'.'}
|
|
for (i in in1.indices) {
|
|
if (skipFourth && i % 4 == 3) {
|
|
continue
|
|
}
|
|
val delta = abs(in1[i].toUByte().toInt() - in2[i].toUByte().toInt())
|
|
if (delta > allowedIntDelta) {
|
|
if (same) {
|
|
println(
|
|
"$task. At $i, Reference is ${in1[i].toUByte()}, $name2 is ${in2[i].toUByte()}"
|
|
)
|
|
}
|
|
if (i < maxDetails) diffs[i] = 'X'
|
|
same = false
|
|
}
|
|
}
|
|
if (!same) {
|
|
for (i in 0 until (min(in1.size, maxDetails) / 4)) print("%-3d|".format(i))
|
|
println()
|
|
println(diffs)
|
|
}
|
|
return same
|
|
}
|
|
|
|
private fun validateAgainstReference(
|
|
task: String,
|
|
in1: IntArray,
|
|
name2: String,
|
|
in2: IntArray,
|
|
allowedIntDelta: Int
|
|
): Boolean {
|
|
if (in1.size != in2.size) {
|
|
println("$task. Sizes don't match: Reference ${in1.size}, $name2 ${in2.size}")
|
|
return false
|
|
}
|
|
for (i in in1.indices) {
|
|
val delta = abs(in1[i] - in2[i])
|
|
if (delta > allowedIntDelta) {
|
|
println("$task. At $i, Reference is ${in1[i]}, $name2 is ${in2[i]}")
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
}
|