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 <androidfw/ResourceTypes.h>
26
27#include <cutils/properties.h>
28
29#include <SkBitmap.h>
30#include <SkRegion.h>
31
32#include <DisplayListCanvas.h>
33#include <Rect.h>
34#include <RenderNode.h>
35#include <CanvasProperty.h>
36#include <Paint.h>
37#include <renderthread/RenderProxy.h>
38
39#include "core_jni_helpers.h"
40
41namespace android {
42
43using namespace uirenderer;
44
45static struct {
46    jmethodID set;
47} gRectClassInfo;
48
49// ----------------------------------------------------------------------------
50// Setup
51// ----------------------------------------------------------------------------
52
53static void android_view_DisplayListCanvas_setViewport(JNIEnv* env, jobject clazz,
54        jlong rendererPtr, jint width, jint height) {
55    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
56    renderer->setViewport(width, height);
57}
58
59static void android_view_DisplayListCanvas_setHighContrastText(JNIEnv* env, jobject clazz,
60        jlong rendererPtr, jboolean highContrastText) {
61    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
62    renderer->setHighContrastText(highContrastText);
63}
64
65static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
66        jlong rendererPtr, jboolean reorderEnable) {
67    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
68    renderer->insertReorderBarrier(reorderEnable);
69}
70
71static void android_view_DisplayListCanvas_prepare(JNIEnv* env, jobject clazz,
72        jlong rendererPtr) {
73    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
74    renderer->prepare();
75}
76
77static void android_view_DisplayListCanvas_prepareDirty(JNIEnv* env, jobject clazz,
78        jlong rendererPtr, jint left, jint top, jint right, jint bottom) {
79    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
80    renderer->prepareDirty(left, top, right, bottom);
81}
82
83static void android_view_DisplayListCanvas_finish(JNIEnv* env, jobject clazz,
84        jlong rendererPtr) {
85    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
86    renderer->finish();
87}
88
89// ----------------------------------------------------------------------------
90// Functor
91// ----------------------------------------------------------------------------
92
93static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
94        jlong rendererPtr, jlong functorPtr) {
95    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
96    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
97    renderer->callDrawGLFunction(functor);
98}
99
100// ----------------------------------------------------------------------------
101// Misc
102// ----------------------------------------------------------------------------
103
104static jint android_view_DisplayListCanvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
105    return Caches::getInstance().maxTextureSize;
106}
107
108static jint android_view_DisplayListCanvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
109    return Caches::getInstance().maxTextureSize;
110}
111
112// ----------------------------------------------------------------------------
113// Drawing
114// ----------------------------------------------------------------------------
115
116static void android_view_DisplayListCanvas_drawPatch(JNIEnv* env, jobject clazz,
117        jlong rendererPtr, jobject jbitmap, jlong patchPtr,
118        float left, float top, float right, float bottom, jlong paintPtr) {
119    SkBitmap bitmap;
120    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
121    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
122    Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(patchPtr);
123    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
124    renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
125}
126
127static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
128        jlong rendererPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
129        jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
130    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
131    CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
132    CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
133    CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
134    CanvasPropertyPrimitive* bottomProp = reinterpret_cast<CanvasPropertyPrimitive*>(bottomPropPtr);
135    CanvasPropertyPrimitive* rxProp = reinterpret_cast<CanvasPropertyPrimitive*>(rxPropPtr);
136    CanvasPropertyPrimitive* ryProp = reinterpret_cast<CanvasPropertyPrimitive*>(ryPropPtr);
137    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
138    renderer->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
139}
140
141static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
142        jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
143    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
144    CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
145    CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
146    CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
147    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
148    renderer->drawCircle(xProp, yProp, radiusProp, paintProp);
149}
150
151static void android_view_DisplayListCanvas_drawRegionAsRects(JNIEnv* env, jobject clazz,
152        jlong rendererPtr, jlong regionPtr, jlong paintPtr) {
153    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
154    SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr);
155    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
156    if (paint->getStyle() != Paint::kFill_Style ||
157            (paint->isAntiAlias() && !renderer->isCurrentTransformSimple())) {
158        SkRegion::Iterator it(*region);
159        while (!it.done()) {
160            const SkIRect& r = it.rect();
161            renderer->drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, *paint);
162            it.next();
163        }
164    } else {
165        int count = 0;
166        Vector<float> rects;
167        SkRegion::Iterator it(*region);
168        while (!it.done()) {
169            const SkIRect& r = it.rect();
170            rects.push(r.fLeft);
171            rects.push(r.fTop);
172            rects.push(r.fRight);
173            rects.push(r.fBottom);
174            count += 4;
175            it.next();
176        }
177        renderer->drawRects(rects.array(), count, paint);
178    }
179}
180
181// ----------------------------------------------------------------------------
182// Display lists
183// ----------------------------------------------------------------------------
184
185static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
186        jobject clazz, jlong rendererPtr) {
187    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
188    return reinterpret_cast<jlong>(renderer->finishRecording());
189}
190
191static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz) {
192    return reinterpret_cast<jlong>(new DisplayListCanvas);
193}
194
195static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
196        jobject clazz, jlong rendererPtr, jlong renderNodePtr) {
197    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
198    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
199    renderer->drawRenderNode(renderNode);
200}
201
202// ----------------------------------------------------------------------------
203// Layers
204// ----------------------------------------------------------------------------
205
206static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
207        jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
208    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
209    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
210    renderer->drawLayer(layer, x, y);
211}
212
213// ----------------------------------------------------------------------------
214// Common
215// ----------------------------------------------------------------------------
216
217static jboolean android_view_DisplayListCanvas_isAvailable(JNIEnv* env, jobject clazz) {
218    char prop[PROPERTY_VALUE_MAX];
219    if (property_get("ro.kernel.qemu", prop, NULL) == 0) {
220        // not in the emulator
221        return JNI_TRUE;
222    }
223    // In the emulator this property will be set to 1 when hardware GLES is
224    // enabled, 0 otherwise. On old emulator versions it will be undefined.
225    property_get("ro.kernel.qemu.gles", prop, "0");
226    return atoi(prop) == 1 ? JNI_TRUE : JNI_FALSE;
227}
228
229// ----------------------------------------------------------------------------
230// Logging
231// ----------------------------------------------------------------------------
232
233static void
234android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
235    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
236    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
237}
238
239// ----------------------------------------------------------------------------
240// JNI Glue
241// ----------------------------------------------------------------------------
242
243const char* const kClassPathName = "android/view/DisplayListCanvas";
244
245static JNINativeMethod gMethods[] = {
246    { "nIsAvailable",       "()Z",             (void*) android_view_DisplayListCanvas_isAvailable },
247    { "nSetViewport",       "(JII)V",          (void*) android_view_DisplayListCanvas_setViewport },
248    { "nSetHighContrastText","(JZ)V",          (void*) android_view_DisplayListCanvas_setHighContrastText },
249    { "nInsertReorderBarrier","(JZ)V",         (void*) android_view_DisplayListCanvas_insertReorderBarrier },
250    { "nPrepare",           "(J)V",            (void*) android_view_DisplayListCanvas_prepare },
251    { "nPrepareDirty",      "(JIIII)V",        (void*) android_view_DisplayListCanvas_prepareDirty },
252    { "nFinish",            "(J)V",            (void*) android_view_DisplayListCanvas_finish },
253
254    { "nCallDrawGLFunction", "(JJ)V",          (void*) android_view_DisplayListCanvas_callDrawGLFunction },
255
256    { "nDrawPatch",         "(JLandroid/graphics/Bitmap;JFFFFJ)V",     (void*) android_view_DisplayListCanvas_drawPatch },
257
258    { "nDrawRects",         "(JJJ)V",          (void*) android_view_DisplayListCanvas_drawRegionAsRects },
259    { "nDrawRoundRect",     "(JJJJJJJJ)V",     (void*) android_view_DisplayListCanvas_drawRoundRectProps },
260    { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_DisplayListCanvas_drawCircleProps },
261
262    { "nFinishRecording",   "(J)J",            (void*) android_view_DisplayListCanvas_finishRecording },
263    { "nDrawRenderNode",    "(JJ)V",           (void*) android_view_DisplayListCanvas_drawRenderNode },
264
265    { "nCreateDisplayListCanvas", "()J",     (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
266
267    { "nDrawLayer",               "(JJFF)V",   (void*) android_view_DisplayListCanvas_drawLayer },
268
269    { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
270    { "nGetMaximumTextureHeight", "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
271};
272
273static JNINativeMethod gActivityThreadMethods[] = {
274    { "dumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
275                                               (void*) android_app_ActivityThread_dumpGraphics }
276};
277
278int register_android_view_DisplayListCanvas(JNIEnv* env) {
279    jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
280    gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
281
282    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
283}
284
285int register_android_app_ActivityThread(JNIEnv* env) {
286    return RegisterMethodsOrDie(env, "android/app/ActivityThread",
287            gActivityThreadMethods, NELEM(gActivityThreadMethods));
288}
289
290};
291