1 /* 2 * Copyright (C) 2011-2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.renderscript.cts; 18 19 import android.graphics.Bitmap; 20 import android.renderscript.Allocation; 21 import android.renderscript.AllocationAdapter; 22 import android.renderscript.Allocation.MipmapControl; 23 import android.renderscript.Element; 24 import android.renderscript.RSIllegalArgumentException; 25 import android.renderscript.RSInvalidStateException; 26 import android.renderscript.Type; 27 import android.renderscript.Type.Builder; 28 29 import android.renderscript.ScriptIntrinsicColorMatrix; 30 import android.renderscript.ScriptIntrinsicConvolve3x3; 31 import android.renderscript.ScriptGroup; 32 import android.renderscript.Matrix4f; 33 import android.util.Log; 34 35 public class ScriptGroupTest extends RSBaseCompute { 36 37 private static final String TAG = "ScriptGroupTest"; 38 private static final int ARRAY_SIZE = 256; 39 static int bDimX = 48; 40 static int bDimY = 8; 41 42 public void testScriptGroupSingleKernel() { 43 ScriptGroup group; 44 45 Type connect = new Type.Builder(mRS, Element.U8_4(mRS)).setX(bDimX).setY(bDimY).create(); 46 47 ScriptIntrinsicColorMatrix mColorMatrix; 48 49 mColorMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); 50 51 Allocation a1_copy, a2_copy; 52 a1_copy = Allocation.createTyped(mRS, connect); 53 a2_copy = Allocation.createTyped(mRS, connect); 54 55 Matrix4f m = new Matrix4f(); 56 m.set(1, 0, 0.2f); 57 m.set(1, 1, 0.9f); 58 m.set(1, 2, 0.2f); 59 mColorMatrix.setColorMatrix(m); 60 61 ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); 62 b.addKernel(mColorMatrix.getKernelID()); 63 group = b.create(); 64 65 group.setInput(mColorMatrix.getKernelID(), a1_copy); 66 group.setOutput(mColorMatrix.getKernelID(), a2_copy); 67 68 group.execute(); 69 70 mColorMatrix.destroy(); 71 a1_copy.destroy(); 72 a2_copy.destroy(); 73 group.destroy(); 74 } 75 76 public void testScriptGroupDisconnectedKernel() { 77 ScriptGroup group = null; 78 79 Type connect = new Type.Builder(mRS, Element.U8_4(mRS)).setX(bDimX).setY(bDimY).create(); 80 81 ScriptIntrinsicColorMatrix mColorMatrix, mColorMatrix2; 82 83 mColorMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); 84 mColorMatrix2 = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); 85 86 Allocation a1_copy, a2_copy; 87 88 a1_copy = Allocation.createTyped(mRS, connect); 89 a2_copy = Allocation.createTyped(mRS, connect); 90 91 Matrix4f m = new Matrix4f(); 92 m.set(1, 0, 0.2f); 93 m.set(1, 1, 0.9f); 94 m.set(1, 2, 0.2f); 95 mColorMatrix.setColorMatrix(m); 96 mColorMatrix2.setColorMatrix(m); 97 98 ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); 99 b.addKernel(mColorMatrix.getKernelID()); 100 b.addKernel(mColorMatrix2.getKernelID()); 101 try { 102 group = b.create(); 103 fail("should throw RSInvalidStateException."); 104 } catch (RSInvalidStateException e) { 105 106 } 107 108 mColorMatrix.destroy(); 109 mColorMatrix2.destroy(); 110 a1_copy.destroy(); 111 a2_copy.destroy(); 112 if (group != null) { 113 group.destroy(); 114 } 115 } 116 117 118 public void testScriptGroupFieldConnection() { 119 ScriptGroup group; 120 121 Type connect = new Type.Builder(mRS, Element.U8_4(mRS)).setX(bDimX).setY(bDimY).create(); 122 123 ScriptIntrinsicConvolve3x3 mConvolve3x3; 124 ScriptIntrinsicColorMatrix mColorMatrix; 125 126 mConvolve3x3 = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS)); 127 mColorMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); 128 129 Allocation a1_copy, a2_copy; 130 a1_copy = Allocation.createTyped(mRS, connect); 131 a2_copy = Allocation.createTyped(mRS, connect); 132 133 float f[] = new float[9]; 134 f[0] = 0.f; f[1] = -1.f; f[2] = 0.f; 135 f[3] = -1.f; f[4] = 5.f; f[5] = -1.f; 136 f[6] = 0.f; f[7] = -1.f; f[8] = 0.f; 137 138 mConvolve3x3.setCoefficients(f); 139 140 Matrix4f m = new Matrix4f(); 141 m.set(1, 0, 0.2f); 142 m.set(1, 1, 0.9f); 143 m.set(1, 2, 0.2f); 144 mColorMatrix.setColorMatrix(m); 145 146 ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); 147 b.addKernel(mColorMatrix.getKernelID()); 148 b.addKernel(mConvolve3x3.getKernelID()); 149 b.addConnection(connect, mColorMatrix.getKernelID(), mConvolve3x3.getFieldID_Input()); 150 group = b.create(); 151 152 group.setInput(mColorMatrix.getKernelID(), a1_copy); 153 group.setOutput(mConvolve3x3.getKernelID(), a2_copy); 154 155 group.execute(); 156 157 mConvolve3x3.destroy(); 158 mColorMatrix.destroy(); 159 a1_copy.destroy(); 160 a2_copy.destroy(); 161 group.destroy(); 162 } 163 164 public void testScriptGroupDisconnectedDAG() { 165 ScriptGroup group = null; 166 167 Type connect = new Type.Builder(mRS, Element.U8_4(mRS)).setX(bDimX).setY(bDimY).create(); 168 169 ScriptIntrinsicConvolve3x3 mConvolve3x3, mConvolve3x32; 170 ScriptIntrinsicColorMatrix mColorMatrix, mColorMatrix2; 171 172 mConvolve3x3 = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS)); 173 mConvolve3x32 = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS)); 174 mColorMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); 175 mColorMatrix2 = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); 176 177 Allocation a1_copy, a2_copy; 178 a1_copy = Allocation.createTyped(mRS, connect); 179 a2_copy = Allocation.createTyped(mRS, connect); 180 181 float f[] = new float[9]; 182 f[0] = 0.f; f[1] = -1.f; f[2] = 0.f; 183 f[3] = -1.f; f[4] = 5.f; f[5] = -1.f; 184 f[6] = 0.f; f[7] = -1.f; f[8] = 0.f; 185 186 mConvolve3x3.setCoefficients(f); 187 mConvolve3x32.setCoefficients(f); 188 189 Matrix4f m = new Matrix4f(); 190 m.set(1, 0, 0.2f); 191 m.set(1, 1, 0.9f); 192 m.set(1, 2, 0.2f); 193 mColorMatrix.setColorMatrix(m); 194 mColorMatrix2.setColorMatrix(m); 195 196 ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); 197 b.addKernel(mColorMatrix.getKernelID()); 198 b.addKernel(mColorMatrix2.getKernelID()); 199 b.addKernel(mConvolve3x3.getKernelID()); 200 b.addKernel(mConvolve3x32.getKernelID()); 201 b.addConnection(connect, mColorMatrix.getKernelID(), mConvolve3x3.getFieldID_Input()); 202 b.addConnection(connect, mColorMatrix2.getKernelID(), mConvolve3x32.getFieldID_Input()); 203 try { 204 group = b.create(); 205 fail("RSInvalidStateException expected"); 206 } catch (RSInvalidStateException e) { 207 208 } 209 210 mConvolve3x3.destroy(); 211 mConvolve3x32.destroy(); 212 mColorMatrix.destroy(); 213 mColorMatrix2.destroy(); 214 a1_copy.destroy(); 215 a2_copy.destroy(); 216 if (group != null) { 217 group.destroy(); 218 } 219 } 220 221 public void testScriptGroupTorture() { 222 ScriptGroup group; 223 224 int[] result = new int[1]; 225 226 bDimX = 1; 227 228 Type connect = new Type.Builder(mRS, Element.I32(mRS)).setX(bDimX).create(); 229 Type compareType = new Type.Builder(mRS, Element.I32(mRS)).create(); 230 231 ScriptC_scriptgroup node1, node2, node3, node4, node5, compare; 232 node1 = new ScriptC_scriptgroup(mRS); 233 node2 = new ScriptC_scriptgroup(mRS); 234 node3 = new ScriptC_scriptgroup(mRS); 235 node4 = new ScriptC_scriptgroup(mRS); 236 node5 = new ScriptC_scriptgroup(mRS); 237 238 compare = new ScriptC_scriptgroup(mRS); 239 240 Allocation in1, in2, out, resultAlloc; 241 in1 = Allocation.createTyped(mRS, connect); 242 in2 = Allocation.createTyped(mRS, connect); 243 244 out = Allocation.createTyped(mRS, connect); 245 resultAlloc = Allocation.createTyped(mRS, compareType); 246 247 node1.set_memset_toValue(1); 248 node1.forEach_memset(in1); 249 node1.set_memset_toValue(2); 250 node1.forEach_memset(in2); 251 252 node1.set_arith_operation(2); 253 node2.set_arith_operation(1); 254 node3.set_arith_operation(0); 255 node4.set_arith_operation(0); 256 node5.set_arith_operation(1); 257 258 node3.set_arith_use_rs_allocation(1); 259 node4.set_arith_use_rs_allocation(1); 260 261 node1.set_arith_value(5); 262 node2.set_arith_value(3); 263 node5.set_arith_value(7); 264 265 ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); 266 b.addKernel(node1.getKernelID_arith()); 267 b.addKernel(node2.getKernelID_arith()); 268 b.addKernel(node3.getKernelID_arith()); 269 b.addKernel(node4.getKernelID_arith()); 270 b.addKernel(node5.getKernelID_arith()); 271 272 b.addConnection(connect, node1.getKernelID_arith(), node2.getKernelID_arith()); 273 b.addConnection(connect, node1.getKernelID_arith(), node3.getFieldID_arith_rs_input()); 274 b.addConnection(connect, node2.getKernelID_arith(), node4.getFieldID_arith_rs_input()); 275 b.addConnection(connect, node3.getKernelID_arith(), node4.getKernelID_arith()); 276 b.addConnection(connect, node4.getKernelID_arith(), node5.getKernelID_arith()); 277 278 group = b.create(); 279 group.setInput(node1.getKernelID_arith(), in1); 280 group.setInput(node3.getKernelID_arith(), in2); 281 282 group.setOutput(node5.getKernelID_arith(), out); 283 284 group.execute(); 285 286 mRS.finish(); 287 288 compare.set_compare_value(2); 289 compare.forEach_compare(out); 290 compare.forEach_getCompareResult(resultAlloc); 291 resultAlloc.copyTo(result); 292 293 node1.destroy(); 294 node2.destroy(); 295 node3.destroy(); 296 node4.destroy(); 297 node5.destroy(); 298 in1.destroy(); 299 in2.destroy(); 300 out.destroy(); 301 resultAlloc.destroy(); 302 303 assertTrue(result[0] == 2); 304 } 305 306 /** 307 * Tests a case where a shared global variable is updated by the first kernel in a group, 308 * but then read by a subsequent kernel. 309 * 310 * The test ensures that we don't accidentally apply any fusion optimizations to the kernel 311 * pair, since there is a potential dependency that crosses the kernel cell boundary. 312 */ 313 public void testScriptGroupSharedGlobal() { 314 Type i32 = new Type.Builder(mRS, Element.I32(mRS)).setX(1).create(); 315 Type u32 = new Type.Builder(mRS, Element.U32(mRS)).setX(2).create(); 316 317 Allocation aFailed = Allocation.createTyped(mRS, i32); 318 Allocation aSharedInt = Allocation.createTyped(mRS, i32); 319 320 ScriptC_group1 mG1 = new ScriptC_group1(mRS); 321 ScriptC_group2 mG2 = new ScriptC_group2(mRS); 322 323 mG1.set_aSharedInt(aSharedInt); 324 mG2.set_aSharedInt(aSharedInt); 325 mG2.set_aFailed(aFailed); 326 327 int [] Failed = new int [1]; 328 Failed[0] = 0; 329 aFailed.copyFrom(Failed); 330 331 ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); 332 333 // Writes to aSharedInt[x] in the kernel. 334 b.addKernel(mG1.getKernelID_setSharedInt()); 335 // Reads aSharedInt[1] to verify it is -5. 336 b.addKernel(mG2.getKernelID_getSharedInt()); 337 // If we fuse mG1/mG2, we won't see the update to the aSharedInt[1] during mG2 for x == 0. 338 // The update is only visible if we correctly identify the dependency and execute all of 339 // mG1 before starting on mG2. 340 b.addConnection(u32, mG1.getKernelID_setSharedInt(), mG2.getKernelID_getSharedInt()); 341 ScriptGroup group = b.create(); 342 group.execute(); 343 344 mG2.invoke_verify(); 345 aFailed.copyTo(Failed); 346 if (Failed[0] != 0) { 347 FoundError = true; 348 } 349 350 aFailed.destroy(); 351 aSharedInt.destroy(); 352 mG1.destroy(); 353 mG2.destroy(); 354 group.destroy(); 355 356 checkForErrors(); 357 } 358 359 /** 360 * Tests that kernel-to-kernel dependency via input/output is handled correctly 361 */ 362 public void testBuilder2PointWiseKernelToKernelDependency() { 363 ScriptC_increment s_inc = new ScriptC_increment(mRS); 364 ScriptC_double s_double = new ScriptC_double(mRS); 365 mRS.setMessageHandler(mRsMessage); 366 367 int[] array = new int[ARRAY_SIZE * 4]; 368 369 for (int i = 0; i < ARRAY_SIZE * 4; i++) { 370 array[i] = i; 371 } 372 373 Allocation input = Allocation.createSized(mRS, Element.I32_4(mRS), ARRAY_SIZE); 374 input.copyFrom(array); 375 376 ScriptGroup.Builder2 builder = new ScriptGroup.Builder2(mRS); 377 378 ScriptGroup.Input unbound = builder.addInput(); 379 380 Type connectType = Type.createX(mRS, Element.I32_4(mRS), ARRAY_SIZE); 381 382 ScriptGroup.Closure c0 = 383 builder.addKernel(s_inc.getKernelID_increment(), 384 connectType, 385 unbound); 386 387 ScriptGroup.Closure c1 = 388 builder.addKernel(s_double.getKernelID_doubleKernel(), 389 connectType, 390 c0.getReturn()); 391 392 ScriptGroup group = builder.create("IncAndDbl", c1.getReturn()); 393 394 int[] a = new int[ARRAY_SIZE * 4]; 395 ((Allocation)group.execute(input)[0]).copyTo(a); 396 397 mRS.finish(); 398 399 input.destroy(); 400 group.destroy(); 401 402 boolean failed = false; 403 for (int i = 0; i < ARRAY_SIZE * 4; i++) { 404 if (a[i] != (i+1) * 2) { 405 Log.e(TAG, "a["+i+"]="+a[i]+", should be "+ ((i+1) * 2)); 406 failed = true; 407 } 408 } 409 410 assertTrue(!failed); 411 } 412 413 /** 414 * Tests that kernel-to-kernel dependency via global allocations is handled correctly 415 */ 416 public void testBuilder2GatherScatterAcrossKernelsViaGlobals() { 417 ScriptC_reduction s = new ScriptC_reduction(mRS); 418 419 int[] array = new int[ARRAY_SIZE * 4]; 420 421 for (int i = 0; i < ARRAY_SIZE; i++) { 422 array[i*4] = i * 7; 423 array[i*4 + 1] = i * 7; 424 array[i*4 + 2] = i * 7; 425 array[i*4 + 3] = i * 7; 426 } 427 428 Allocation input = Allocation.createSized(mRS, Element.I32_4(mRS), ARRAY_SIZE); 429 input.copyFrom(array); 430 431 ScriptGroup.Builder2 builder = new ScriptGroup.Builder2(mRS); 432 433 ScriptGroup.Input unbound = builder.addInput(); 434 435 ScriptGroup.Closure c = null; 436 ScriptGroup.Binding b2 = new ScriptGroup.Binding(s.getFieldID_a(), unbound); 437 for (int stride = ARRAY_SIZE / 2; stride >= 1; stride >>= 1) { 438 ScriptGroup.Binding b1 = new ScriptGroup.Binding(s.getFieldID_reduction_stride(), 439 stride); 440 c = builder.addKernel(s.getKernelID_add(), 441 Type.createX(mRS, Element.I32_4(mRS), stride), 442 b1, b2); 443 b2 = new ScriptGroup.Binding(s.getFieldID_a(), c.getReturn()); 444 } 445 446 if (c == null) { 447 return; 448 } 449 450 ScriptGroup group = builder.create("Summation", c.getReturn()); 451 452 int[] a = new int[4]; 453 ((Allocation)group.execute(input)[0]).copyTo(a); 454 455 mRS.finish(); 456 457 input.destroy(); 458 group.destroy(); 459 460 boolean failed = false; 461 for (int i = 0; i < 4; i++) { 462 if (failed == false && a[i] != ARRAY_SIZE * (ARRAY_SIZE - 1) * 7 / 2) { 463 Log.e(TAG, 464 "a["+i+"]="+a[i]+", should be "+ (ARRAY_SIZE * (ARRAY_SIZE - 1) * 7 / 2)); 465 failed = true; 466 } 467 } 468 469 assertTrue(!failed); 470 } 471 472 /** 473 * Tests that the kernel output to a global can be used as a future 474 */ 475 public void testBuilder2KernelOutputToGlobal() { 476 ScriptC_reduction s = new ScriptC_reduction(mRS); 477 478 int[] array = new int[ARRAY_SIZE * 4]; 479 480 for (int i = 0; i < ARRAY_SIZE; i++) { 481 array[i*4] = i; 482 array[i*4 + 1] = i; 483 array[i*4 + 2] = i; 484 array[i*4 + 3] = i; 485 } 486 487 Allocation input = Allocation.createSized(mRS, Element.I32_4(mRS), ARRAY_SIZE); 488 input.copyFrom(array); 489 Allocation input1 = Allocation.createSized(mRS, Element.I32_4(mRS), ARRAY_SIZE); 490 491 ScriptGroup.Builder2 builder = new ScriptGroup.Builder2(mRS); 492 493 ScriptGroup.Input unbound = builder.addInput(); 494 495 ScriptGroup.Closure c = null; 496 ScriptGroup.Binding b2 = new ScriptGroup.Binding(s.getFieldID_a(), unbound); 497 for (int stride = ARRAY_SIZE / 2; stride >= 1; stride >>= 1) { 498 ScriptGroup.Binding b1 = new ScriptGroup.Binding(s.getFieldID_reduction_stride(), 499 stride); 500 c = builder.addKernel(s.getKernelID_add2(), 501 Type.createX(mRS, Element.I32_4(mRS), stride), 502 b1, b2); 503 b2 = new ScriptGroup.Binding(s.getFieldID_a(), 504 c.getGlobal(s.getFieldID_a())); 505 } 506 507 if (c == null) { 508 return; 509 } 510 511 ScriptGroup group = builder.create("SummationGlobal", c.getGlobal(s.getFieldID_a())); 512 513 int[] a = new int[4 * ARRAY_SIZE]; 514 ((Allocation)group.execute(input, input1)[0]).copyTo(a); 515 516 mRS.finish(); 517 518 input.destroy(); 519 input1.destroy(); 520 group.destroy(); 521 522 boolean failed = false; 523 for (int i = 0; i < 4; i++) { 524 if (failed == false && a[i] != ARRAY_SIZE * (ARRAY_SIZE - 1) / 2) { 525 Log.e(TAG, 526 "a["+i+"]="+a[i]+", should be "+ (ARRAY_SIZE * (ARRAY_SIZE - 1) / 2)); 527 failed = true; 528 } 529 } 530 531 assertTrue(!failed); 532 } 533 534 /** 535 * Tests that invoke-to-kernel dependency is handled correctly 536 */ 537 public void testBuilder2InvokeToKernelDependency() { 538 ScriptC_matrix s = new ScriptC_matrix(mRS); 539 540 float[] array = new float[ARRAY_SIZE * 4]; 541 542 for (int i = 0; i < ARRAY_SIZE; i++) { 543 array[i * 4] = i * 4 * 7; 544 array[i * 4 + 1] = (i * 4 + 1) * 7; 545 array[i * 4 + 2] = (i * 4 + 2) * 7; 546 array[i * 4 + 3] = (i * 4 + 3) * 7; 547 } 548 549 Allocation input = Allocation.createSized(mRS, Element.F32_4(mRS), ARRAY_SIZE); 550 input.copyFrom(array); 551 552 ScriptGroup.Builder2 builder = new ScriptGroup.Builder2(mRS); 553 554 ScriptGroup.Input unbound = builder.addInput(); 555 556 Matrix4f mat = new Matrix4f(); 557 558 mat.set(0, 0, 0.0f); 559 mat.set(0, 1, 0.0f); 560 mat.set(0, 2, 0.0f); 561 mat.set(0, 3, 1.0f); 562 563 mat.set(1, 0, 1.0f); 564 mat.set(1, 1, 0.0f); 565 mat.set(1, 2, 0.0f); 566 mat.set(1, 3, 0.0f); 567 568 mat.set(2, 0, 0.0f); 569 mat.set(2, 1, 1.0f); 570 mat.set(2, 2, 0.0f); 571 mat.set(2, 3, 0.0f); 572 573 mat.set(3, 0, 0.0f); 574 mat.set(3, 1, 0.0f); 575 mat.set(3, 2, 1.0f); 576 mat.set(3, 3, 0.0f); 577 578 ScriptGroup.Closure c1 = 579 builder.addInvoke(s.getInvokeID_setMatrix(), mat); 580 581 ScriptGroup.Closure c2 = 582 builder.addKernel(s.getKernelID_multiply(), 583 Type.createX(mRS, Element.F32_4(mRS), ARRAY_SIZE), 584 unbound); 585 586 ScriptGroup group = builder.create("Multiply", c2.getReturn()); 587 588 float[] a = new float[ARRAY_SIZE * 4]; 589 ((Allocation)group.execute(input)[0]).copyTo(a); 590 591 mRS.finish(); 592 593 input.destroy(); 594 group.destroy(); 595 596 boolean failed = false; 597 for (int i = 0; i < ARRAY_SIZE; i++) { 598 for (int j = 0; j < 4; j++) { 599 float expected = (i*4+((j+1)%4))*7; 600 if (failed == false && a[i * 4 + j] != expected) { 601 Log.e(TAG, "a["+i+"]="+a[i]+", should be "+ expected); 602 failed = true; 603 } 604 } 605 } 606 607 assertTrue(!failed); 608 } 609 } 610