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// Setup
92// ----------------------------------------------------------------------------
93
94static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
95        jlong canvasPtr, jboolean reorderEnable) {
96    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
97    canvas->insertReorderBarrier(reorderEnable);
98}
99
100// ----------------------------------------------------------------------------
101// Functor
102// ----------------------------------------------------------------------------
103
104static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
105        jlong canvasPtr, jlong functorPtr, jobject releasedCallback) {
106    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
107    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
108    sp<GlFunctorReleasedCallbackBridge> bridge;
109    if (releasedCallback) {
110        bridge = new GlFunctorReleasedCallbackBridge(env, releasedCallback);
111    }
112    canvas->callDrawGLFunction(functor, bridge.get());
113}
114
115// ----------------------------------------------------------------------------
116// Misc
117// ----------------------------------------------------------------------------
118
119static jint android_view_DisplayListCanvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
120    if (!Caches::hasInstance()) {
121        android::uirenderer::renderthread::RenderProxy::staticFence();
122    }
123    return Caches::getInstance().maxTextureSize;
124}
125
126static jint android_view_DisplayListCanvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
127    if (!Caches::hasInstance()) {
128        android::uirenderer::renderthread::RenderProxy::staticFence();
129    }
130    return Caches::getInstance().maxTextureSize;
131}
132
133// ----------------------------------------------------------------------------
134// Drawing
135// ----------------------------------------------------------------------------
136
137static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
138        jlong canvasPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
139        jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
140    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
141    CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
142    CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
143    CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
144    CanvasPropertyPrimitive* bottomProp = reinterpret_cast<CanvasPropertyPrimitive*>(bottomPropPtr);
145    CanvasPropertyPrimitive* rxProp = reinterpret_cast<CanvasPropertyPrimitive*>(rxPropPtr);
146    CanvasPropertyPrimitive* ryProp = reinterpret_cast<CanvasPropertyPrimitive*>(ryPropPtr);
147    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
148    canvas->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
149}
150
151static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
152        jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
153    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
154    CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
155    CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
156    CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
157    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
158    canvas->drawCircle(xProp, yProp, radiusProp, paintProp);
159}
160
161// ----------------------------------------------------------------------------
162// Display lists
163// ----------------------------------------------------------------------------
164
165static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
166        jobject clazz, jlong canvasPtr) {
167    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
168    return reinterpret_cast<jlong>(canvas->finishRecording());
169}
170
171static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz,
172        jint width, jint height) {
173    return reinterpret_cast<jlong>(Canvas::create_recording_canvas(width, height));
174}
175
176static void android_view_DisplayListCanvas_resetDisplayListCanvas(JNIEnv* env, jobject clazz,
177        jlong canvasPtr, jint width, jint height) {
178    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
179    canvas->resetRecording(width, height);
180}
181
182
183static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
184        jobject clazz, jlong canvasPtr, jlong renderNodePtr) {
185    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
186    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
187    canvas->drawRenderNode(renderNode);
188}
189
190// ----------------------------------------------------------------------------
191// Layers
192// ----------------------------------------------------------------------------
193
194static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
195        jlong canvasPtr, jlong layerPtr) {
196    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
197    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
198    canvas->drawLayer(layer);
199}
200
201// ----------------------------------------------------------------------------
202// Common
203// ----------------------------------------------------------------------------
204
205static jboolean android_view_DisplayListCanvas_isAvailable(JNIEnv* env, jobject clazz) {
206    char prop[PROPERTY_VALUE_MAX];
207    if (property_get("ro.kernel.qemu", prop, NULL) == 0) {
208        // not in the emulator
209        return JNI_TRUE;
210    }
211    // In the emulator this property will be set > 0 when OpenGL ES 2.0 is
212    // enabled, 0 otherwise. On old emulator versions it will be undefined.
213    property_get("qemu.gles", prop, "0");
214    return atoi(prop) > 0 ? JNI_TRUE : JNI_FALSE;
215}
216
217// ----------------------------------------------------------------------------
218// Logging
219// ----------------------------------------------------------------------------
220
221static void
222android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
223    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
224    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
225}
226
227// ----------------------------------------------------------------------------
228// JNI Glue
229// ----------------------------------------------------------------------------
230
231const char* const kClassPathName = "android/view/DisplayListCanvas";
232
233static JNINativeMethod gMethods[] = {
234    { "nIsAvailable",       "!()Z",             (void*) android_view_DisplayListCanvas_isAvailable },
235    { "nInsertReorderBarrier","!(JZ)V",         (void*) android_view_DisplayListCanvas_insertReorderBarrier },
236
237    { "nCallDrawGLFunction", "!(JJLjava/lang/Runnable;)V",
238            (void*) android_view_DisplayListCanvas_callDrawGLFunction },
239
240    { "nDrawRoundRect",     "!(JJJJJJJJ)V",     (void*) android_view_DisplayListCanvas_drawRoundRectProps },
241    { "nDrawCircle",        "!(JJJJJ)V",        (void*) android_view_DisplayListCanvas_drawCircleProps },
242
243    { "nFinishRecording",   "!(J)J",            (void*) android_view_DisplayListCanvas_finishRecording },
244    { "nDrawRenderNode",    "!(JJ)V",           (void*) android_view_DisplayListCanvas_drawRenderNode },
245
246    { "nCreateDisplayListCanvas", "!(II)J",     (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
247    { "nResetDisplayListCanvas", "!(JII)V",     (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
248
249    { "nDrawLayer",               "!(JJ)V",     (void*) android_view_DisplayListCanvas_drawLayer },
250
251    { "nGetMaximumTextureWidth",  "!()I",       (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
252    { "nGetMaximumTextureHeight", "!()I",       (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
253};
254
255static JNINativeMethod gActivityThreadMethods[] = {
256    { "dumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
257                                               (void*) android_app_ActivityThread_dumpGraphics }
258};
259
260int register_android_view_DisplayListCanvas(JNIEnv* env) {
261    jclass runnableClass = FindClassOrDie(env, "java/lang/Runnable");
262    gRunnableMethodId = GetMethodIDOrDie(env, runnableClass, "run", "()V");
263
264    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
265}
266
267int register_android_app_ActivityThread(JNIEnv* env) {
268    return RegisterMethodsOrDie(env, "android/app/ActivityThread",
269            gActivityThreadMethods, NELEM(gActivityThreadMethods));
270}
271
272};
273