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 "OpenGLRenderer"
18
19#include "jni.h"
20#include "GraphicsJNI.h"
21#include <nativehelper/JNIHelp.h>
22
23#include <android_runtime/AndroidRuntime.h>
24
25#include <utils/Looper.h>
26#include <cutils/properties.h>
27
28#include <SkBitmap.h>
29#include <SkRegion.h>
30
31#include <Rect.h>
32#include <RenderNode.h>
33#include <CanvasProperty.h>
34#include <hwui/Canvas.h>
35#include <hwui/Paint.h>
36#include <renderthread/RenderProxy.h>
37
38#include "core_jni_helpers.h"
39
40namespace android {
41
42using namespace uirenderer;
43
44jmethodID gRunnableMethodId;
45
46static JNIEnv* jnienv(JavaVM* vm) {
47    JNIEnv* env;
48    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
49        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
50    }
51    return env;
52}
53
54class InvokeRunnableMessage : public MessageHandler {
55public:
56    InvokeRunnableMessage(JNIEnv* env, jobject runnable) {
57        mRunnable = env->NewGlobalRef(runnable);
58        env->GetJavaVM(&mVm);
59    }
60
61    virtual ~InvokeRunnableMessage() {
62        jnienv(mVm)->DeleteGlobalRef(mRunnable);
63    }
64
65    virtual void handleMessage(const Message&) {
66        jnienv(mVm)->CallVoidMethod(mRunnable, gRunnableMethodId);
67    }
68
69private:
70    JavaVM* mVm;
71    jobject mRunnable;
72};
73
74class GlFunctorReleasedCallbackBridge : public GlFunctorLifecycleListener {
75public:
76    GlFunctorReleasedCallbackBridge(JNIEnv* env, jobject javaCallback) {
77        mLooper = Looper::getForThread();
78        mMessage = new InvokeRunnableMessage(env, javaCallback);
79    }
80
81    virtual void onGlFunctorReleased(Functor* functor) override {
82        mLooper->sendMessage(mMessage, 0);
83    }
84
85private:
86    sp<Looper> mLooper;
87    sp<InvokeRunnableMessage> mMessage;
88};
89
90
91// ---------------- Regular JNI -----------------------------
92
93static void
94android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
95    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
96    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
97}
98
99
100// ---------------- @FastNative -----------------------------
101
102static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
103        jlong canvasPtr, jlong functorPtr, jobject releasedCallback) {
104    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
105    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
106    sp<GlFunctorReleasedCallbackBridge> bridge;
107    if (releasedCallback) {
108        bridge = new GlFunctorReleasedCallbackBridge(env, releasedCallback);
109    }
110    canvas->callDrawGLFunction(functor, bridge.get());
111}
112
113
114// ---------------- @CriticalNative -------------------------
115
116static jlong android_view_DisplayListCanvas_createDisplayListCanvas(jlong renderNodePtr,
117        jint width, jint height) {
118    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
119    return reinterpret_cast<jlong>(Canvas::create_recording_canvas(width, height, renderNode));
120}
121
122static void android_view_DisplayListCanvas_resetDisplayListCanvas(jlong canvasPtr,
123        jlong renderNodePtr, jint width, jint height) {
124    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
125    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
126    canvas->resetRecording(width, height, renderNode);
127}
128
129static jint android_view_DisplayListCanvas_getMaxTextureWidth() {
130    if (!Caches::hasInstance()) {
131        android::uirenderer::renderthread::RenderProxy::staticFence();
132    }
133    return Caches::getInstance().maxTextureSize;
134}
135
136static jint android_view_DisplayListCanvas_getMaxTextureHeight() {
137    if (!Caches::hasInstance()) {
138        android::uirenderer::renderthread::RenderProxy::staticFence();
139    }
140    return Caches::getInstance().maxTextureSize;
141}
142
143static void android_view_DisplayListCanvas_insertReorderBarrier(jlong canvasPtr,
144        jboolean reorderEnable) {
145    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
146    canvas->insertReorderBarrier(reorderEnable);
147}
148
149static jlong android_view_DisplayListCanvas_finishRecording(jlong canvasPtr) {
150    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
151    return reinterpret_cast<jlong>(canvas->finishRecording());
152}
153
154static void android_view_DisplayListCanvas_drawRenderNode(jlong canvasPtr, jlong renderNodePtr) {
155    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
156    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
157    canvas->drawRenderNode(renderNode);
158}
159
160static void android_view_DisplayListCanvas_drawLayer(jlong canvasPtr, jlong layerPtr) {
161    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
162    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
163    canvas->drawLayer(layer);
164}
165
166static void android_view_DisplayListCanvas_drawRoundRectProps(jlong canvasPtr,
167        jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr, jlong bottomPropPtr,
168        jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
169    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
170    CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
171    CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
172    CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
173    CanvasPropertyPrimitive* bottomProp = reinterpret_cast<CanvasPropertyPrimitive*>(bottomPropPtr);
174    CanvasPropertyPrimitive* rxProp = reinterpret_cast<CanvasPropertyPrimitive*>(rxPropPtr);
175    CanvasPropertyPrimitive* ryProp = reinterpret_cast<CanvasPropertyPrimitive*>(ryPropPtr);
176    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
177    canvas->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
178}
179
180static void android_view_DisplayListCanvas_drawCircleProps(jlong canvasPtr,
181        jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
182    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
183    CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
184    CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
185    CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
186    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
187    canvas->drawCircle(xProp, yProp, radiusProp, paintProp);
188}
189
190// ----------------------------------------------------------------------------
191// JNI Glue
192// ----------------------------------------------------------------------------
193
194const char* const kClassPathName = "android/view/DisplayListCanvas";
195
196static JNINativeMethod gMethods[] = {
197
198    // ------------ @FastNative ------------------
199
200    { "nCallDrawGLFunction", "(JJLjava/lang/Runnable;)V",
201            (void*) android_view_DisplayListCanvas_callDrawGLFunction },
202
203    // ------------ @CriticalNative --------------
204    { "nCreateDisplayListCanvas", "(JII)J",     (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
205    { "nResetDisplayListCanvas",  "(JJII)V",    (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
206    { "nGetMaximumTextureWidth",  "()I",        (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
207    { "nGetMaximumTextureHeight", "()I",        (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
208    { "nInsertReorderBarrier",    "(JZ)V",      (void*) android_view_DisplayListCanvas_insertReorderBarrier },
209    { "nFinishRecording",         "(J)J",       (void*) android_view_DisplayListCanvas_finishRecording },
210    { "nDrawRenderNode",          "(JJ)V",      (void*) android_view_DisplayListCanvas_drawRenderNode },
211    { "nDrawLayer",               "(JJ)V",      (void*) android_view_DisplayListCanvas_drawLayer },
212    { "nDrawCircle",              "(JJJJJ)V",   (void*) android_view_DisplayListCanvas_drawCircleProps },
213    { "nDrawRoundRect",           "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps },
214};
215
216static JNINativeMethod gActivityThreadMethods[] = {
217        // ------------ Regular JNI ------------------
218    { "nDumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
219                                               (void*) android_app_ActivityThread_dumpGraphics }
220};
221
222int register_android_view_DisplayListCanvas(JNIEnv* env) {
223    jclass runnableClass = FindClassOrDie(env, "java/lang/Runnable");
224    gRunnableMethodId = GetMethodIDOrDie(env, runnableClass, "run", "()V");
225
226    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
227}
228
229int register_android_app_ActivityThread(JNIEnv* env) {
230    return RegisterMethodsOrDie(env, "android/app/ActivityThread",
231            gActivityThreadMethods, NELEM(gActivityThreadMethods));
232}
233
234};
235