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