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