1 /*
2  * Copyright (C) 2011 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 
18 package android.filterfw.core;
19 
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.filterfw.geometry.Quad;
22 import android.opengl.GLES20;
23 
24 /**
25  * @hide
26  */
27 public class ShaderProgram extends Program {
28 
29     private int shaderProgramId;
30 
31     private int mMaxTileSize = 0;
32 
33     // Keep a reference to the GL environment, so that it does not get deallocated while there
34     // are still programs living in it.
35     private GLEnvironment mGLEnvironment;
36 
37     private StopWatchMap mTimer = null;
38 
setTimer()39     private void setTimer() {
40         mTimer = new StopWatchMap();
41     }
42 
43     // Used from native layer for creating empty wrapper only!
ShaderProgram()44     private ShaderProgram() {
45     }
46 
ShaderProgram(NativeAllocatorTag tag)47     private ShaderProgram(NativeAllocatorTag tag) {
48     }
49 
50     @UnsupportedAppUsage
ShaderProgram(FilterContext context, String fragmentShader)51     public ShaderProgram(FilterContext context, String fragmentShader) {
52         mGLEnvironment = getGLEnvironment(context);
53         allocate(mGLEnvironment, null, fragmentShader);
54         if (!compileAndLink()) {
55             throw new RuntimeException("Could not compile and link shader!");
56         }
57         this.setTimer();
58     }
59 
ShaderProgram(FilterContext context, String vertexShader, String fragmentShader)60     public ShaderProgram(FilterContext context, String vertexShader, String fragmentShader) {
61         mGLEnvironment = getGLEnvironment(context);
62         allocate(mGLEnvironment, vertexShader, fragmentShader);
63         if (!compileAndLink()) {
64             throw new RuntimeException("Could not compile and link shader!");
65         }
66         this.setTimer();
67     }
68 
69     @UnsupportedAppUsage
createIdentity(FilterContext context)70     public static ShaderProgram createIdentity(FilterContext context) {
71         ShaderProgram program = nativeCreateIdentity(getGLEnvironment(context));
72         program.setTimer();
73         return program;
74     }
75 
76     @Override
finalize()77     protected void finalize() throws Throwable {
78         deallocate();
79     }
80 
getGLEnvironment()81     public GLEnvironment getGLEnvironment() {
82         return mGLEnvironment;
83     }
84 
85     @Override
86     @UnsupportedAppUsage
process(Frame[] inputs, Frame output)87     public void process(Frame[] inputs, Frame output) {
88         if (mTimer.LOG_MFF_RUNNING_TIMES) {
89           mTimer.start("glFinish");
90           GLES20.glFinish();
91           mTimer.stop("glFinish");
92         }
93 
94         // Get the GL input frames
95         // TODO: We do the same in the NativeProgram... can we find a better way?!
96         GLFrame[] glInputs = new GLFrame[inputs.length];
97         for (int i = 0; i < inputs.length; ++i) {
98             if (inputs[i] instanceof GLFrame) {
99                 glInputs[i] = (GLFrame)inputs[i];
100             } else {
101                 throw new RuntimeException("ShaderProgram got non-GL frame as input " + i + "!");
102             }
103         }
104 
105         // Get the GL output frame
106         GLFrame glOutput = null;
107         if (output instanceof GLFrame) {
108             glOutput = (GLFrame)output;
109         } else {
110             throw new RuntimeException("ShaderProgram got non-GL output frame!");
111         }
112 
113         // Adjust tiles to meet maximum tile size requirement
114         if (mMaxTileSize > 0) {
115             int xTiles = (output.getFormat().getWidth() + mMaxTileSize - 1) / mMaxTileSize;
116             int yTiles = (output.getFormat().getHeight() + mMaxTileSize - 1) / mMaxTileSize;
117             setShaderTileCounts(xTiles, yTiles);
118         }
119 
120         // Process!
121         if (!shaderProcess(glInputs, glOutput)) {
122             throw new RuntimeException("Error executing ShaderProgram!");
123         }
124 
125         if (mTimer.LOG_MFF_RUNNING_TIMES) {
126           GLES20.glFinish();
127         }
128     }
129 
130     @Override
131     @UnsupportedAppUsage
setHostValue(String variableName, Object value)132     public void setHostValue(String variableName, Object value) {
133         if (!setUniformValue(variableName, value)) {
134             throw new RuntimeException("Error setting uniform value for variable '" +
135                                        variableName + "'!");
136         }
137     }
138 
139     @Override
getHostValue(String variableName)140     public Object getHostValue(String variableName) {
141         return getUniformValue(variableName);
142     }
143 
setAttributeValues(String attributeName, float[] data, int componentCount)144     public void setAttributeValues(String attributeName, float[] data, int componentCount) {
145         if (!setShaderAttributeValues(attributeName, data, componentCount)) {
146             throw new RuntimeException("Error setting attribute value for attribute '" +
147                                        attributeName + "'!");
148         }
149     }
150 
setAttributeValues(String attributeName, VertexFrame vertexData, int type, int componentCount, int strideInBytes, int offsetInBytes, boolean normalize)151     public void setAttributeValues(String attributeName,
152                                    VertexFrame vertexData,
153                                    int type,
154                                    int componentCount,
155                                    int strideInBytes,
156                                    int offsetInBytes,
157                                    boolean normalize) {
158         if (!setShaderAttributeVertexFrame(attributeName,
159                                            vertexData,
160                                            type,
161                                            componentCount,
162                                            strideInBytes,
163                                            offsetInBytes,
164                                            normalize)) {
165             throw new RuntimeException("Error setting attribute value for attribute '" +
166                                        attributeName + "'!");
167         }
168     }
169 
170     @UnsupportedAppUsage
setSourceRegion(Quad region)171     public void setSourceRegion(Quad region) {
172         setSourceRegion(region.p0.x, region.p0.y,
173                         region.p1.x, region.p1.y,
174                         region.p2.x, region.p2.y,
175                         region.p3.x, region.p3.y);
176     }
177 
setTargetRegion(Quad region)178     public void setTargetRegion(Quad region) {
179         setTargetRegion(region.p0.x, region.p0.y,
180                         region.p1.x, region.p1.y,
181                         region.p2.x, region.p2.y,
182                         region.p3.x, region.p3.y);
183     }
184 
185     @UnsupportedAppUsage
setSourceRect(float x, float y, float width, float height)186     public void setSourceRect(float x, float y, float width, float height) {
187         setSourceRegion(x, y, x + width, y, x, y + height, x + width, y + height);
188     }
189 
setTargetRect(float x, float y, float width, float height)190     public void setTargetRect(float x, float y, float width, float height) {
191         setTargetRegion(x, y, x + width, y, x, y + height, x + width, y + height);
192     }
193 
setClearsOutput(boolean clears)194     public void setClearsOutput(boolean clears) {
195         if (!setShaderClearsOutput(clears)) {
196             throw new RuntimeException("Could not set clears-output flag to " + clears + "!");
197         }
198     }
199 
setClearColor(float r, float g, float b)200     public void setClearColor(float r, float g, float b) {
201         if (!setShaderClearColor(r, g, b)) {
202             throw new RuntimeException("Could not set clear color to " + r + "," + g + "," + b + "!");
203         }
204     }
205 
setBlendEnabled(boolean enable)206     public void setBlendEnabled(boolean enable) {
207         if (!setShaderBlendEnabled(enable)) {
208             throw new RuntimeException("Could not set Blending " + enable + "!");
209         }
210     }
211 
setBlendFunc(int sfactor, int dfactor)212     public void setBlendFunc(int sfactor, int dfactor) {
213         if (!setShaderBlendFunc(sfactor, dfactor)) {
214             throw new RuntimeException("Could not set BlendFunc " + sfactor +","+ dfactor + "!");
215         }
216     }
217 
setDrawMode(int drawMode)218     public void setDrawMode(int drawMode) {
219         if (!setShaderDrawMode(drawMode)) {
220             throw new RuntimeException("Could not set GL draw-mode to " + drawMode + "!");
221         }
222     }
223 
setVertexCount(int count)224     public void setVertexCount(int count) {
225         if (!setShaderVertexCount(count)) {
226             throw new RuntimeException("Could not set GL vertex count to " + count + "!");
227         }
228     }
229 
230     @UnsupportedAppUsage
setMaximumTileSize(int size)231     public void setMaximumTileSize(int size) {
232         mMaxTileSize = size;
233     }
234 
beginDrawing()235     public void beginDrawing() {
236         if (!beginShaderDrawing()) {
237             throw new RuntimeException("Could not prepare shader-program for drawing!");
238         }
239     }
240 
getGLEnvironment(FilterContext context)241     private static GLEnvironment getGLEnvironment(FilterContext context) {
242         GLEnvironment result = context != null ? context.getGLEnvironment() : null;
243         if (result == null) {
244             throw new NullPointerException("Attempting to create ShaderProgram with no GL "
245                 + "environment in place!");
246         }
247         return result;
248     }
249 
250     static {
251         System.loadLibrary("filterfw");
252     }
253 
allocate(GLEnvironment glEnv, String vertexShader, String fragmentShader)254     private native boolean allocate(GLEnvironment glEnv,
255                                     String vertexShader,
256                                     String fragmentShader);
257 
deallocate()258     private native boolean deallocate();
259 
compileAndLink()260     private native boolean compileAndLink();
261 
shaderProcess(GLFrame[] inputs, GLFrame output)262     private native boolean shaderProcess(GLFrame[] inputs, GLFrame output);
263 
setUniformValue(String name, Object value)264     private native boolean setUniformValue(String name, Object value);
265 
getUniformValue(String name)266     private native Object getUniformValue(String name);
267 
setSourceRegion(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)268     public native boolean setSourceRegion(float x0, float y0, float x1, float y1,
269                                           float x2, float y2, float x3, float y3);
270 
setTargetRegion(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)271     private native boolean setTargetRegion(float x0, float y0, float x1, float y1,
272                                            float x2, float y2, float x3, float y3);
273 
nativeCreateIdentity(GLEnvironment glEnv)274     private static native ShaderProgram nativeCreateIdentity(GLEnvironment glEnv);
275 
setShaderClearsOutput(boolean clears)276     private native boolean setShaderClearsOutput(boolean clears);
277 
setShaderBlendEnabled(boolean enable)278     private native boolean setShaderBlendEnabled(boolean enable);
279 
setShaderBlendFunc(int sfactor, int dfactor)280     private native boolean setShaderBlendFunc(int sfactor, int dfactor);
281 
setShaderClearColor(float r, float g, float b)282     private native boolean setShaderClearColor(float r, float g, float b);
283 
setShaderDrawMode(int drawMode)284     private native boolean setShaderDrawMode(int drawMode);
285 
setShaderTileCounts(int xCount, int yCount)286     private native boolean setShaderTileCounts(int xCount, int yCount);
287 
setShaderVertexCount(int vertexCount)288     private native boolean setShaderVertexCount(int vertexCount);
289 
beginShaderDrawing()290     private native boolean beginShaderDrawing();
291 
setShaderAttributeValues(String attributeName, float[] data, int componentCount)292     private native boolean setShaderAttributeValues(String attributeName,
293                                                     float[] data,
294                                                     int componentCount);
295 
setShaderAttributeVertexFrame(String attributeName, VertexFrame vertexData, int type, int componentCount, int strideInBytes, int offsetInBytes, boolean normalize)296     private native boolean setShaderAttributeVertexFrame(String attributeName,
297                                                          VertexFrame vertexData,
298                                                          int type,
299                                                          int componentCount,
300                                                          int strideInBytes,
301                                                          int offsetInBytes,
302                                                          boolean normalize);
303 
304 }
305