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