1 /* 2 * Copyright (C) 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 com.android.rs.sgtest; 18 19 import android.renderscript.Allocation; 20 import android.renderscript.Element; 21 import android.renderscript.RenderScript; 22 import android.renderscript.Sampler; 23 import android.renderscript.Script; 24 import android.renderscript.Type; 25 import android.renderscript.Matrix3f; 26 import android.renderscript.Matrix4f; 27 import android.renderscript.ScriptGroup; 28 import android.util.Log; 29 30 import java.lang.reflect.Constructor; 31 import java.lang.Math; 32 import java.util.HashMap; 33 34 public class Filters extends TestBase { 35 36 interface FilterInterface { 37 public void init(); 38 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b); 39 public Script.KernelID getKernelID(); 40 public ScriptGroup.Closure asyncLaunch(ScriptGroup.Builder2 builder, 41 Object in, Type outputType); 42 public void forEach(Allocation in, Allocation out); 43 } 44 45 abstract class FilterBase implements FilterInterface { 46 public ScriptGroup.Closure asyncLaunch(ScriptGroup.Builder2 builder, 47 Object in, Type outputType) { 48 return builder.addKernel(getKernelID(), outputType, in); 49 } 50 } 51 52 /* 53 54 Template for a subclass that implements Filter. 55 56 class Filter implements Filter { 57 Filter(RenderScript RS) { s = new ScriptC_(RS); } 58 59 void init() {} 60 61 Script.KernelID getKernelID() { return s.getKernelID_(); } 62 63 void forEach(Allocation in, Allocation out) { s.forEach_(in, out); } 64 65 private ScriptC_ s; 66 } 67 */ 68 69 class ColorMatrixFilter extends FilterBase { 70 public ColorMatrixFilter(RenderScript RS) { s_mat = new ScriptC_colormatrix_f(RS); } 71 72 public void init() { } 73 74 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b) { /* TODO */ return null; } 75 76 public Script.KernelID getKernelID() { return s_mat.getKernelID_colormatrix(); } 77 78 public void forEach(Allocation in, Allocation out) { s_mat.forEach_colormatrix(in, out); } 79 80 private ScriptC_colormatrix_f s_mat; 81 } 82 83 class ContrastFilter extends FilterBase { 84 public ContrastFilter(RenderScript RS) { s = new ScriptC_contrast_f(RS); } 85 86 public void init() {} 87 88 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b) { return null; } 89 90 public Script.KernelID getKernelID() { return s.getKernelID_contrast(); } 91 92 public void forEach(Allocation in, Allocation out) { s.forEach_contrast(in, out); } 93 94 private ScriptC_contrast_f s; 95 } 96 97 class ExposureFilter extends FilterBase { 98 public ExposureFilter(RenderScript RS) { s = new ScriptC_exposure_f(RS); } 99 100 public void init() {} 101 102 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b) { return null; } 103 104 public Script.KernelID getKernelID() { return s.getKernelID_exposure(); } 105 106 public void forEach(Allocation in, Allocation out) { s.forEach_exposure(in, out); } 107 108 private ScriptC_exposure_f s; 109 } 110 111 class FisheyeFilter extends FilterBase { 112 public FisheyeFilter(RenderScript RS) { 113 mRS = RS; 114 s = new ScriptC_fisheye_approx_relaxed_f(RS); 115 } 116 117 public void init() { 118 } 119 120 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b) { 121 return b.addInvoke(s.getInvokeID_init_filter(), 122 dimX, dimY, 0.5f, 0.5f, 0.5f, Sampler.CLAMP_LINEAR(mRS)); 123 } 124 125 public Script.KernelID getKernelID() { return s.getKernelID_fisheye(); } 126 127 public ScriptGroup.Closure asyncLaunch(ScriptGroup.Builder2 builder, 128 Object in, Type outputType) { 129 return builder.addKernel(getKernelID(), outputType, 130 new ScriptGroup.Binding(s.getFieldID_in_alloc(), in)); 131 } 132 133 public void forEach(Allocation in, Allocation out) { 134 s.set_in_alloc(in); 135 s.forEach_fisheye(out); 136 } 137 138 private RenderScript mRS; 139 private ScriptC_fisheye_approx_relaxed_f s; 140 private final int dimX=1067, dimY=1600; 141 } 142 143 class GreyFilter extends FilterBase { 144 public GreyFilter(RenderScript RS) { s = new ScriptC_greyscale_f(RS); } 145 146 public void init() {} 147 148 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b) { return null; } 149 150 public Script.KernelID getKernelID() { return s.getKernelID_greyscale(); } 151 152 public void forEach(Allocation in, Allocation out) { s.forEach_greyscale(in, out); } 153 154 private ScriptC_greyscale_f s; 155 } 156 157 class LevelsFilter extends FilterBase { 158 public LevelsFilter(RenderScript RS) { s = new ScriptC_levels_relaxed_f(RS); } 159 private final float mSaturation = 1.0f; 160 private final float mInBlack = 0.0f; // 0-255 161 private final float mOutBlack = 0.0f; // 0-255 162 private final float mInWhite = 255.0f; // 0-255 163 private final float mOutWhite = 255.0f; // 0-255 164 private final float mInWMinInB = mInWhite - mInBlack; 165 private final float mOutWMinOutB = mOutWhite - mOutBlack; 166 private final float mOverInWMinInB = 1.f / mInWMinInB; 167 private Matrix3f mSatMatrix; 168 169 private void setLevels() { 170 s.set_inBlack(mInBlack); 171 s.set_outBlack(mOutBlack); 172 s.set_inWMinInB(mInWMinInB); 173 s.set_outWMinOutB(mOutWMinOutB); 174 s.set_overInWMinInB(mOverInWMinInB); 175 } 176 177 private void setSaturation() { 178 Matrix3f satMatrix = new Matrix3f(); 179 float rWeight = 0.299f; 180 float gWeight = 0.587f; 181 float bWeight = 0.114f; 182 float oneMinusS = 1.0f - mSaturation; 183 184 satMatrix.set(0, 0, oneMinusS * rWeight + mSaturation); 185 satMatrix.set(0, 1, oneMinusS * rWeight); 186 satMatrix.set(0, 2, oneMinusS * rWeight); 187 satMatrix.set(1, 0, oneMinusS * gWeight); 188 satMatrix.set(1, 1, oneMinusS * gWeight + mSaturation); 189 satMatrix.set(1, 2, oneMinusS * gWeight); 190 satMatrix.set(2, 0, oneMinusS * bWeight); 191 satMatrix.set(2, 1, oneMinusS * bWeight); 192 satMatrix.set(2, 2, oneMinusS * bWeight + mSaturation); 193 s.set_colorMat(satMatrix); 194 195 mSatMatrix = satMatrix; 196 } 197 198 public void init() { 199 setSaturation(); 200 setLevels(); 201 } 202 203 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b) { 204 return b.addInvoke(s.getInvokeID_initialize(), 205 mInBlack, mOutBlack, mInWMinInB, mOutWMinOutB, 206 mOverInWMinInB, mSatMatrix); 207 } 208 209 public Script.KernelID getKernelID() { return s.getKernelID_levels_v4(); } 210 211 public void forEach(Allocation in, Allocation out) { s.forEach_levels_v4(in, out); } 212 213 private ScriptC_levels_relaxed_f s; 214 } 215 216 class ShadowsFilter extends FilterBase { 217 public ShadowsFilter(RenderScript RS) { s = new ScriptC_shadows_f(RS); } 218 219 public void init() { s.invoke_prepareShadows(50.f); } 220 221 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b) { 222 cInit = b.addInvoke(s.getInvokeID_prepareShadows(), 50.f); 223 return cInit; 224 } 225 226 public Script.KernelID getKernelID() { return s.getKernelID_shadowsKernel(); } 227 228 public void forEach(Allocation in, Allocation out) { s.forEach_shadowsKernel(in, out); } 229 230 private ScriptC_shadows_f s; 231 private ScriptGroup.Closure cInit; 232 } 233 234 class VibranceFilter extends FilterBase { 235 public VibranceFilter(RenderScript RS) { s = new ScriptC_vibrance_f(RS); } 236 237 public void init() {} 238 239 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b) { return null; } 240 241 public Script.KernelID getKernelID() { return s.getKernelID_vibranceKernel(); } 242 243 public void forEach(Allocation in, Allocation out) { s.forEach_vibranceKernel(in, out); } 244 245 private ScriptC_vibrance_f s; 246 } 247 248 class VignetteFilter extends FilterBase { 249 public VignetteFilter(RenderScript RS) { s = new ScriptC_vignette_approx_relaxed_f(RS); } 250 private final float center_x = 0.5f; 251 private final float center_y = 0.5f; 252 private final float scale = 0.5f; 253 private final float shade = 0.5f; 254 private final float slope = 20.0f; 255 private ScriptGroup.Closure cInit; 256 257 public void init() { 258 s.invoke_init_vignette( 259 mInPixelsAllocation.getType().getX(), 260 mInPixelsAllocation.getType().getY(), center_x, 261 center_y, scale, shade, slope); 262 } 263 264 public ScriptGroup.Closure prepInit(ScriptGroup.Builder2 b) { 265 cInit = b.addInvoke(s.getInvokeID_init_vignette(), 266 mInPixelsAllocation.getType().getX(), 267 mInPixelsAllocation.getType().getY(), 268 center_x, 269 center_y, 270 scale, shade, slope); 271 return cInit; 272 } 273 274 public Script.KernelID getKernelID() { return s.getKernelID_vignette(); } 275 276 public void forEach(Allocation in, Allocation out) { s.forEach_vignette(in, out); } 277 278 private ScriptC_vignette_approx_relaxed_f s; 279 } 280 281 public final static Class[] mFilterClasses = { 282 ColorMatrixFilter.class, 283 ContrastFilter.class, 284 ExposureFilter.class, 285 /* The fisheye filter uses rsSample, which does not work for float4 element 286 type. 287 FisheyeFilter.class, 288 */ 289 GreyFilter.class, 290 LevelsFilter.class, 291 ShadowsFilter.class, 292 VibranceFilter.class, 293 VignetteFilter.class 294 }; 295 private FilterInterface[] mFilters; 296 private int[] mIndices; 297 298 ScriptC_uc4tof4 s_uc2f; 299 ScriptC_f4touc4 s_f2uc; 300 301 private Allocation[] mScratchPixelsAllocation = new Allocation[2]; 302 private ScriptGroup mGroup; 303 private ScriptGroup mGroup2; 304 305 private int mWidth; 306 private int mHeight; 307 private int mMode; 308 309 public static final int EMULATED = 0; 310 public static final int NATIVE2 = 1; 311 public static final int NATIVE1 = 2; 312 public static final int MANUAL = 3; 313 314 public Filters(int mode, int[] filter) { 315 mMode = mode; 316 mIndices = new int[filter.length]; 317 System.arraycopy(filter, 0, mIndices, 0, filter.length); 318 mFilters = new FilterInterface[filter.length+2]; 319 } 320 321 public void createTest(android.content.res.Resources res) { 322 s_uc2f = new ScriptC_uc4tof4(mRS); 323 s_f2uc = new ScriptC_f4touc4(mRS); 324 for (int i = 0; i < mIndices.length; i++) { 325 try { 326 /* 327 Constructor[] constructors = mFilterClasses[mIndices[i]].getConstructors(); 328 for (Constructor ctr : constructors) { 329 Log.i("Filters", "constructor " + ctr); 330 } 331 */ 332 Constructor constructor = 333 // mFilterClasses[i].getConstructor(new Class[]{ RenderScript.class }); 334 //mFilterClasses[i].getConstructor(RenderScript.class); 335 mFilterClasses[mIndices[i]].getConstructors()[0]; 336 try { 337 mFilters[i] = (FilterInterface)constructor.newInstance(this, mRS); 338 } catch (Exception e) { 339 Log.e("Filters", "newInstance caught " + e); 340 System.exit(-2); 341 } 342 mFilters[i].init(); 343 } catch (Exception e) { 344 Log.e("Filters", "getConstructor caught " + e + " for " + 345 mFilterClasses[mIndices[i]].getName()); 346 System.exit(-1); 347 } 348 349 } 350 351 mWidth = mInPixelsAllocation.getType().getX(); 352 mHeight = mInPixelsAllocation.getType().getY(); 353 354 Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS)); 355 tb.setX(mWidth); 356 tb.setY(mHeight); 357 Type connect = tb.create(); 358 359 switch (mMode) { 360 case NATIVE1: 361 ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); 362 b.addKernel(s_uc2f.getKernelID_uc4tof4()); 363 b.addKernel(mFilters[0].getKernelID()); 364 b.addConnection(connect, s_uc2f.getKernelID_uc4tof4(), 365 mFilters[0].getKernelID()); 366 367 for (int i = 0; i < mIndices.length; i++) { 368 b.addKernel(mFilters[i].getKernelID()); 369 b.addConnection(connect, mFilters[i-1].getKernelID(), 370 mFilters[i].getKernelID()); 371 } 372 373 b.addKernel(s_f2uc.getKernelID_f4touc4()); 374 b.addConnection(mOutPixelsAllocation.getType(), 375 mFilters[0].getKernelID(), s_f2uc.getKernelID_f4touc4()); 376 377 mGroup = b.create(); 378 break; 379 case NATIVE2: { 380 ScriptGroup.Builder2 b2 = new ScriptGroup.Builder2(mRS); 381 382 for (int i = 0; i < mIndices.length; i++) { 383 mFilters[i].prepInit(b2); 384 } 385 386 ScriptGroup.Input in = b2.addInput(); 387 388 ScriptGroup.Closure c = b2.addKernel(s_uc2f.getKernelID_uc4tof4(), 389 connect, in); 390 391 for (int i = 0; i < mIndices.length; i++) { 392 c = mFilters[i].asyncLaunch(b2, c.getReturn(), connect); 393 } 394 395 c = b2.addKernel(s_f2uc.getKernelID_f4touc4(), 396 mOutPixelsAllocation.getType(), 397 c.getReturn()); 398 399 final String name = mFilters[0].getClass().getSimpleName() + "-" + 400 mFilters[1].getClass().getSimpleName(); 401 mGroup2 = b2.create(name, c.getReturn()); 402 } 403 break; 404 case EMULATED: 405 mScratchPixelsAllocation[0] = Allocation.createTyped(mRS, connect); 406 mScratchPixelsAllocation[1] = Allocation.createTyped(mRS, connect); 407 break; 408 } 409 } 410 411 public void runTest() { 412 switch (mMode) { 413 case NATIVE1: 414 // mGroup.setInput(mFilters[0].getKernelID(), mInPixelsAllocation); 415 mGroup.setInput(s_uc2f.getKernelID_uc4tof4(), mInPixelsAllocation); 416 // mGroup.setOutput(mFilters[mIndices.length - 1].getKernelID(), mOutPixelsAllocation); 417 mGroup.setOutput(s_f2uc.getKernelID_f4touc4(), mOutPixelsAllocation); 418 mGroup.execute(); 419 break; 420 case NATIVE2: 421 mOutPixelsAllocation = (Allocation)mGroup2.execute(mInPixelsAllocation)[0]; 422 break; 423 case EMULATED: 424 s_uc2f.forEach_uc4tof4(mInPixelsAllocation, mScratchPixelsAllocation[0]); 425 for (int i = 0; i < mIndices.length; i++) { 426 mFilters[i].forEach(mScratchPixelsAllocation[i % 2], 427 mScratchPixelsAllocation[(i+1) % 2]); 428 } 429 s_f2uc.forEach_f4touc4(mScratchPixelsAllocation[mIndices.length % 2], 430 mOutPixelsAllocation); 431 break; 432 } 433 } 434 435 } 436