android_view_TextureView.cpp revision 76f56dd598045dadae6dee5e8547bd077b980d5c
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#include "jni.h" 18#include <nativehelper/JNIHelp.h> 19#include <android_runtime/AndroidRuntime.h> 20#include <android_runtime/android_graphics_SurfaceTexture.h> 21 22#include <ui/Region.h> 23#include <ui/Rect.h> 24 25#include <gui/GLConsumer.h> 26#include <gui/Surface.h> 27 28#include <SkBitmap.h> 29#include <SkCanvas.h> 30 31namespace android { 32 33// ---------------------------------------------------------------------------- 34// JNI Glue 35// ---------------------------------------------------------------------------- 36 37static struct { 38 jmethodID set; 39 jfieldID left; 40 jfieldID top; 41 jfieldID right; 42 jfieldID bottom; 43} gRectClassInfo; 44 45static struct { 46 jfieldID mFinalizer; 47 jfieldID mNativeCanvas; 48 jfieldID mSurfaceFormat; 49} gCanvasClassInfo; 50 51static struct { 52 jfieldID mNativeCanvas; 53} gCanvasFinalizerClassInfo; 54 55static struct { 56 jfieldID nativeWindow; 57} gTextureViewClassInfo; 58 59#define GET_INT(object, field) \ 60 env->GetIntField(object, field) 61 62#define SET_INT(object, field, value) \ 63 env->SetIntField(object, field, value) 64 65#define INVOKEV(object, method, ...) \ 66 env->CallVoidMethod(object, method, __VA_ARGS__) 67 68// ---------------------------------------------------------------------------- 69// Native layer 70// ---------------------------------------------------------------------------- 71 72static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject, 73 jobject surface, jint width, jint height) { 74 75 sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface)); 76 glConsumer->setDefaultBufferSize(width, height); 77} 78 79static inline SkBitmap::Config convertPixelFormat(int32_t format) { 80 switch (format) { 81 case WINDOW_FORMAT_RGBA_8888: 82 return SkBitmap::kARGB_8888_Config; 83 case WINDOW_FORMAT_RGBX_8888: 84 return SkBitmap::kARGB_8888_Config; 85 case WINDOW_FORMAT_RGB_565: 86 return SkBitmap::kRGB_565_Config; 87 default: 88 return SkBitmap::kNo_Config; 89 } 90} 91 92/** 93 * This is a private API, and this implementation is also provided in the NDK. 94 * However, the NDK links against android_runtime, which means that using the 95 * NDK implementation would create a circular dependency between the libraries. 96 */ 97static int32_t native_window_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, 98 Rect* inOutDirtyBounds) { 99 return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds); 100} 101 102static int32_t native_window_unlockAndPost(ANativeWindow* window) { 103 return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST); 104} 105 106static void android_view_TextureView_createNativeWindow(JNIEnv* env, jobject textureView, 107 jobject surface) { 108 109 sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface)); 110 sp<ANativeWindow> window = new Surface(glConsumer->getBufferQueue()); 111 112 window->incStrong(0); 113 SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get())); 114} 115 116static void android_view_TextureView_destroyNativeWindow(JNIEnv* env, jobject textureView) { 117 118 ANativeWindow* nativeWindow = (ANativeWindow*) 119 GET_INT(textureView, gTextureViewClassInfo.nativeWindow); 120 121 if (nativeWindow) { 122 sp<ANativeWindow> window(nativeWindow); 123 window->decStrong(0); 124 SET_INT(textureView, gTextureViewClassInfo.nativeWindow, 0); 125 } 126} 127 128static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) { 129 jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer); 130 SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>( 131 env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas)); 132 env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas); 133 env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas); 134 SkSafeUnref(previousCanvas); 135} 136 137static void android_view_TextureView_lockCanvas(JNIEnv* env, jobject, 138 jint nativeWindow, jobject canvas, jobject dirtyRect) { 139 140 if (!nativeWindow) { 141 return; 142 } 143 144 ANativeWindow_Buffer buffer; 145 146 Rect rect; 147 if (dirtyRect) { 148 rect.left = GET_INT(dirtyRect, gRectClassInfo.left); 149 rect.top = GET_INT(dirtyRect, gRectClassInfo.top); 150 rect.right = GET_INT(dirtyRect, gRectClassInfo.right); 151 rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom); 152 } else { 153 rect.set(Rect(0x3FFF, 0x3FFF)); 154 } 155 156 sp<ANativeWindow> window((ANativeWindow*) nativeWindow); 157 native_window_lock(window.get(), &buffer, &rect); 158 159 ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format); 160 161 SkBitmap bitmap; 162 bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount); 163 164 if (buffer.format == WINDOW_FORMAT_RGBX_8888) { 165 bitmap.setIsOpaque(true); 166 } 167 168 if (buffer.width > 0 && buffer.height > 0) { 169 bitmap.setPixels(buffer.bits); 170 } else { 171 bitmap.setPixels(NULL); 172 } 173 174 SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format); 175 176 SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap)); 177 swapCanvasPtr(env, canvas, nativeCanvas); 178 179 SkRect clipRect; 180 clipRect.set(rect.left, rect.top, rect.right, rect.bottom); 181 nativeCanvas->clipRect(clipRect); 182 183 if (dirtyRect) { 184 INVOKEV(dirtyRect, gRectClassInfo.set, 185 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); 186 } 187} 188 189static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject, 190 jint nativeWindow, jobject canvas) { 191 192 SkCanvas* nativeCanvas = SkNEW(SkCanvas); 193 swapCanvasPtr(env, canvas, nativeCanvas); 194 195 if (nativeWindow) { 196 sp<ANativeWindow> window((ANativeWindow*) nativeWindow); 197 native_window_unlockAndPost(window.get()); 198 } 199} 200 201// ---------------------------------------------------------------------------- 202// JNI Glue 203// ---------------------------------------------------------------------------- 204 205const char* const kClassPathName = "android/view/TextureView"; 206 207static JNINativeMethod gMethods[] = { 208 { "nSetDefaultBufferSize", "(Landroid/graphics/SurfaceTexture;II)V", 209 (void*) android_view_TextureView_setDefaultBufferSize }, 210 211 { "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V", 212 (void*) android_view_TextureView_createNativeWindow }, 213 { "nDestroyNativeWindow", "()V", 214 (void*) android_view_TextureView_destroyNativeWindow }, 215 216 { "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)V", 217 (void*) android_view_TextureView_lockCanvas }, 218 { "nUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V", 219 (void*) android_view_TextureView_unlockCanvasAndPost }, 220}; 221 222#define FIND_CLASS(var, className) \ 223 var = env->FindClass(className); \ 224 LOG_FATAL_IF(!var, "Unable to find class " className); 225 226#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ 227 var = env->GetMethodID(clazz, methodName, methodDescriptor); \ 228 LOG_FATAL_IF(!var, "Unable to find method " methodName); 229 230#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 231 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 232 LOG_FATAL_IF(!var, "Unable to find field" fieldName); 233 234int register_android_view_TextureView(JNIEnv* env) { 235 jclass clazz; 236 FIND_CLASS(clazz, "android/graphics/Rect"); 237 GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V"); 238 GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I"); 239 GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I"); 240 GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I"); 241 GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I"); 242 243 FIND_CLASS(clazz, "android/graphics/Canvas"); 244 GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;"); 245 GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); 246 GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I"); 247 248 FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer"); 249 GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); 250 251 FIND_CLASS(clazz, "android/view/TextureView"); 252 GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "I"); 253 254 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 255} 256 257}; 258