1 /* <lambda>null2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // TODO Rename to something better 18 package com.example.testapp 19 20 import android.content.Context 21 import android.graphics.Bitmap 22 import android.graphics.BitmapFactory 23 import android.renderscript.RenderScript 24 import android.renderscript.toolkit.BlendingMode 25 import android.renderscript.toolkit.LookupTable 26 import android.renderscript.toolkit.Range2d 27 import android.renderscript.toolkit.Rgba3dArray 28 import android.renderscript.toolkit.Toolkit 29 import android.renderscript.toolkit.YuvFormat 30 import kotlin.math.abs 31 import kotlin.math.min 32 33 data class TestLayout( 34 val sizeX: Int, 35 val sizeY: Int, 36 val restriction: Range2d? 37 ) 38 39 // List of dimensions (sizeX, sizeY) to try when generating random data. 40 val commonLayoutsToTry = listOf( 41 // Small layouts to start with 42 TestLayout(3, 4, null), 43 TestLayout(3, 4, Range2d(0, 1, 0, 3)), 44 TestLayout(3, 4, Range2d(2, 3, 1, 4)), 45 TestLayout(10, 14, null), 46 TestLayout(10, 14, Range2d(2, 3, 8, 14)), 47 // The size of most CTS intrinsic tests 48 TestLayout(160, 100, null), 49 TestLayout(125, 227, Range2d(50, 125, 100, 227)), 50 // A larger one 51 TestLayout(800, 600, null), 52 // Weirdly shaped ones 53 TestLayout(1, 1, null), // A single item 54 // TODO This size makes Intrinsic Blur fail. 55 TestLayout(16000, 1, null), // A single item 56 TestLayout(1, 16000, null), // One large row 57 // A very large test 58 TestLayout(1024, 2048, null), 59 ) 60 61 62 class Tester(context: Context, private val validate: Boolean) { 63 private val renderscriptContext = RenderScript.create(context) 64 private val toolkit = Toolkit() 65 private val testImage1 = BitmapFactory.decodeResource(context.resources, R.drawable.img800x450a) 66 private val testImage2 = BitmapFactory.decodeResource(context.resources, R.drawable.img800x450b) 67 68 init { 69 validateTestImage(testImage1) 70 validateTestImage(testImage2) 71 } 72 73 /** 74 * Verify that the test images are in format that works for our tests. 75 */ 76 private fun validateTestImage(bitmap: Bitmap) { 77 require(bitmap.config == Bitmap.Config.ARGB_8888) 78 require(bitmap.rowBytes == bitmap.width * 4) { 79 "Can't handle bitmaps that have extra padding. " + 80 "${bitmap.rowBytes} != ${bitmap.width} * 4." } 81 require(bitmap.byteCount == bitmap.rowBytes * bitmap.height) 82 } 83 84 fun destroy() { 85 renderscriptContext.destroy() 86 } 87 88 @ExperimentalUnsignedTypes 89 fun testAll(timer: TimingTracker): String { 90 val tests = listOf( 91 Pair("blend", ::testBlend), 92 Pair("blur", ::testBlur), 93 Pair("colorMatrix", ::testColorMatrix), 94 Pair("convolve", ::testConvolve), 95 Pair("histogram", ::testHistogram), 96 Pair("lut", ::testLut), 97 Pair("lut3d", ::testLut3d), 98 Pair("resize", ::testResize), 99 Pair("yuvToRgb", ::testYuvToRgb), 100 ) 101 val results = Array(tests.size) { "" } 102 for (i in tests.indices) { 103 val (name, test) = tests[i] 104 println("Doing $name") 105 val success = test(timer) 106 results[i] = "$name " + if (success) "succeeded" else "FAILED! FAILED! FAILED! FAILED!" 107 println(" ${results[i]}") 108 } 109 110 return results.joinToString("\n") 111 } 112 113 @ExperimentalUnsignedTypes 114 private fun testBlend(timer: TimingTracker): Boolean { 115 return BlendingMode.values().all { mode -> 116 testOneBitmapBlend(timer, testImage1, testImage2, mode, null) and 117 testOneBitmapBlend( 118 timer, testImage1, testImage2, mode, 119 Range2d(6, 23, 2, 4) 120 ) and 121 commonLayoutsToTry.all { (sizeX, sizeY, restriction) -> 122 testOneRandomBlend(timer, sizeX, sizeY, mode, restriction) 123 } 124 } 125 } 126 127 @ExperimentalUnsignedTypes 128 private fun testOneRandomBlend( 129 timer: TimingTracker, 130 sizeX: Int, 131 sizeY: Int, 132 mode: BlendingMode, 133 restriction: Range2d? 134 ): Boolean { 135 val sourceArray = randomByteArray(0x50521f0, sizeX, sizeY, 4) 136 val destArray = randomByteArray(0x2932147, sizeX, sizeY, 4) 137 // Make clones because these will be modified by the blend. 138 val intrinsicDestArray = destArray.clone() 139 val referenceDestArray = destArray.clone() 140 val toolkitDestArray = destArray.clone() 141 142 timer.measure("IntrinsicBlend") { 143 intrinsicBlend( 144 renderscriptContext, mode, sourceArray, intrinsicDestArray, sizeX, sizeY, 145 restriction 146 ) 147 } 148 timer.measure("ToolkitBlend") { 149 toolkit.blend(mode, sourceArray, toolkitDestArray, sizeX, sizeY, restriction) 150 } 151 if (!validate) return true 152 153 timer.measure("ReferenceBlend") { 154 referenceBlend(mode, sourceArray, referenceDestArray, sizeX, sizeY, restriction) 155 } 156 157 return validateSame( 158 "Blend_$mode", intrinsicDestArray, referenceDestArray, toolkitDestArray 159 ) { 160 println("blend $mode ($sizeX, $sizeY) $restriction") 161 logArray("Blend_$mode src", sourceArray, 48) 162 logArray("Blend_$mode dst", destArray, 48) 163 logArray("Blend_$mode reference out", referenceDestArray, 48) 164 logArray("Blend_$mode intrinsic out", intrinsicDestArray, 48) 165 logArray("Blend_$mode toolkit out", toolkitDestArray, 48) 166 } 167 } 168 169 @ExperimentalUnsignedTypes 170 private fun testOneBitmapBlend( 171 timer: TimingTracker, 172 sourceBitmap: Bitmap, 173 destBitmap: Bitmap, 174 mode: BlendingMode, 175 restriction: Range2d? 176 ): Boolean { 177 // Make clones because these will be modified by the blend. 178 val intrinsicDestBitmap = duplicateBitmap(destBitmap) 179 val toolkitDestBitmap = duplicateBitmap(destBitmap) 180 val referenceDestBitmap = duplicateBitmap(destBitmap) 181 182 timer.measure("IntrinsicBlend") { 183 intrinsicBlend( 184 renderscriptContext, mode, sourceBitmap, intrinsicDestBitmap, restriction 185 ) 186 } 187 timer.measure("ToolkitBlend") { 188 toolkit.blend(mode, sourceBitmap, toolkitDestBitmap, restriction) 189 } 190 if (!validate) return true 191 192 val referenceDestArray = getBitmapBytes(referenceDestBitmap) 193 timer.measure("ReferenceBlend") { 194 referenceBlend( 195 mode, getBitmapBytes(sourceBitmap), referenceDestArray, sourceBitmap.width, 196 sourceBitmap.height, restriction 197 ) 198 } 199 200 val intrinsicDestArray = getBitmapBytes(intrinsicDestBitmap) 201 val toolkitDestArray = getBitmapBytes(toolkitDestBitmap) 202 return validateSame( 203 "BlendBitmap_$mode", intrinsicDestArray, referenceDestArray, toolkitDestArray 204 ) { 205 println("BlendBitmap $mode $restriction") 206 //logArray("BlendBitmap_$mode src", sourceArray, 48) 207 //logArray("BlendBitmap_$mode dst", destArray, 48) 208 logArray("BlendBitmap_$mode reference out", referenceDestArray, 48) 209 logArray("BlendBitmap_$mode intrinsic out", intrinsicDestArray, 48) 210 logArray("BlendBitmap_$mode toolkit out", toolkitDestArray, 48) 211 } 212 } 213 214 @ExperimentalUnsignedTypes 215 private fun testBlur(timer: TimingTracker): Boolean { 216 return arrayOf(1, 3, 8, 25).all { radius -> 217 testOneBitmapBlur(timer, testImage1, radius, null) and 218 testOneBitmapBlur(timer, testImage1, radius, Range2d(6, 23, 2, 4)) and 219 commonLayoutsToTry.all { (sizeX, sizeY, restriction) -> 220 arrayOf(1, 4).all { vectorSize -> 221 testOneRandomBlur(timer, vectorSize, sizeX, sizeY, radius, restriction) 222 } 223 } 224 } 225 } 226 227 @ExperimentalUnsignedTypes 228 private fun testOneRandomBlur( 229 timer: TimingTracker, 230 vectorSize: Int, 231 sizeX: Int, 232 sizeY: Int, 233 radius: Int, 234 restriction: Range2d? 235 ): Boolean { 236 val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, vectorSize) 237 val intrinsicOutArray = timer.measure("IntrinsicBlur") { 238 intrinsicBlur( 239 renderscriptContext, inputArray, vectorSize, sizeX, sizeY, radius, restriction 240 ) 241 } 242 val toolkitOutArray = timer.measure("ToolkitBlur") { 243 toolkit.blur(inputArray, vectorSize, sizeX, sizeY, radius, restriction) 244 } 245 if (!validate) return true 246 247 val referenceOutArray = timer.measure("ReferenceBlur") { 248 referenceBlur(inputArray, vectorSize, sizeX, sizeY, radius, restriction) 249 } 250 return validateSame("blur", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 251 println("blur $vectorSize ($sizeX, $sizeY) radius = $radius $restriction") 252 logArray("blur input ", inputArray) 253 logArray("blur reference out", referenceOutArray) 254 logArray("blur intrinsic out", intrinsicOutArray) 255 logArray("blur toolkit out", toolkitOutArray) 256 } 257 } 258 259 @ExperimentalUnsignedTypes 260 private fun testOneBitmapBlur( 261 timer: TimingTracker, 262 bitmap: Bitmap, 263 radius: Int, 264 restriction: Range2d? 265 ): Boolean { 266 val intrinsicOutArray = timer.measure("IntrinsicBlur") { 267 intrinsicBlur(renderscriptContext, bitmap, radius, restriction) 268 } 269 270 val toolkitOutBitmap = timer.measure("ToolkitBlur") { 271 toolkit.blur(bitmap, radius, restriction) 272 } 273 if (!validate) return true 274 275 val referenceOutArray = timer.measure("ReferenceBlur") { 276 referenceBlur( 277 getBitmapBytes(bitmap), 278 vectorSizeOfBitmap(bitmap), 279 bitmap.width, 280 bitmap.height, 281 radius, 282 restriction 283 ) 284 } 285 286 val toolkitOutArray = getBitmapBytes(toolkitOutBitmap) 287 return validateSame("blur", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 288 println("BlurBitmap ${bitmap.config} $radius $restriction") 289 logArray("blur reference out", referenceOutArray) 290 logArray("blur intrinsic out", intrinsicOutArray) 291 logArray("blur toolkit out", toolkitOutArray) 292 } 293 } 294 295 enum class ColorMatrixConversionType { 296 RGB_TO_YUV, 297 YUV_TO_RGB, 298 GREYSCALE, 299 RANDOM 300 } 301 302 @ExperimentalUnsignedTypes 303 private fun testColorMatrix(timer: TimingTracker): Boolean { 304 return ColorMatrixConversionType.values().all { conversion -> 305 testOneBitmapColorMatrix(timer, testImage1, conversion, null) and 306 testOneBitmapColorMatrix( 307 timer, 308 testImage1, 309 conversion, 310 Range2d(6, 23, 2, 4) 311 ) and 312 commonLayoutsToTry.all { (sizeX, sizeY, restriction) -> 313 (1..4).all { inputVectorSize -> 314 (1..4).all { outputVectorSize -> 315 testOneRandomColorMatrix( 316 timer, 317 inputVectorSize, 318 sizeX, 319 sizeY, 320 outputVectorSize, 321 conversion, 322 restriction 323 ) 324 } 325 } 326 } 327 } 328 } 329 330 @ExperimentalUnsignedTypes 331 private fun testOneRandomColorMatrix( 332 timer: TimingTracker, 333 inputVectorSize: Int, 334 sizeX: Int, 335 sizeY: Int, 336 outputVectorSize: Int, 337 conversion: ColorMatrixConversionType, 338 restriction: Range2d? 339 ): Boolean { 340 val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, paddedSize(inputVectorSize)) 341 val addVector = randomFloatArray(0x243238, 4, 1, 1, 0.3f) 342 val matrix = when (conversion) { 343 ColorMatrixConversionType.RGB_TO_YUV -> toolkit.rgbToYuvMatrix 344 ColorMatrixConversionType.YUV_TO_RGB -> toolkit.yuvToRgbMatrix 345 ColorMatrixConversionType.GREYSCALE -> toolkit.greyScaleColorMatrix 346 ColorMatrixConversionType.RANDOM -> randomFloatArray(0x234348, 4, 4, 1) 347 } 348 349 val intrinsicOutArray = timer.measure("IntrinsicColorMatrix") { 350 intrinsicColorMatrix( 351 renderscriptContext, 352 conversion, 353 inputArray, 354 inputVectorSize, 355 sizeX, 356 sizeY, 357 outputVectorSize, 358 matrix, 359 addVector, 360 restriction 361 ) 362 } 363 val toolkitOutArray = timer.measure("ToolkitColorMatrix") { 364 toolkit.colorMatrix( 365 inputArray, 366 inputVectorSize, 367 sizeX, 368 sizeY, 369 outputVectorSize, 370 matrix, 371 addVector, 372 restriction 373 ) 374 } 375 if (!validate) return true 376 377 val referenceOutArray = timer.measure("ReferenceColorMatrix") { 378 referenceColorMatrix( 379 inputArray, inputVectorSize, sizeX, sizeY, outputVectorSize, matrix, addVector, 380 restriction 381 ) 382 } 383 384 return validateSame("colorMatrix", intrinsicOutArray, referenceOutArray, toolkitOutArray, 385 outputVectorSize == 3) { 386 println("colorMatrix ($sizeX, $sizeY) $inputVectorSize->$outputVectorSize $restriction") 387 logArray("colorMatrix matrix ", matrix, 16) 388 logArray("colorMatrix addVector", addVector, 4) 389 logArray("colorMatrix in ", inputArray) 390 logArray("colorMatrix reference out", referenceOutArray, 300) 391 logArray("colorMatrix intrinsic out", intrinsicOutArray, 300) 392 logArray("colorMatrix toolkit out", toolkitOutArray, 300) 393 } 394 } 395 396 @ExperimentalUnsignedTypes 397 private fun testOneBitmapColorMatrix( 398 timer: TimingTracker, 399 bitmap: Bitmap, 400 conversion: ColorMatrixConversionType, 401 restriction: Range2d? 402 ): Boolean { 403 val addVector = randomFloatArray(0x243238, 4, 1, 1, 0.3f) 404 val matrix = when (conversion) { 405 ColorMatrixConversionType.RGB_TO_YUV -> toolkit.rgbToYuvMatrix 406 ColorMatrixConversionType.YUV_TO_RGB -> toolkit.yuvToRgbMatrix 407 ColorMatrixConversionType.GREYSCALE -> toolkit.greyScaleColorMatrix 408 ColorMatrixConversionType.RANDOM -> randomFloatArray(0x234348, 4, 4, 1) 409 } 410 411 val intrinsicOutArray = timer.measure("IntrinsicColorMatrix") { 412 intrinsicColorMatrix( 413 renderscriptContext, conversion, bitmap, matrix, addVector, restriction 414 ) 415 } 416 val toolkitOutBitmap = timer.measure("ToolkitColorMatrix") { 417 toolkit.colorMatrix(bitmap, matrix, addVector, restriction) 418 } 419 if (!validate) return true 420 421 val referenceOutArray = timer.measure("ReferenceColorMatrix") { 422 referenceColorMatrix( 423 getBitmapBytes(bitmap), vectorSizeOfBitmap(bitmap), bitmap.width, bitmap.height, 424 vectorSizeOfBitmap(bitmap), matrix, addVector, restriction 425 ) 426 } 427 428 val toolkitOutArray = getBitmapBytes(toolkitOutBitmap) 429 return validateSame("ColorMatrix", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 430 println("colorMatrixBitmap $restriction") 431 logArray("colorMatrixBitmap matrix ", matrix, 16) 432 logArray("colorMatrixBitmap addVector", addVector, 4) 433 logArray("colorMatrixBitmap reference out", referenceOutArray) 434 logArray("colorMatrixBitmap intrinsic out", intrinsicOutArray) 435 logArray("colorMatrixBitmap toolkit out", toolkitOutArray) 436 } 437 } 438 439 @ExperimentalUnsignedTypes 440 private fun testConvolve(timer: TimingTracker): Boolean { 441 val coefficientsToTry = listOf( 442 randomFloatArray(0x2937021, 3, 3, 1, 0.1f), 443 randomFloatArray(0x2937021, 5, 5, 1, 0.05f) 444 ) 445 return coefficientsToTry.all { coefficients -> 446 testOneBitmapConvolve(timer, testImage1, coefficients, null) and 447 testOneBitmapConvolve(timer, testImage1, coefficients, Range2d(6, 23, 2, 4)) and 448 449 commonLayoutsToTry.all { (sizeX, sizeY, restriction) -> 450 (1..4).all { vectorSize -> 451 testOneRandomConvolve( 452 timer, 453 vectorSize, 454 sizeX, 455 sizeY, 456 coefficients, 457 restriction 458 ) 459 } 460 } 461 } 462 } 463 464 @ExperimentalUnsignedTypes 465 private fun testOneRandomConvolve( 466 timer: TimingTracker, 467 vectorSize: Int, 468 sizeX: Int, 469 sizeY: Int, 470 coefficients: FloatArray, 471 restriction: Range2d? 472 ): Boolean { 473 val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, paddedSize(vectorSize)) 474 475 val intrinsicOutArray = timer.measure("IntrinsicConvolve") { 476 intrinsicConvolve( 477 renderscriptContext, inputArray, vectorSize, sizeX, sizeY, coefficients, restriction 478 ) 479 } 480 val toolkitOutArray = timer.measure("ToolkitConvolve") { 481 toolkit.convolve(inputArray, vectorSize, sizeX, sizeY, coefficients, restriction) 482 } 483 if (!validate) return true 484 485 val referenceOutArray = timer.measure("ReferenceConvolve") { 486 referenceConvolve(inputArray, vectorSize, sizeX, sizeY, coefficients, restriction) 487 } 488 489 val task = if (coefficients.size == 9) "convolve3x3 $vectorSize" else "convolve5x5 $vectorSize" 490 return validateSame(task, intrinsicOutArray, referenceOutArray, toolkitOutArray) { 491 println("Convolve $vectorSize ($sizeX, $sizeY) $restriction") 492 logArray("Convolve coefficients", coefficients, 25) 493 logArray("Convolve in ", inputArray) 494 logArray("Convolve reference out", referenceOutArray) 495 logArray("Convolve intrinsic out", intrinsicOutArray) 496 logArray("Convolve toolkit out", toolkitOutArray) 497 } 498 } 499 500 @ExperimentalUnsignedTypes 501 private fun testOneBitmapConvolve( 502 timer: TimingTracker, 503 bitmap: Bitmap, 504 coefficients: FloatArray, 505 restriction: Range2d? 506 ): Boolean { 507 val intrinsicOutArray = timer.measure("IntrinsicConvolve") { 508 intrinsicConvolve(renderscriptContext, bitmap, coefficients, restriction) 509 } 510 val toolkitOutBitmap = timer.measure("ToolkitConvolve") { 511 toolkit.convolve(bitmap, coefficients, restriction) 512 } 513 if (!validate) return true 514 515 val referenceOutArray = timer.measure("ReferenceConvolve") { 516 referenceConvolve( 517 getBitmapBytes(bitmap), vectorSizeOfBitmap(bitmap), bitmap.width, bitmap.height, 518 coefficients, restriction 519 ) 520 } 521 522 val task = if (coefficients.size == 9) "convolve3x3" else "convolve5x5" 523 val toolkitOutArray = getBitmapBytes(toolkitOutBitmap) 524 return validateSame(task, intrinsicOutArray, referenceOutArray, toolkitOutArray) { 525 println("ConvolveBitmap $restriction") 526 logArray("ConvolveBitmap coefficients", coefficients, 25) 527 //logArray("ConvolveBitmap in ", inputArray) 528 logArray("ConvolveBitmap reference out", referenceOutArray) 529 logArray("ConvolveBitmap intrinsic out", intrinsicOutArray) 530 logArray("ConvolveBitmap toolkit out", toolkitOutArray) 531 } 532 } 533 534 @ExperimentalUnsignedTypes 535 private fun testHistogram(timer: TimingTracker): Boolean { 536 val coefficients = floatArrayOf(0.1f, 0.3f, 0.5f, 0.05f) 537 return testOneBitmapHistogram(timer, testImage1, null) and 538 testOneBitmapHistogram(timer, testImage1, Range2d(6, 23, 2, 4)) and 539 testOneBitmapHistogramDot(timer, testImage1, null, null) and 540 testOneBitmapHistogramDot(timer, testImage1, coefficients, null) and 541 testOneBitmapHistogramDot(timer, testImage1, coefficients, Range2d(6, 23, 2, 4)) and 542 commonLayoutsToTry.all { (sizeX, sizeY, restriction) -> 543 (1..4).all { vectorSize -> 544 testOneRandomHistogram(timer, vectorSize, sizeX, sizeY, restriction) && 545 testOneRandomHistogramDot( 546 timer, 547 vectorSize, 548 sizeX, 549 sizeY, 550 null, 551 restriction 552 ) && 553 testOneRandomHistogramDot( 554 timer, 555 vectorSize, 556 sizeX, 557 sizeY, 558 coefficients.sliceArray(0 until vectorSize), 559 restriction 560 ) 561 } 562 } 563 } 564 565 @ExperimentalUnsignedTypes 566 private fun testOneRandomHistogram( 567 timer: TimingTracker, 568 vectorSize: Int, 569 sizeX: Int, 570 sizeY: Int, 571 restriction: Range2d? 572 ): Boolean { 573 val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, paddedSize(vectorSize)) 574 575 val intrinsicOutput = timer.measure("IntrinsicHistogram") { 576 intrinsicHistogram( 577 renderscriptContext, inputArray, vectorSize, sizeX, sizeY, restriction 578 ) 579 } 580 val toolkitOutput = timer.measure("ToolkitHistogram") { 581 toolkit.histogram(inputArray, vectorSize, sizeX, sizeY, restriction) 582 } 583 if (!validate) return true 584 585 val referenceOutput = timer.measure("ReferenceHistogram") { 586 referenceHistogram( 587 inputArray, vectorSize, sizeX, sizeY, restriction 588 ) 589 } 590 591 return validateSame("histogram", intrinsicOutput, referenceOutput, toolkitOutput, 0) { 592 println("histogram $vectorSize ($sizeX, $sizeY) $restriction") 593 logArray("histogram in ", inputArray, 200) 594 logArray("histogram reference out", referenceOutput, 200) 595 logArray("histogram intrinsic out", intrinsicOutput, 200) 596 logArray("histogram toolkit out", toolkitOutput, 200) 597 } 598 } 599 600 @ExperimentalUnsignedTypes 601 private fun testOneBitmapHistogram( 602 timer: TimingTracker, 603 bitmap: Bitmap, 604 restriction: Range2d? 605 ): Boolean { 606 val intrinsicOutput = timer.measure("IntrinsicHistogram") { 607 intrinsicHistogram(renderscriptContext, bitmap, restriction) 608 } 609 val toolkitOutput = timer.measure("ToolkitHistogram") { 610 toolkit.histogram(bitmap, restriction) 611 } 612 if (!validate) return true 613 614 val referenceOutput = timer.measure("ReferenceHistogram") { 615 referenceHistogram( 616 getBitmapBytes(bitmap), vectorSizeOfBitmap(bitmap), bitmap.width, bitmap.height, 617 restriction 618 ) 619 } 620 621 return validateSame("histogram", intrinsicOutput, referenceOutput, toolkitOutput, 0) { 622 println("HistogramBitmap $restriction") 623 logArray("HistogramBitmap reference out", referenceOutput) 624 logArray("HistogramBitmap intrinsic out", intrinsicOutput) 625 logArray("HistogramBitmap toolkit out", toolkitOutput) 626 } 627 } 628 629 @ExperimentalUnsignedTypes 630 private fun testOneRandomHistogramDot( 631 timer: TimingTracker, 632 vectorSize: Int, 633 sizeX: Int, 634 sizeY: Int, 635 coefficients: FloatArray?, restriction: Range2d? 636 ): Boolean { 637 val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, paddedSize(vectorSize)) 638 639 val intrinsicOutArray = timer.measure("IntrinsicHistogramDot") { 640 intrinsicHistogramDot( 641 renderscriptContext, inputArray, vectorSize, sizeX, sizeY, coefficients, restriction 642 ) 643 } 644 val toolkitOutArray = timer.measure("ToolkitHistogramDot") { 645 toolkit.histogramDot( 646 inputArray, vectorSize, sizeX, sizeY, coefficients, restriction 647 ) 648 } 649 if (!validate) return true 650 651 val referenceOutArray = timer.measure("ReferenceHistogramDot") { 652 referenceHistogramDot(inputArray, vectorSize, sizeX, sizeY, coefficients, restriction) 653 } 654 655 return validateSame("histogramDot", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 656 println("histogramDot $vectorSize ($sizeX, $sizeY) $restriction") 657 logArray("histogramDot coefficients ", coefficients) 658 logArray("histogramDot in ", inputArray) 659 logArray("histogramDot reference out", referenceOutArray, 256) 660 logArray("histogramDot intrinsic out", intrinsicOutArray, 256) 661 logArray("histogramDot toolkit out", toolkitOutArray, 256) 662 } 663 } 664 665 @ExperimentalUnsignedTypes 666 private fun testOneBitmapHistogramDot( 667 timer: TimingTracker, 668 bitmap: Bitmap, 669 coefficients: FloatArray?, 670 restriction: Range2d? 671 ): Boolean { 672 val intrinsicOutArray = timer.measure("IntrinsicHistogramDot") { 673 intrinsicHistogramDot(renderscriptContext, bitmap, coefficients, restriction) 674 } 675 val toolkitOutArray = timer.measure("ToolkitHistogramDot") { 676 toolkit.histogramDot(bitmap, coefficients, restriction) 677 } 678 if (!validate) return true 679 680 val referenceOutArray = timer.measure("ReferenceHistogramDot") { 681 referenceHistogramDot( 682 getBitmapBytes(bitmap), 683 vectorSizeOfBitmap(bitmap), 684 bitmap.width, 685 bitmap.height, 686 coefficients, 687 restriction 688 ) 689 } 690 691 return validateSame( 692 "HistogramDotBitmap", 693 intrinsicOutArray, 694 referenceOutArray, 695 toolkitOutArray 696 ) { 697 println("HistogramDotBitmap $restriction") 698 logArray("HistogramDotBitmap coefficients ", coefficients) 699 //logArray("HistogramDotBitmap in ", inputArray) 700 logArray("HistogramDotBitmap reference out", referenceOutArray, 256) 701 logArray("HistogramDotBitmap intrinsic out", intrinsicOutArray, 256) 702 logArray("HistogramDotBitmap toolkit out", toolkitOutArray, 256) 703 } 704 } 705 706 @ExperimentalUnsignedTypes 707 private fun testLut(timer: TimingTracker): Boolean { 708 return testOneBitmapLut(timer, testImage1, null) and 709 testOneBitmapLut(timer, testImage1, Range2d(6, 23, 2, 4)) and 710 commonLayoutsToTry.all { (sizeX, sizeY, restriction) -> 711 testOneRandomLut(timer, sizeX, sizeY, restriction) 712 } 713 } 714 715 @ExperimentalUnsignedTypes 716 private fun testOneRandomLut( 717 timer: TimingTracker, 718 sizeX: Int, 719 sizeY: Int, 720 restriction: Range2d? 721 ): Boolean { 722 val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, 4) 723 val newRed = randomByteArray(0x32425, 256, 1, 1) 724 val newGreen = randomByteArray(0x1F3225, 256, 1, 1) 725 val newBlue = randomByteArray(0x32D4F27, 256, 1, 1) 726 val newAlpha = randomByteArray(0x3A20001, 256, 1, 1) 727 val table = LookupTable() 728 table.red = newRed 729 table.blue = newBlue 730 table.green = newGreen 731 table.alpha = newAlpha 732 733 val intrinsicOutArray = timer.measure("IntrinsicLUT") { 734 intrinsicLut( 735 renderscriptContext, inputArray, sizeX, sizeY, newRed, newGreen, newBlue, newAlpha, 736 restriction 737 ) 738 } 739 val toolkitOutArray = timer.measure("ToolkitLUT") { 740 toolkit.lut(inputArray, sizeX, sizeY, table, restriction) 741 } 742 if (!validate) return true 743 744 val referenceOutArray = timer.measure("ReferenceLUT") { 745 referenceLut(inputArray, sizeX, sizeY, table, restriction) 746 } 747 748 return validateSame("LUT", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 749 println("lut ($sizeX, $sizeY) $restriction") 750 logArray("LUT red ", newRed, 256) 751 logArray("LUT green", newGreen, 256) 752 logArray("LUT blue ", newBlue, 256) 753 logArray("LUT alpha", newAlpha, 256) 754 logArray("LUT in ", inputArray) 755 logArray("LUT reference out", referenceOutArray) 756 logArray("LUT intrinsic out", intrinsicOutArray) 757 logArray("LUT toolkit out", toolkitOutArray) 758 } 759 } 760 761 @ExperimentalUnsignedTypes 762 private fun testOneBitmapLut( 763 timer: TimingTracker, 764 bitmap: Bitmap, 765 restriction: Range2d? 766 ): Boolean { 767 val newRed = randomByteArray(0x32425, 256, 1, 1) 768 val newGreen = randomByteArray(0x1F3225, 256, 1, 1) 769 val newBlue = randomByteArray(0x32D4F27, 256, 1, 1) 770 val newAlpha = randomByteArray(0x3A20001, 256, 1, 1) 771 val table = LookupTable() 772 table.red = newRed 773 table.blue = newBlue 774 table.green = newGreen 775 table.alpha = newAlpha 776 777 val intrinsicOutArray = timer.measure("IntrinsicLUT") { 778 intrinsicLut( 779 renderscriptContext, bitmap, newRed, newGreen, newBlue, newAlpha, restriction 780 ) 781 } 782 val toolkitOutBitmap = timer.measure("ToolkitLUT") { 783 toolkit.lut(bitmap, table, restriction) 784 } 785 if (!validate) return true 786 787 val referenceOutArray = timer.measure("ReferenceLUT") { 788 referenceLut( 789 getBitmapBytes(bitmap), 790 bitmap.width, 791 bitmap.height, 792 table, 793 restriction 794 ) 795 } 796 797 val toolkitOutArray = getBitmapBytes(toolkitOutBitmap) 798 return validateSame("LutBitmap", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 799 println("LutBitmap $restriction") 800 logArray("LutBitmap red ", newRed, 256) 801 logArray("LutBitmap green", newGreen, 256) 802 logArray("LutBitmap blue ", newBlue, 256) 803 logArray("LutBitmap alpha", newAlpha, 256) 804 //logArray("LutBitmap in ", inputArray, 80) 805 logArray("LutBitmap reference out", referenceOutArray) 806 logArray("LutBitmap intrinsic out", intrinsicOutArray) 807 logArray("LutBitmap toolkit out", toolkitOutArray) 808 } 809 } 810 811 @ExperimentalUnsignedTypes 812 private fun testLut3d(timer: TimingTracker): Boolean { 813 val cubeSizesToTry = listOf( 814 Dimension(2, 2, 2), 815 Dimension(32, 32, 16), 816 Dimension(256, 256, 256) 817 ) 818 return cubeSizesToTry.all { cubeSize -> 819 val identityCube = identityCube(cubeSize) 820 val randomCube = randomCube(0x23424, cubeSize) 821 testOneBitmapLut3d(timer, testImage1, cubeSize, identityCube, 1, null) and 822 testOneBitmapLut3d(timer, testImage2, cubeSize, randomCube, 3, null) and 823 testOneBitmapLut3d(timer, testImage2, cubeSize, randomCube, 3, Range2d(6, 23, 2, 4)) and 824 commonLayoutsToTry.all { (sizeX, sizeY, restriction) -> 825 testOneRandomLut3d(timer, sizeX, sizeY, cubeSize, identityCube, 1, restriction) && 826 testOneRandomLut3d( 827 timer, 828 sizeX, 829 sizeY, 830 cubeSize, 831 randomCube, 832 3, 833 restriction 834 ) 835 } 836 } 837 } 838 839 @ExperimentalUnsignedTypes 840 private fun testOneRandomLut3d( 841 timer: TimingTracker, 842 sizeX: Int, 843 sizeY: Int, 844 cubeSize: Dimension, 845 cubeArray: ByteArray, 846 allowedIntError: Int, restriction: Range2d? 847 ): Boolean { 848 val inputArray = randomByteArray(0x50521f0, sizeX, sizeY, 4) 849 850 val intrinsicOutArray = timer.measure("IntrinsicLut3d") { 851 intrinsicLut3d( 852 renderscriptContext, inputArray, sizeX, sizeY, cubeArray, cubeSize, restriction 853 ) 854 } 855 val toolkitOutArray = timer.measure("ToolkitLut3d") { 856 val toolkitCube = Rgba3dArray(cubeArray, cubeSize.sizeX, cubeSize.sizeY, cubeSize.sizeZ) 857 toolkit.lut3d(inputArray, sizeX, sizeY, toolkitCube, restriction) 858 } 859 if (!validate) return true 860 861 val referenceOutArray = timer.measure("ReferenceLut3d") { 862 val cube = Rgba3dArray(cubeArray, cubeSize.sizeX, cubeSize.sizeY, cubeSize.sizeZ) 863 referenceLut3d(inputArray, sizeX, sizeY, cube, restriction) 864 } 865 866 return validateSame( 867 "lut3d", 868 intrinsicOutArray, 869 referenceOutArray, 870 toolkitOutArray, 871 false, 872 allowedIntError 873 ) { 874 println("lut3d ($sizeX, $sizeY) $restriction") 875 logArray("lut3d cube", cubeArray, 256) 876 logArray("lut3d in ", inputArray, 64) 877 logArray("lut3d reference out", referenceOutArray, 64) 878 logArray("lut3d intrinsic out", intrinsicOutArray, 64) 879 logArray("lut3d toolkit out", toolkitOutArray) 880 } 881 } 882 883 @ExperimentalUnsignedTypes 884 private fun testOneBitmapLut3d( 885 timer: TimingTracker, 886 bitmap: Bitmap, 887 cubeSize: Dimension, 888 cubeArray: ByteArray, 889 allowedIntError: Int, restriction: Range2d? 890 ): Boolean { 891 val intrinsicOutArray = timer.measure("IntrinsicLut3d") { 892 intrinsicLut3d(renderscriptContext, bitmap, cubeArray, cubeSize, restriction) 893 } 894 val toolkitOutBitmap = timer.measure("ToolkitLut3d") { 895 val toolkitCube = Rgba3dArray(cubeArray, cubeSize.sizeX, cubeSize.sizeY, cubeSize.sizeZ) 896 toolkit.lut3d(bitmap, toolkitCube, restriction) 897 } 898 if (!validate) return true 899 900 val referenceOutArray = timer.measure("ReferenceLut3d") { 901 val cube = Rgba3dArray(cubeArray, cubeSize.sizeX, cubeSize.sizeY, cubeSize.sizeZ) 902 referenceLut3d(getBitmapBytes(bitmap), bitmap.width, bitmap.height, cube, restriction) 903 } 904 905 val toolkitOutArray = getBitmapBytes(toolkitOutBitmap) 906 return validateSame( 907 "Lut3dBitmap", 908 intrinsicOutArray, 909 referenceOutArray, 910 toolkitOutArray, 911 false, 912 allowedIntError 913 ) { 914 println("Lut3dBitmap $restriction") 915 logArray("Lut3dBitmap cube", cubeArray, 256) 916 //logArray("Lut3dBitmap in ", inputArray, 64) 917 logArray("Lut3dBitmap reference out", referenceOutArray, 64) 918 logArray("Lut3dBitmap intrinsic out", intrinsicOutArray, 64) 919 logArray("Lut3dBitmap toolkit out", toolkitOutArray) 920 } 921 } 922 923 @ExperimentalUnsignedTypes 924 private fun testResize(timer: TimingTracker): Boolean { 925 val factorsToTry = listOf( 926 Pair(1f, 1f), 927 Pair(0.5f, 1f), 928 Pair(2f, 2f), 929 Pair(0.5f, 2f), 930 Pair(2f, 0.5f), 931 // The RenderScript Intrinsic tests used the above factors. It's tempting to use 932 // less regular ones like Pair(6.37f, 0.17f) however this creates small offset 933 // errors between the result provided by the C++ code and the SIMD code. This is 934 // due to the SIMD code using a scaled integer to increment going from one pixel to the 935 // next, while the C++ code uses float operations. 936 ) 937 val layoutsToTry = listOf( 938 TestLayout(37, 47, null), 939 TestLayout(60, 10, null), 940 TestLayout(6, 4, Range2d(1, 3, 0, 2)), 941 TestLayout(10, 14, Range2d(2, 3, 3, 7)), 942 ) 943 944 return factorsToTry.all { (scaleX, scaleY) -> 945 // Do one resize that's greater than 4x, as that's used in the code but don't do it 946 // for everything, as some images will get very large 947 testOneRandomResize(timer, 1, 25, 30, 6f, 6f, null) and 948 testOneBitmapResize(timer, testImage1, scaleX, scaleY, null) and 949 testOneBitmapResize(timer, testImage1, scaleX, scaleY, Range2d(6, 23, 2, 4)) and 950 layoutsToTry.all { (sizeX, sizeY, restriction) -> 951 (1..4).all { vectorSize -> 952 testOneRandomResize( 953 timer, 954 vectorSize, 955 sizeX, 956 sizeY, 957 scaleX, 958 scaleY, 959 restriction 960 ) 961 } 962 } 963 } 964 } 965 966 @ExperimentalUnsignedTypes 967 private fun testOneRandomResize( 968 timer: TimingTracker, 969 vectorSize: Int, 970 inSizeX: Int, 971 inSizeY: Int, 972 scaleX: Float, 973 scaleY: Float, 974 restriction: Range2d? 975 ): Boolean { 976 val inputArray = randomByteArray(0x50521f0, inSizeX, inSizeY, paddedSize(vectorSize)) 977 val outSizeX = (inSizeX * scaleX).toInt() 978 val outSizeY = (inSizeY * scaleY).toInt() 979 980 val intrinsicOutArray = timer.measure("IntrinsicResize") { 981 intrinsicResize( 982 renderscriptContext, inputArray, vectorSize, inSizeX, inSizeY, outSizeX, outSizeY, 983 restriction 984 ) 985 } 986 val toolkitOutArray = timer.measure("ToolkitResize") { 987 toolkit.resize( 988 inputArray, vectorSize, inSizeX, inSizeY, outSizeX, outSizeY, restriction 989 ) 990 } 991 if (!validate) return true 992 993 val referenceOutArray = timer.measure("ReferenceResize") { 994 referenceResize( 995 inputArray, vectorSize, inSizeX, inSizeY, outSizeX, outSizeY, restriction 996 ) 997 } 998 999 return validateSame("resize", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 1000 println("resize $vectorSize ($inSizeX, $inSizeY) by ($scaleX, $scaleY) to ($outSizeX, $outSizeY), $restriction") 1001 logArray("resize in ", inputArray) 1002 logArray("resize reference out", referenceOutArray) 1003 logArray("resize intrinsic out", intrinsicOutArray) 1004 logArray("resize toolkit out", toolkitOutArray) 1005 } 1006 } 1007 1008 @ExperimentalUnsignedTypes 1009 private fun testOneBitmapResize( 1010 timer: TimingTracker, 1011 bitmap: Bitmap, 1012 scaleX: Float, 1013 scaleY: Float, 1014 restriction: Range2d? 1015 ): Boolean { 1016 // println("Doing resize $inSizeX x $inSizeY x $vectorSize, $scaleX x $scaleY, $restriction") 1017 val outSizeX = (bitmap.width * scaleX).toInt() 1018 val outSizeY = (bitmap.height * scaleY).toInt() 1019 1020 val intrinsicOutArray = timer.measure("IntrinsicResize") { 1021 intrinsicResize(renderscriptContext, bitmap, outSizeX, outSizeY, restriction) 1022 } 1023 val toolkitOutBitmap = timer.measure("ToolkitResize") { 1024 toolkit.resize(bitmap, outSizeX, outSizeY, restriction) 1025 } 1026 if (!validate) return true 1027 1028 val referenceOutArray = timer.measure("ReferenceResize") { 1029 referenceResize( 1030 getBitmapBytes(bitmap), 1031 vectorSizeOfBitmap(bitmap), 1032 bitmap.width, 1033 bitmap.height, 1034 outSizeX, 1035 outSizeY, 1036 restriction 1037 ) 1038 } 1039 1040 val toolkitOutArray = getBitmapBytes(toolkitOutBitmap) 1041 return validateSame("ResizeBitmap", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 1042 println("ResizeBitmap by ($scaleX, $scaleY) to ($outSizeX, $outSizeY), $restriction") 1043 //logArray("ResizeBitmap in ", inputArray, 100) 1044 logArray("ResizeBitmap reference out", referenceOutArray) 1045 logArray("ResizeBitmap intrinsic out", intrinsicOutArray) 1046 logArray("ResizeBitmap toolkit out", toolkitOutArray) 1047 } 1048 } 1049 1050 @ExperimentalUnsignedTypes 1051 private fun testYuvToRgb(timer: TimingTracker): Boolean { 1052 val layoutsToTry = listOf( 1053 // Don't try sizeX with odd values. That's not allowed by definition of some 1054 // of the video formats. 1055 TestLayout(10, 14, null), 1056 TestLayout(64, 40, null), 1057 TestLayout(96, 94, null), 1058 ) 1059 return layoutsToTry.all { (sizeX, sizeY, _) -> 1060 YuvFormat.values().all { format -> 1061 testOneRandomYuvToRgb(timer, sizeX, sizeY, format) and 1062 testOneRandomYuvToRgbBitmap(timer, sizeX, sizeY, format) 1063 } 1064 } 1065 } 1066 1067 @ExperimentalUnsignedTypes 1068 private fun testOneRandomYuvToRgb( 1069 timer: TimingTracker, 1070 sizeX: Int, 1071 sizeY: Int, 1072 format: YuvFormat 1073 ): Boolean { 1074 // The RenderScript Intrinsic does not handle this combination correctly. 1075 if (format == YuvFormat.YV12 && sizeX % 32 != 0) { 1076 return true 1077 } 1078 val inputArray = randomYuvArray(0x50521f0, sizeX, sizeY, format) 1079 1080 val intrinsicOutArray = timer.measure("IntrinsicYuvToRgb") { 1081 intrinsicYuvToRgb(renderscriptContext, inputArray, sizeX, sizeY, format) 1082 } 1083 val toolkitOutArray = timer.measure("ToolkitYuvToRgb") { 1084 toolkit.yuvToRgb(inputArray, sizeX, sizeY, format) 1085 } 1086 if (!validate) return true 1087 1088 val referenceOutArray = timer.measure("ReferenceYuvToRgb") { 1089 referenceYuvToRgb(inputArray, sizeX, sizeY, format) 1090 } 1091 1092 return validateSame("yuvToRgb", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 1093 println("yuvToRgb ($sizeX, $sizeY) $format") 1094 logArray("yuvToRgb in ", inputArray) 1095 logArray("yuvToRgb reference out", referenceOutArray) 1096 logArray("yuvToRgb intrinsic out", intrinsicOutArray) 1097 logArray("yuvToRgb toolkit out", toolkitOutArray) 1098 } 1099 } 1100 1101 @ExperimentalUnsignedTypes 1102 private fun testOneRandomYuvToRgbBitmap( 1103 timer: TimingTracker, 1104 sizeX: Int, 1105 sizeY: Int, 1106 format: YuvFormat 1107 ): Boolean { 1108 // The RenderScript Intrinsic does not handle this combination correctly. 1109 if (format == YuvFormat.YV12 && sizeX % 32 != 0) { 1110 return true 1111 } 1112 val inputArray = randomYuvArray(0x50521f0, sizeX, sizeY, format) 1113 1114 val intrinsicOutArray = timer.measure("IntrinsicYuvToRgb") { 1115 intrinsicYuvToRgb(renderscriptContext, inputArray, sizeX, sizeY, format) 1116 } 1117 val toolkitOutBitmap = timer.measure("ToolkitYuvToRgb") { 1118 toolkit.yuvToRgbBitmap(inputArray, sizeX, sizeY, format) 1119 } 1120 if (!validate) return true 1121 1122 val referenceOutArray = timer.measure("ReferenceYuvToRgb") { 1123 referenceYuvToRgb(inputArray, sizeX, sizeY, format) 1124 } 1125 1126 val toolkitOutArray = getBitmapBytes(toolkitOutBitmap) 1127 return validateSame("yuvToRgb", intrinsicOutArray, referenceOutArray, toolkitOutArray) { 1128 println("yuvToRgb ($sizeX, $sizeY) $format") 1129 logArray("yuvToRgb in ", inputArray) 1130 logArray("yuvToRgb reference out", referenceOutArray) 1131 logArray("yuvToRgb intrinsic out", intrinsicOutArray) 1132 logArray("yuvToRgb toolkit out", toolkitOutArray) 1133 } 1134 } 1135 1136 /** 1137 * Verifies that the arrays returned by the Intrinsic, the reference code, and the Toolkit 1138 * are all within a margin of error. 1139 * 1140 * RenderScript Intrinsic test (rc/android/cts/rscpp/RSCppTest.java) used 3 for ints. 1141 * For floats, rc/android/cts/rscpp/verify.rscript uses 0.0001f. 1142 */ 1143 @ExperimentalUnsignedTypes 1144 private fun validateSame( 1145 task: String, 1146 intrinsic: ByteArray, 1147 reference: ByteArray, 1148 toolkit: ByteArray, 1149 skipFourth: Boolean = false, 1150 allowedIntDelta: Int = 3, 1151 errorLogging: () -> Unit 1152 ): Boolean { 1153 val success = validateAgainstReference( 1154 task, reference, "Intrinsic", intrinsic, skipFourth, allowedIntDelta 1155 ) and validateAgainstReference( 1156 task, reference, "Toolkit", toolkit, skipFourth, allowedIntDelta 1157 ) 1158 if (!success) { 1159 println("$task FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!") 1160 errorLogging() 1161 } 1162 return success 1163 } 1164 1165 private fun validateSame( 1166 task: String, 1167 intrinsic: IntArray, 1168 reference: IntArray, 1169 toolkit: IntArray, 1170 allowedIntDelta: Int = 3, 1171 errorLogging: () -> Unit 1172 ): Boolean { 1173 val success = validateAgainstReference( 1174 task, reference, "Intrinsic", intrinsic, allowedIntDelta 1175 ) and validateAgainstReference( 1176 task, reference, "Toolkit", toolkit, allowedIntDelta 1177 ) 1178 if (!success) { 1179 println("$task FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!FAIL!") 1180 errorLogging() 1181 } 1182 return success 1183 } 1184 1185 @ExperimentalUnsignedTypes 1186 private fun validateAgainstReference( 1187 task: String, 1188 in1: ByteArray, 1189 name2: String, 1190 in2: ByteArray, 1191 skipFourth: Boolean, 1192 allowedIntDelta: Int 1193 ): Boolean { 1194 if (in1.size != in2.size) { 1195 println("$task. Sizes don't match: Reference ${in1.size}, $name2 ${in2.size}") 1196 return false 1197 } 1198 var same = true 1199 val maxDetails = 80 1200 val diffs = CharArray(min(in1.size, maxDetails)) {'.'} 1201 for (i in in1.indices) { 1202 if (skipFourth && i % 4 == 3) { 1203 continue 1204 } 1205 val delta = abs(in1[i].toUByte().toInt() - in2[i].toUByte().toInt()) 1206 if (delta > allowedIntDelta) { 1207 if (same) { 1208 println( 1209 "$task. At $i, Reference is ${in1[i].toUByte()}, $name2 is ${in2[i].toUByte()}" 1210 ) 1211 } 1212 if (i < maxDetails) diffs[i] = 'X' 1213 same = false 1214 } 1215 } 1216 if (!same) { 1217 for (i in 0 until (min(in1.size, maxDetails) / 4)) print("%-3d|".format(i)) 1218 println() 1219 println(diffs) 1220 } 1221 return same 1222 } 1223 1224 private fun validateAgainstReference( 1225 task: String, 1226 in1: IntArray, 1227 name2: String, 1228 in2: IntArray, 1229 allowedIntDelta: Int 1230 ): Boolean { 1231 if (in1.size != in2.size) { 1232 println("$task. Sizes don't match: Reference ${in1.size}, $name2 ${in2.size}") 1233 return false 1234 } 1235 for (i in in1.indices) { 1236 val delta = abs(in1[i] - in2[i]) 1237 if (delta > allowedIntDelta) { 1238 println("$task. At $i, Reference is ${in1[i]}, $name2 is ${in2[i]}") 1239 return false 1240 } 1241 } 1242 return true 1243 } 1244 } 1245