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