1 package com.android.rs.refocus;
2 
3 import androidx.renderscript.RenderScript;
4 import androidx.renderscript.Allocation;
5 import androidx.renderscript.Element;
6 
7 import com.android.rs.refocus.renderscript.ScriptField_KernelInfo;
8 
9 /**
10  * A class that manages the blur kernel matrices of a blending layer that
11  * interface between Java and Render Script. This class will be specialized for
12  * float in f32 package and for byte in u8 package.
13  *
14  * @author zhl@google.com (Li Zhang)
15  */
16 public class KernelDataForRenderScript {
17 	/**
18 	 *	A flag to turn on using optimized RenderScript.
19 	 *  False means using original version; true means using the new version.
20 	 */
21 	private static boolean UseNewRS = false;
22 
23   /**
24    * Number of sub-pixels that is used to generate anti-aliased blur kernel
25    * matrix. That is, we divide one pixel into
26    * {@code NUM_SUB_PIXELS * NUM_SUB_PIXELS} sub-pixels to test whether or not a
27    * pixel is in the blur disk.
28    */
29   protected static final int NUM_SUB_PIXELS = 5;
30 
31   /**
32    * The width of the pixels that are used to pad the image boundary to avoid
33    * boundary checking in filtering operation.
34    */
35   private static final int MAX_KERNEL_RADIUS =
36       computeKernelRadiusFromDiskRadius(BlurStack.getMaxDiskRadius());
37 
38   /**
39    * The length of an array that concatenates all (vectorized) kernel matrices.
40    */
41   protected int stackLength;
42 
43   /**
44    * A class automatically generated by Render Script compiler, which contains
45    * required auxiliary information to parse {@code kernelStack}, including the
46    * starting position of each kernel matrix in a memory buffer and the radius
47    * (radius_x,radius_y) of each kernel matrix. The names radius_x and radius_y
48    * follow C++ style because render script is C language.
49    */
50   protected ScriptField_KernelInfo kernelInfo;
51 
52 	/** Java array version of the current kernel info. Used when UseNewRS is true.
53 	 * 4*m: offset; 4*m + 1: radius_x; 4*m + 2: radius_y
54 	 */
55 	protected float[] infoArray;
56 
57 	/** An allocation used to store global allocation of stack info. Used when UseNewRS is true.
58 	 *
59 	 */
60     public Allocation infoAllocation;
61 
getNumSubPixels()62   public static int getNumSubPixels() {
63     return NUM_SUB_PIXELS;
64   }
65 
getMaxKernelRadius()66   public static int getMaxKernelRadius() {
67     return MAX_KERNEL_RADIUS;
68   }
69 
setUseNewRS(boolean choice)70     public static void setUseNewRS(boolean choice) {UseNewRS = choice;}
71 
72   /**
73    * Computes the kernel matrix radius from the blur disk radius.
74    *
75    * @param diskRadius blur disk radius
76    * @return kernel matrix radius
77    */
computeKernelRadiusFromDiskRadius(float diskRadius)78   public static int computeKernelRadiusFromDiskRadius(float diskRadius) {
79     return (int) (diskRadius) + 1;
80   }
81 
getKernelInfo()82   public ScriptField_KernelInfo getKernelInfo() {
83     return kernelInfo;
84   }
85 
86   /**
87    * Initializes {@code kernelInfo}.
88    *
89    * @param targetLayer the index of a target layer
90    * @param blurStack an instance of {@code BlurStack}
91    * @param renderScript an instance of {@code RenderScript}
92    */
KernelDataForRenderScript(int targetLayer, BlurStack blurStack, RenderScript renderScript)93   protected KernelDataForRenderScript(int targetLayer, BlurStack blurStack,
94       RenderScript renderScript) {
95 		if (UseNewRS) {
96 			// Use the new version of renderscript files.
97  			int numDepths = blurStack.getNumDepths(targetLayer);
98 			infoAllocation = Allocation.createSized(
99         	renderScript, Element.F32_4(renderScript),
100         	numDepths);
101 
102 			infoArray = new float[4*numDepths];
103     		// Generates information for each blur kernel matrix.
104     		int offset = 0;
105     		for (int m = 0; m < numDepths; ++m) {
106       			int depth = blurStack.getDepth(targetLayer, m);
107       			float diskRadius = blurStack.getDiskRadius(depth);
108       			int kernelRadius = computeKernelRadiusFromDiskRadius(diskRadius);
109 
110 				infoArray[m*4] = offset;
111 				infoArray[m*4 + 1] = kernelRadius;
112 				infoArray[m*4 + 2] = kernelRadius;
113 
114       			// Updates offset variable.
115       			int kernelLength = (2 * kernelRadius + 1) * (2 * kernelRadius + 1);
116       			offset += kernelLength;
117     		}
118 			infoAllocation.copyFrom(infoArray);
119     		stackLength = offset;
120 		} else {
121 			// Use original version of renderscript files.
122     		int numDepths = blurStack.getNumDepths(targetLayer);
123     		kernelInfo = new ScriptField_KernelInfo(renderScript, numDepths);
124 
125     		// Generates information for each blur kernel matrix.
126     		int offset = 0;
127     		for (int m = 0; m < numDepths; ++m) {
128       			int depth = blurStack.getDepth(targetLayer, m);
129       			float diskRadius = blurStack.getDiskRadius(depth);
130       			int kernelRadius = computeKernelRadiusFromDiskRadius(diskRadius);
131       			// Sets information for the {@code m}'th kernel matrix.
132       			kernelInfo.set_offset(m, offset, true);
133       			kernelInfo.set_radius_x(m, kernelRadius, true);
134       			kernelInfo.set_radius_y(m, kernelRadius, true);
135       			// Updates offset variable.
136       			int kernelLength = (2 * kernelRadius + 1) * (2 * kernelRadius + 1);
137       			offset += kernelLength;
138     		}
139     		stackLength = offset;
140 		}
141   }
142 }
143