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 setTimer()43 private void setTimer() { 44 mTimer = new StopWatchMap(); 45 } 46 47 // Used from native layer for creating empty wrapper only! ShaderProgram()48 private ShaderProgram() { 49 } 50 ShaderProgram(NativeAllocatorTag tag)51 private ShaderProgram(NativeAllocatorTag tag) { 52 } 53 ShaderProgram(FilterContext context, String fragmentShader)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 ShaderProgram(FilterContext context, String vertexShader, String fragmentShader)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 createIdentity(FilterContext context)72 public static ShaderProgram createIdentity(FilterContext context) { 73 ShaderProgram program = nativeCreateIdentity(getGLEnvironment(context)); 74 program.setTimer(); 75 return program; 76 } 77 78 @Override finalize()79 protected void finalize() throws Throwable { 80 deallocate(); 81 } 82 getGLEnvironment()83 public GLEnvironment getGLEnvironment() { 84 return mGLEnvironment; 85 } 86 87 @Override process(Frame[] inputs, Frame output)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 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 setSourceRegion(Quad region)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 setTargetRegion(Quad region)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 setSourceRect(float x, float y, float width, float height)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 setTargetRect(float x, float y, float width, float height)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 setClearsOutput(boolean clears)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 setClearColor(float r, float g, float b)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 setBlendEnabled(boolean enable)204 public void setBlendEnabled(boolean enable) { 205 if (!setShaderBlendEnabled(enable)) { 206 throw new RuntimeException("Could not set Blending " + enable + "!"); 207 } 208 } 209 setBlendFunc(int sfactor, int dfactor)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 setDrawMode(int drawMode)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 setVertexCount(int count)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 setMaximumTileSize(int size)228 public void setMaximumTileSize(int size) { 229 mMaxTileSize = size; 230 } 231 beginDrawing()232 public void beginDrawing() { 233 if (!beginShaderDrawing()) { 234 throw new RuntimeException("Could not prepare shader-program for drawing!"); 235 } 236 } 237 getGLEnvironment(FilterContext context)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 allocate(GLEnvironment glEnv, String vertexShader, String fragmentShader)251 private native boolean allocate(GLEnvironment glEnv, 252 String vertexShader, 253 String fragmentShader); 254 deallocate()255 private native boolean deallocate(); 256 compileAndLink()257 private native boolean compileAndLink(); 258 shaderProcess(GLFrame[] inputs, GLFrame output)259 private native boolean shaderProcess(GLFrame[] inputs, GLFrame output); 260 setUniformValue(String name, Object value)261 private native boolean setUniformValue(String name, Object value); 262 getUniformValue(String name)263 private native Object getUniformValue(String name); 264 setSourceRegion(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)265 public native boolean setSourceRegion(float x0, float y0, float x1, float y1, 266 float x2, float y2, float x3, float y3); 267 setTargetRegion(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)268 private native boolean setTargetRegion(float x0, float y0, float x1, float y1, 269 float x2, float y2, float x3, float y3); 270 nativeCreateIdentity(GLEnvironment glEnv)271 private static native ShaderProgram nativeCreateIdentity(GLEnvironment glEnv); 272 setShaderClearsOutput(boolean clears)273 private native boolean setShaderClearsOutput(boolean clears); 274 setShaderBlendEnabled(boolean enable)275 private native boolean setShaderBlendEnabled(boolean enable); 276 setShaderBlendFunc(int sfactor, int dfactor)277 private native boolean setShaderBlendFunc(int sfactor, int dfactor); 278 setShaderClearColor(float r, float g, float b)279 private native boolean setShaderClearColor(float r, float g, float b); 280 setShaderDrawMode(int drawMode)281 private native boolean setShaderDrawMode(int drawMode); 282 setShaderTileCounts(int xCount, int yCount)283 private native boolean setShaderTileCounts(int xCount, int yCount); 284 setShaderVertexCount(int vertexCount)285 private native boolean setShaderVertexCount(int vertexCount); 286 beginShaderDrawing()287 private native boolean beginShaderDrawing(); 288 setShaderAttributeValues(String attributeName, float[] data, int componentCount)289 private native boolean setShaderAttributeValues(String attributeName, 290 float[] data, 291 int componentCount); 292 setShaderAttributeVertexFrame(String attributeName, VertexFrame vertexData, int type, int componentCount, int strideInBytes, int offsetInBytes, boolean normalize)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