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