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