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