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.FrameFormat;
     22 import android.filterfw.core.FrameManager;
     23 import android.filterfw.core.NativeFrame;
     24 import android.filterfw.core.StopWatchMap;
     25 import android.graphics.Bitmap;
     26 import android.opengl.GLES20;
     27 import android.graphics.Rect;
     28 
     29 import java.nio.ByteBuffer;
     30 
     31 class GLFrameTimer {
     32 
     33     private static StopWatchMap mTimer = null;
     34 
     35     public static StopWatchMap get() {
     36         if (mTimer == null) {
     37             mTimer = new StopWatchMap();
     38         }
     39         return mTimer;
     40     }
     41 
     42 }
     43 
     44 /**
     45  * @hide
     46  */
     47 public class GLFrame extends Frame {
     48 
     49     // GL-related binding types
     50     public final static int EXISTING_TEXTURE_BINDING = 100;
     51     public final static int EXISTING_FBO_BINDING     = 101;
     52     public final static int NEW_TEXTURE_BINDING      = 102; // TODO: REMOVE THIS
     53     public final static int NEW_FBO_BINDING          = 103; // TODO: REMOVE THIS
     54     public final static int EXTERNAL_TEXTURE         = 104;
     55 
     56     private int glFrameId = -1;
     57 
     58     /**
     59      * Flag whether we own the texture or not. If we do not, we must be careful when caching or
     60      * storing the frame, as the user may delete, and regenerate it.
     61      */
     62     private boolean mOwnsTexture = true;
     63 
     64     /**
     65      * Keep a reference to the GL environment, so that it does not get deallocated while there
     66      * are still frames living in it.
     67      */
     68     private GLEnvironment mGLEnvironment;
     69 
     70     GLFrame(FrameFormat format, FrameManager frameManager) {
     71         super(format, frameManager);
     72     }
     73 
     74     GLFrame(FrameFormat format, FrameManager frameManager, int bindingType, long bindingId) {
     75         super(format, frameManager, bindingType, bindingId);
     76     }
     77 
     78     void init(GLEnvironment glEnv) {
     79         FrameFormat format = getFormat();
     80         mGLEnvironment = glEnv;
     81 
     82         // Check that we have a valid format
     83         if (format.getBytesPerSample() != 4) {
     84             throw new IllegalArgumentException("GL frames must have 4 bytes per sample!");
     85         } else if (format.getDimensionCount() != 2) {
     86             throw new IllegalArgumentException("GL frames must be 2-dimensional!");
     87         } else if (getFormat().getSize() < 0) {
     88             throw new IllegalArgumentException("Initializing GL frame with zero size!");
     89         }
     90 
     91         // Create correct frame
     92         int bindingType = getBindingType();
     93         boolean reusable = true;
     94         if (bindingType == Frame.NO_BINDING) {
     95             initNew(false);
     96         } else if (bindingType == EXTERNAL_TEXTURE) {
     97             initNew(true);
     98             reusable = false;
     99         } else if (bindingType == EXISTING_TEXTURE_BINDING) {
    100             initWithTexture((int)getBindingId());
    101         } else if (bindingType == EXISTING_FBO_BINDING) {
    102             initWithFbo((int)getBindingId());
    103         } else if (bindingType == NEW_TEXTURE_BINDING) {
    104             initWithTexture((int)getBindingId());
    105         } else if (bindingType == NEW_FBO_BINDING) {
    106             initWithFbo((int)getBindingId());
    107         } else {
    108             throw new RuntimeException("Attempting to create GL frame with unknown binding type "
    109                 + bindingType + "!");
    110         }
    111         setReusable(reusable);
    112     }
    113 
    114     private void initNew(boolean isExternal) {
    115         if (isExternal) {
    116             if (!nativeAllocateExternal(mGLEnvironment)) {
    117                 throw new RuntimeException("Could not allocate external GL frame!");
    118             }
    119         } else {
    120             if (!nativeAllocate(mGLEnvironment, getFormat().getWidth(), getFormat().getHeight())) {
    121                 throw new RuntimeException("Could not allocate GL frame!");
    122             }
    123         }
    124     }
    125 
    126     private void initWithTexture(int texId) {
    127         int width = getFormat().getWidth();
    128         int height = getFormat().getHeight();
    129         if (!nativeAllocateWithTexture(mGLEnvironment, texId, width, height)) {
    130             throw new RuntimeException("Could not allocate texture backed GL frame!");
    131         }
    132         mOwnsTexture = false;
    133         markReadOnly();
    134     }
    135 
    136     private void initWithFbo(int fboId) {
    137         int width = getFormat().getWidth();
    138         int height = getFormat().getHeight();
    139         if (!nativeAllocateWithFbo(mGLEnvironment, fboId, width, height)) {
    140             throw new RuntimeException("Could not allocate FBO backed GL frame!");
    141         }
    142     }
    143 
    144     void flushGPU(String message) {
    145         StopWatchMap timer = GLFrameTimer.get();
    146         if (timer.LOG_MFF_RUNNING_TIMES) {
    147           timer.start("glFinish " + message);
    148           GLES20.glFinish();
    149           timer.stop("glFinish " + message);
    150         }
    151     }
    152 
    153     @Override
    154     protected synchronized boolean hasNativeAllocation() {
    155         return glFrameId != -1;
    156     }
    157 
    158     @Override
    159     protected synchronized void releaseNativeAllocation() {
    160         nativeDeallocate();
    161         glFrameId = -1;
    162     }
    163 
    164     public GLEnvironment getGLEnvironment() {
    165         return mGLEnvironment;
    166     }
    167 
    168     @Override
    169     public Object getObjectValue() {
    170         assertGLEnvValid();
    171         return ByteBuffer.wrap(getNativeData());
    172     }
    173 
    174     @Override
    175     public void setInts(int[] ints) {
    176         assertFrameMutable();
    177         assertGLEnvValid();
    178         if (!setNativeInts(ints)) {
    179             throw new RuntimeException("Could not set int values for GL frame!");
    180         }
    181     }
    182 
    183     @Override
    184     public int[] getInts() {
    185         assertGLEnvValid();
    186         flushGPU("getInts");
    187         return getNativeInts();
    188     }
    189 
    190     @Override
    191     public void setFloats(float[] floats) {
    192         assertFrameMutable();
    193         assertGLEnvValid();
    194         if (!setNativeFloats(floats)) {
    195             throw new RuntimeException("Could not set int values for GL frame!");
    196         }
    197     }
    198 
    199     @Override
    200     public float[] getFloats() {
    201         assertGLEnvValid();
    202         flushGPU("getFloats");
    203         return getNativeFloats();
    204     }
    205 
    206     @Override
    207     public void setData(ByteBuffer buffer, int offset, int length) {
    208         assertFrameMutable();
    209         assertGLEnvValid();
    210         byte[] bytes = buffer.array();
    211         if (getFormat().getSize() != bytes.length) {
    212             throw new RuntimeException("Data size in setData does not match GL frame size!");
    213         } else if (!setNativeData(bytes, offset, length)) {
    214             throw new RuntimeException("Could not set GL frame data!");
    215         }
    216     }
    217 
    218     @Override
    219     public ByteBuffer getData() {
    220         assertGLEnvValid();
    221         flushGPU("getData");
    222         return ByteBuffer.wrap(getNativeData());
    223     }
    224 
    225     @Override
    226     public void setBitmap(Bitmap bitmap) {
    227         assertFrameMutable();
    228         assertGLEnvValid();
    229         if (getFormat().getWidth()  != bitmap.getWidth() ||
    230             getFormat().getHeight() != bitmap.getHeight()) {
    231             throw new RuntimeException("Bitmap dimensions do not match GL frame dimensions!");
    232         } else {
    233             Bitmap rgbaBitmap = convertBitmapToRGBA(bitmap);
    234             if (!setNativeBitmap(rgbaBitmap, rgbaBitmap.getByteCount())) {
    235                 throw new RuntimeException("Could not set GL frame bitmap data!");
    236             }
    237         }
    238     }
    239 
    240     @Override
    241     public Bitmap getBitmap() {
    242         assertGLEnvValid();
    243         flushGPU("getBitmap");
    244         Bitmap result = Bitmap.createBitmap(getFormat().getWidth(),
    245                                             getFormat().getHeight(),
    246                                             Bitmap.Config.ARGB_8888);
    247         if (!getNativeBitmap(result)) {
    248             throw new RuntimeException("Could not get bitmap data from GL frame!");
    249         }
    250         return result;
    251     }
    252 
    253     @Override
    254     public void setDataFromFrame(Frame frame) {
    255         assertGLEnvValid();
    256 
    257         // Make sure frame fits
    258         if (getFormat().getSize() < frame.getFormat().getSize()) {
    259             throw new RuntimeException(
    260                 "Attempting to assign frame of size " + frame.getFormat().getSize() + " to " +
    261                 "smaller GL frame of size " + getFormat().getSize() + "!");
    262         }
    263 
    264         // Invoke optimized implementations if possible
    265         if (frame instanceof NativeFrame) {
    266             nativeCopyFromNative((NativeFrame)frame);
    267         } else if (frame instanceof GLFrame) {
    268             nativeCopyFromGL((GLFrame)frame);
    269         } else if (frame instanceof SimpleFrame) {
    270             setObjectValue(frame.getObjectValue());
    271         } else {
    272             super.setDataFromFrame(frame);
    273         }
    274     }
    275 
    276     public void setViewport(int x, int y, int width, int height) {
    277         assertFrameMutable();
    278         setNativeViewport(x, y, width, height);
    279     }
    280 
    281     public void setViewport(Rect rect) {
    282         assertFrameMutable();
    283         setNativeViewport(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
    284     }
    285 
    286     public void generateMipMap() {
    287         assertFrameMutable();
    288         assertGLEnvValid();
    289         if (!generateNativeMipMap()) {
    290             throw new RuntimeException("Could not generate mip-map for GL frame!");
    291         }
    292     }
    293 
    294     public void setTextureParameter(int param, int value) {
    295         assertFrameMutable();
    296         assertGLEnvValid();
    297         if (!setNativeTextureParam(param, value)) {
    298             throw new RuntimeException("Could not set texture value " + param + " = " + value + " " +
    299                                        "for GLFrame!");
    300         }
    301     }
    302 
    303     public int getTextureId() {
    304         return getNativeTextureId();
    305     }
    306 
    307     public int getFboId() {
    308         return getNativeFboId();
    309     }
    310 
    311     public void focus() {
    312         if (!nativeFocus()) {
    313             throw new RuntimeException("Could not focus on GLFrame for drawing!");
    314         }
    315     }
    316 
    317     @Override
    318     public String toString() {
    319         return "GLFrame id: " + glFrameId + " (" + getFormat() + ") with texture ID "
    320             + getTextureId() + ", FBO ID " + getFboId();
    321     }
    322 
    323     @Override
    324     protected void reset(FrameFormat newFormat) {
    325         if (!nativeResetParams()) {
    326             throw new RuntimeException("Could not reset GLFrame texture parameters!");
    327         }
    328         super.reset(newFormat);
    329     }
    330 
    331     @Override
    332     protected void onFrameStore() {
    333         if (!mOwnsTexture) {
    334             // Detach texture from FBO in case user manipulates it.
    335             nativeDetachTexFromFbo();
    336         }
    337     }
    338 
    339     @Override
    340     protected void onFrameFetch() {
    341         if (!mOwnsTexture) {
    342             // Reattach texture to FBO when using frame again. This may reallocate the texture
    343             // in case it has become invalid.
    344             nativeReattachTexToFbo();
    345         }
    346     }
    347 
    348     private void assertGLEnvValid() {
    349         if (!mGLEnvironment.isContextActive()) {
    350             if (GLEnvironment.isAnyContextActive()) {
    351                 throw new RuntimeException("Attempting to access " + this + " with foreign GL " +
    352                     "context active!");
    353             } else {
    354                 throw new RuntimeException("Attempting to access " + this + " with no GL context " +
    355                     " active!");
    356             }
    357         }
    358     }
    359 
    360     static {
    361         System.loadLibrary("filterfw");
    362     }
    363 
    364     private native boolean nativeAllocate(GLEnvironment env, int width, int height);
    365 
    366     private native boolean nativeAllocateWithTexture(GLEnvironment env,
    367                                                int textureId,
    368                                                int width,
    369                                                int height);
    370 
    371     private native boolean nativeAllocateWithFbo(GLEnvironment env,
    372                                            int fboId,
    373                                            int width,
    374                                            int height);
    375 
    376     private native boolean nativeAllocateExternal(GLEnvironment env);
    377 
    378     private native boolean nativeDeallocate();
    379 
    380     private native boolean setNativeData(byte[] data, int offset, int length);
    381 
    382     private native byte[] getNativeData();
    383 
    384     private native boolean setNativeInts(int[] ints);
    385 
    386     private native boolean setNativeFloats(float[] floats);
    387 
    388     private native int[] getNativeInts();
    389 
    390     private native float[] getNativeFloats();
    391 
    392     private native boolean setNativeBitmap(Bitmap bitmap, int size);
    393 
    394     private native boolean getNativeBitmap(Bitmap bitmap);
    395 
    396     private native boolean setNativeViewport(int x, int y, int width, int height);
    397 
    398     private native int getNativeTextureId();
    399 
    400     private native int getNativeFboId();
    401 
    402     private native boolean generateNativeMipMap();
    403 
    404     private native boolean setNativeTextureParam(int param, int value);
    405 
    406     private native boolean nativeResetParams();
    407 
    408     private native boolean nativeCopyFromNative(NativeFrame frame);
    409 
    410     private native boolean nativeCopyFromGL(GLFrame frame);
    411 
    412     private native boolean nativeFocus();
    413 
    414     private native boolean nativeReattachTexToFbo();
    415 
    416     private native boolean nativeDetachTexFromFbo();
    417 }
    418