android_view_ThreadedRenderer.cpp revision 3b20251a355c88193c439f928a84ae69483fb488
1/* 2 * Copyright (C) 2010 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#define LOG_TAG "ThreadedRenderer" 18 19#include <algorithm> 20 21#include "jni.h" 22#include <nativehelper/JNIHelp.h> 23#include <android_runtime/AndroidRuntime.h> 24 25#include <EGL/egl.h> 26#include <EGL/eglext.h> 27#include <EGL/egl_cache.h> 28 29#include <utils/StrongPointer.h> 30#include <android_runtime/android_view_Surface.h> 31#include <system/window.h> 32 33#include "android_view_GraphicBuffer.h" 34 35#include <Animator.h> 36#include <RenderNode.h> 37#include <renderthread/CanvasContext.h> 38#include <renderthread/RenderProxy.h> 39#include <renderthread/RenderTask.h> 40#include <renderthread/RenderThread.h> 41#include <Vector.h> 42 43namespace android { 44 45#ifdef USE_OPENGL_RENDERER 46 47using namespace android::uirenderer; 48using namespace android::uirenderer::renderthread; 49 50static jmethodID gRunnableMethod; 51 52static JNIEnv* getenv(JavaVM* vm) { 53 JNIEnv* env; 54 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { 55 LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm); 56 } 57 return env; 58} 59 60class JavaTask : public RenderTask { 61public: 62 JavaTask(JNIEnv* env, jobject jrunnable) { 63 env->GetJavaVM(&mVm); 64 mRunnable = env->NewGlobalRef(jrunnable); 65 } 66 67 virtual void run() { 68 JNIEnv* env = getenv(mVm); 69 env->CallVoidMethod(mRunnable, gRunnableMethod); 70 env->DeleteGlobalRef(mRunnable); 71 delete this; 72 }; 73 74private: 75 JavaVM* mVm; 76 jobject mRunnable; 77}; 78 79class OnFinishedEvent { 80public: 81 OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener) 82 : animator(animator), listener(listener) {} 83 sp<BaseRenderNodeAnimator> animator; 84 sp<AnimationListener> listener; 85}; 86 87class InvokeAnimationListeners : public MessageHandler { 88public: 89 InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) { 90 mOnFinishedEvents.swap(events); 91 } 92 93 static void callOnFinished(OnFinishedEvent& event) { 94 event.listener->onAnimationFinished(event.animator.get()); 95 } 96 97 virtual void handleMessage(const Message& message) { 98 std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished); 99 mOnFinishedEvents.clear(); 100 } 101 102private: 103 std::vector<OnFinishedEvent> mOnFinishedEvents; 104}; 105 106class RenderingException : public MessageHandler { 107public: 108 RenderingException(JavaVM* vm, const std::string& message) 109 : mVm(vm) 110 , mMessage(message) { 111 } 112 113 virtual void handleMessage(const Message&) { 114 throwException(mVm, mMessage); 115 } 116 117 static void throwException(JavaVM* vm, const std::string& message) { 118 JNIEnv* env = getenv(vm); 119 jniThrowException(env, "java/lang/IllegalStateException", message.c_str()); 120 } 121 122private: 123 JavaVM* mVm; 124 std::string mMessage; 125}; 126 127class RootRenderNode : public RenderNode, AnimationHook, ErrorHandler { 128public: 129 RootRenderNode(JNIEnv* env) : RenderNode() { 130 mLooper = Looper::getForThread(); 131 LOG_ALWAYS_FATAL_IF(!mLooper.get(), 132 "Must create RootRenderNode on a thread with a looper!"); 133 env->GetJavaVM(&mVm); 134 } 135 136 virtual ~RootRenderNode() {} 137 138 virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) { 139 OnFinishedEvent event(animator, listener); 140 mOnFinishedEvents.push_back(event); 141 } 142 143 virtual void onError(const std::string& message) { 144 mLooper->sendMessage(new RenderingException(mVm, message), 0); 145 } 146 147 virtual void prepareTree(TreeInfo& info) { 148 info.animationHook = this; 149 info.errorHandler = this; 150 RenderNode::prepareTree(info); 151 info.animationHook = NULL; 152 info.errorHandler = NULL; 153 154 // post all the finished stuff 155 if (mOnFinishedEvents.size()) { 156 sp<InvokeAnimationListeners> message 157 = new InvokeAnimationListeners(mOnFinishedEvents); 158 mLooper->sendMessage(message, 0); 159 } 160 } 161 162protected: 163 virtual void damageSelf(TreeInfo& info) { 164 // Intentionally a no-op. As RootRenderNode gets a new DisplayListData 165 // every frame this would result in every draw push being a full inval, 166 // which is wrong. Only RootRenderNode has this issue. 167 } 168 169private: 170 sp<Looper> mLooper; 171 std::vector<OnFinishedEvent> mOnFinishedEvents; 172 JavaVM* mVm; 173}; 174 175static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz, 176 jlong proxyPtr, jobject graphicBuffer, jlongArray atlasMapArray) { 177 sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer); 178 jsize len = env->GetArrayLength(atlasMapArray); 179 if (len <= 0) { 180 ALOGW("Failed to initialize atlas, invalid map length: %d", len); 181 return; 182 } 183 int64_t* map = new int64_t[len]; 184 env->GetLongArrayRegion(atlasMapArray, 0, len, map); 185 186 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 187 proxy->setTextureAtlas(buffer, map, len); 188} 189 190static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) { 191 RootRenderNode* node = new RootRenderNode(env); 192 node->incStrong(0); 193 node->setName("RootRenderNode"); 194 return reinterpret_cast<jlong>(node); 195} 196 197static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz, 198 jboolean translucent, jlong rootRenderNodePtr) { 199 RenderNode* rootRenderNode = reinterpret_cast<RenderNode*>(rootRenderNodePtr); 200 return (jlong) new RenderProxy(translucent, rootRenderNode); 201} 202 203static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz, 204 jlong proxyPtr) { 205 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 206 delete proxy; 207} 208 209static void android_view_ThreadedRenderer_setFrameInterval(JNIEnv* env, jobject clazz, 210 jlong proxyPtr, jlong frameIntervalNanos) { 211 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 212 proxy->setFrameInterval(frameIntervalNanos); 213} 214 215static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz, 216 jlong proxyPtr) { 217 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 218 return proxy->loadSystemProperties(); 219} 220 221static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz, 222 jlong proxyPtr, jobject jsurface) { 223 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 224 sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface); 225 return proxy->initialize(window); 226} 227 228static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz, 229 jlong proxyPtr, jobject jsurface) { 230 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 231 sp<ANativeWindow> window; 232 if (jsurface) { 233 window = android_view_Surface_getNativeWindow(env, jsurface); 234 } 235 proxy->updateSurface(window); 236} 237 238static void android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz, 239 jlong proxyPtr, jobject jsurface) { 240 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 241 sp<ANativeWindow> window; 242 if (jsurface) { 243 window = android_view_Surface_getNativeWindow(env, jsurface); 244 } 245 proxy->pauseSurface(window); 246} 247 248static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr, 249 jint width, jint height, 250 jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius) { 251 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 252 proxy->setup(width, height, Vector3(lightX, lightY, lightZ), lightRadius); 253} 254 255static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz, 256 jlong proxyPtr, jboolean opaque) { 257 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 258 proxy->setOpaque(opaque); 259} 260 261static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz, 262 jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) { 263 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 264 return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density); 265} 266 267static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz, 268 jlong proxyPtr) { 269 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 270 proxy->destroyCanvasAndSurface(); 271} 272 273static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz, 274 jlong functorPtr, jboolean waitForCompletion) { 275 Functor* functor = reinterpret_cast<Functor*>(functorPtr); 276 RenderProxy::invokeFunctor(functor, waitForCompletion); 277} 278 279static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz, 280 jlong proxyPtr, jobject jrunnable) { 281 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 282 RenderTask* task = new JavaTask(env, jrunnable); 283 proxy->runWithGlContext(task); 284} 285 286static jlong android_view_ThreadedRenderer_createDisplayListLayer(JNIEnv* env, jobject clazz, 287 jlong proxyPtr, jint width, jint height) { 288 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 289 DeferredLayerUpdater* layer = proxy->createDisplayListLayer(width, height); 290 return reinterpret_cast<jlong>(layer); 291} 292 293static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz, 294 jlong proxyPtr) { 295 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 296 DeferredLayerUpdater* layer = proxy->createTextureLayer(); 297 return reinterpret_cast<jlong>(layer); 298} 299 300static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz, 301 jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) { 302 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 303 DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr); 304 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr); 305 return proxy->copyLayerInto(layer, bitmap); 306} 307 308static void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz, 309 jlong proxyPtr, jlong layerPtr) { 310 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 311 DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr); 312 proxy->pushLayerUpdate(layer); 313} 314 315static void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz, 316 jlong proxyPtr, jlong layerPtr) { 317 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 318 DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr); 319 proxy->cancelLayerUpdate(layer); 320} 321 322static void android_view_ThreadedRenderer_flushCaches(JNIEnv* env, jobject clazz, 323 jlong proxyPtr, jint flushMode) { 324 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 325 proxy->flushCaches(static_cast<Caches::FlushMode>(flushMode)); 326} 327 328static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz, 329 jlong proxyPtr) { 330 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 331 proxy->fence(); 332} 333 334static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz, 335 jlong proxyPtr) { 336 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 337 proxy->notifyFramePending(); 338} 339 340static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz, 341 jlong proxyPtr, jobject javaFileDescriptor) { 342 RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); 343 int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor); 344 proxy->dumpProfileInfo(fd); 345} 346 347#endif 348 349// ---------------------------------------------------------------------------- 350// Shaders 351// ---------------------------------------------------------------------------- 352 353static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz, 354 jstring diskCachePath) { 355 356 const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL); 357 egl_cache_t::get()->setCacheFilename(cacheArray); 358 env->ReleaseStringUTFChars(diskCachePath, cacheArray); 359} 360 361// ---------------------------------------------------------------------------- 362// JNI Glue 363// ---------------------------------------------------------------------------- 364 365const char* const kClassPathName = "android/view/ThreadedRenderer"; 366 367static JNINativeMethod gMethods[] = { 368#ifdef USE_OPENGL_RENDERER 369 { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V", (void*) android_view_ThreadedRenderer_setAtlas }, 370 { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode }, 371 { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy }, 372 { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy }, 373 { "nSetFrameInterval", "(JJ)V", (void*) android_view_ThreadedRenderer_setFrameInterval }, 374 { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties }, 375 { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize }, 376 { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface }, 377 { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface }, 378 { "nSetup", "(JIIFFFF)V", (void*) android_view_ThreadedRenderer_setup }, 379 { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque }, 380 { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, 381 { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface }, 382 { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, 383 { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext }, 384 { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer }, 385 { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer }, 386 { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto }, 387 { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate }, 388 { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate }, 389 { "nFlushCaches", "(JI)V", (void*) android_view_ThreadedRenderer_flushCaches }, 390 { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence }, 391 { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending }, 392 { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo }, 393#endif 394 { "setupShadersDiskCache", "(Ljava/lang/String;)V", 395 (void*) android_view_ThreadedRenderer_setupShadersDiskCache }, 396}; 397 398int register_android_view_ThreadedRenderer(JNIEnv* env) { 399#ifdef USE_OPENGL_RENDERER 400 jclass cls = env->FindClass("java/lang/Runnable"); 401 gRunnableMethod = env->GetMethodID(cls, "run", "()V"); 402 env->DeleteLocalRef(cls); 403#endif 404 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 405} 406 407}; // namespace android 408