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