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