Home | History | Annotate | Download | only in core
      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