1 /*
2  * Copyright (C) 2015 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.refocus.f32;
18 
19 import android.renderscript.Allocation;
20 import android.renderscript.Element;
21 import android.renderscript.RenderScript;
22 import android.renderscript.cts.refocus.BlurStack;
23 import android.renderscript.cts.refocus.KernelDataForRenderScript;
24 
25 import java.util.Arrays;
26 
27 /**
28  * A class that manages the blur kernel matrices of a blending layer that
29  * interface between Java and Render Script.
30  */
31 public class KernelDataForRenderScriptF32 extends KernelDataForRenderScript {
32   /**
33    * A stack of blur kernel matrices packed into a continuous memory buffer.
34    */
35   float[] kernelStack;
36 
37   /**
38    * The minimum blur disk in the stack.
39    */
40   float minDiskRadius;
41 
42   /**
43    * An RenderScript Allocation for kernelStack.
44    */
45   Allocation stackAllocation;
46 
47   /**
48    * Initializes {@code kernelStack} and {@code kernelInfo}.
49    *
50    * @param targetLayer the index of a target layer
51    * @param blurStack an instance of {@code BlurStack}
52    * @param renderScript an instance of {@code RenderScript}
53    */
KernelDataForRenderScriptF32(int targetLayer, BlurStack blurStack, RenderScript renderScript)54   public KernelDataForRenderScriptF32(int targetLayer, BlurStack blurStack,
55       RenderScript renderScript) {
56     super(targetLayer, blurStack, renderScript);
57     // stackLength is set in super.
58 
59     kernelStack = new float[stackLength];
60     int numDepths = blurStack.getNumDepths(targetLayer);
61     minDiskRadius = BlurStack.getMaxDiskRadius();
62     for (int m = 0; m < numDepths; ++m) {
63       int depth = blurStack.getDepth(targetLayer, m);
64       float diskRadius = blurStack.getDiskRadius(depth);
65       float[] kernelMatrix = getKernel(diskRadius);
66       System.arraycopy(kernelMatrix, 0, kernelStack, kernelInfo.get_offset(m),
67           kernelMatrix.length);
68       minDiskRadius = Math.min(minDiskRadius, diskRadius);
69     }
70 
71     stackAllocation = Allocation.createSized(renderScript,
72         Element.F32(renderScript), kernelStack.length);
73     stackAllocation.copyFrom(kernelStack);
74   }
75 
76   /**
77    * Returns the kernel matrix of a depth level.
78    *
79    * @param diskRadius disk radius of the kernel.
80    * @return the kernel matrix of the disk radius.
81    */
getKernel(float diskRadius)82   public float[] getKernel(float diskRadius) {
83     int kernelRadius = computeKernelRadiusFromDiskRadius(diskRadius);
84     return generateDiskKernelArray(diskRadius, kernelRadius);
85   }
86 
87   /**
88    * Generates a blur kernel matrix for a blur disk with radius
89    * {@code diskRadius}.
90    *
91    * @param diskRadius radius of blur disk
92    * @param kernelRadius radius of blur kernel matrix
93    * @return a kernel matrix represented as an array
94    */
generateDiskKernelArray(float diskRadius, int kernelRadius)95   private static float[] generateDiskKernelArray(float diskRadius,
96       int kernelRadius) {
97     int kernelDim = 2 * kernelRadius + 1;
98     int kernelLength = kernelDim * kernelDim;
99 
100     float[] kernel = new float[kernelLength];
101     Arrays.fill(kernel, 0);
102 
103     // Generates {@code NUM_SUB_PIXELS*NUM_SUB_PIXELS} sub-pixel shifts {@code
104     // (dx,dy)} uniformly within [-0.5,0.5]*[-0.5,0.5].
105     // For each shift, tests whether or not the shifted pixel is within the
106     // disc and accumulates the count.
107     float diskRadius2 = diskRadius * diskRadius;
108     float dy0 = -0.5f + 1.0f / (2 * getNumSubPixels());
109     float dx0 = -0.5f + 1.0f / (2 * getNumSubPixels());
110 
111     float sumKernelValues = 0;
112     for (int v = 0; v < getNumSubPixels(); ++v) {
113       float dy = dy0 + (float) v / (float) getNumSubPixels();
114       for (int u = 0; u < getNumSubPixels(); ++u) {
115         float dx = dx0 + (float) u / (float) getNumSubPixels();
116         for (int y = 0; y < kernelDim; ++y) {
117           float yf = y - kernelRadius + dy;
118           for (int x = 0; x < kernelDim; ++x) {
119             float xf = x - kernelRadius + dx;
120             if (yf * yf + xf * xf <= diskRadius2) {
121               kernel[y * kernelDim + x] += 1;
122               sumKernelValues += 1;
123             }
124           }
125         }
126       }
127     }
128 
129     // Normalizes kernel elements such that they sum up to 1.
130     for (int n = 0; n < kernelLength; ++n) {
131       kernel[n] /= sumKernelValues;
132     }
133 
134     return kernel;
135   }
136 }
137