OSDN Git Service

DO NOT MERGE Backport of limited jank-tracking metrics
[android-x86/frameworks-base.git] / core / jni / android_view_Surface.cpp
1 /*
2  * Copyright (C) 2007 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 "Surface"
18
19 #include <stdio.h>
20
21 #include "jni.h"
22 #include "JNIHelp.h"
23 #include "android_os_Parcel.h"
24 #include "android/graphics/GraphicsJNI.h"
25
26 #include <android_runtime/AndroidRuntime.h>
27 #include <android_runtime/android_view_Surface.h>
28 #include <android_runtime/android_graphics_SurfaceTexture.h>
29 #include <android_runtime/Log.h>
30
31 #include <binder/Parcel.h>
32
33 #include <gui/Surface.h>
34 #include <gui/SurfaceControl.h>
35 #include <gui/GLConsumer.h>
36
37 #include <ui/Rect.h>
38 #include <ui/Region.h>
39
40 #include <SkCanvas.h>
41 #include <SkBitmap.h>
42 #include <SkImage.h>
43 #include <SkRegion.h>
44
45 #include <utils/misc.h>
46 #include <utils/Log.h>
47
48 #include <ScopedUtfChars.h>
49
50 #include <AnimationContext.h>
51 #include <DisplayListRenderer.h>
52 #include <FrameInfo.h>
53 #include <RenderNode.h>
54 #include <renderthread/RenderProxy.h>
55
56 // ----------------------------------------------------------------------------
57
58 namespace android {
59
60 static const char* const OutOfResourcesException =
61     "android/view/Surface$OutOfResourcesException";
62
63 static struct {
64     jclass clazz;
65     jfieldID mNativeObject;
66     jfieldID mLock;
67     jmethodID ctor;
68 } gSurfaceClassInfo;
69
70 static struct {
71     jfieldID left;
72     jfieldID top;
73     jfieldID right;
74     jfieldID bottom;
75 } gRectClassInfo;
76
77 static struct {
78     jfieldID mSurfaceFormat;
79     jmethodID setNativeBitmap;
80 } gCanvasClassInfo;
81
82 // ----------------------------------------------------------------------------
83
84 // this is just a pointer we use to pass to inc/decStrong
85 static const void *sRefBaseOwner;
86
87 bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
88     return env->IsInstanceOf(obj, gSurfaceClassInfo.clazz);
89 }
90
91 sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
92     return android_view_Surface_getSurface(env, surfaceObj);
93 }
94
95 sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
96     sp<Surface> sur;
97     jobject lock = env->GetObjectField(surfaceObj,
98             gSurfaceClassInfo.mLock);
99     if (env->MonitorEnter(lock) == JNI_OK) {
100         sur = reinterpret_cast<Surface *>(
101                 env->GetLongField(surfaceObj, gSurfaceClassInfo.mNativeObject));
102         env->MonitorExit(lock);
103     }
104     env->DeleteLocalRef(lock);
105     return sur;
106 }
107
108 jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
109         const sp<IGraphicBufferProducer>& bufferProducer) {
110     if (bufferProducer == NULL) {
111         return NULL;
112     }
113
114     sp<Surface> surface(new Surface(bufferProducer, true));
115     if (surface == NULL) {
116         return NULL;
117     }
118
119     jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz,
120             gSurfaceClassInfo.ctor, (jlong)surface.get());
121     if (surfaceObj == NULL) {
122         if (env->ExceptionCheck()) {
123             ALOGE("Could not create instance of Surface from IGraphicBufferProducer.");
124             LOGE_EX(env);
125             env->ExceptionClear();
126         }
127         return NULL;
128     }
129     surface->incStrong(&sRefBaseOwner);
130     return surfaceObj;
131 }
132
133 // ----------------------------------------------------------------------------
134
135 static inline bool isSurfaceValid(const sp<Surface>& sur) {
136     return Surface::isValid(sur);
137 }
138
139 // ----------------------------------------------------------------------------
140
141 static jlong nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz,
142         jobject surfaceTextureObj) {
143     sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj));
144     if (producer == NULL) {
145         jniThrowException(env, "java/lang/IllegalArgumentException",
146                 "SurfaceTexture has already been released");
147         return 0;
148     }
149
150     sp<Surface> surface(new Surface(producer, true));
151     if (surface == NULL) {
152         jniThrowException(env, OutOfResourcesException, NULL);
153         return 0;
154     }
155
156     surface->incStrong(&sRefBaseOwner);
157     return jlong(surface.get());
158 }
159
160 static void nativeRelease(JNIEnv* env, jclass clazz, jlong nativeObject) {
161     sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
162     sur->decStrong(&sRefBaseOwner);
163 }
164
165 static jboolean nativeIsValid(JNIEnv* env, jclass clazz, jlong nativeObject) {
166     sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
167     return isSurfaceValid(sur) ? JNI_TRUE : JNI_FALSE;
168 }
169
170 static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jlong nativeObject) {
171     sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
172     if (!isSurfaceValid(sur)) {
173         doThrowIAE(env);
174         return JNI_FALSE;
175     }
176     int value = 0;
177     ANativeWindow* anw = static_cast<ANativeWindow*>(sur.get());
178     anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value);
179     return value;
180 }
181
182 static inline SkColorType convertPixelFormat(PixelFormat format) {
183     /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
184         we can map to kN32_SkColorType, and optionally call
185         bitmap.setAlphaType(kOpaque_SkAlphaType) on the resulting SkBitmap
186         (as an accelerator)
187     */
188     switch (format) {
189     case PIXEL_FORMAT_RGBX_8888:    return kN32_SkColorType;
190     case PIXEL_FORMAT_RGBA_8888:    return kN32_SkColorType;
191     case PIXEL_FORMAT_RGB_565:      return kRGB_565_SkColorType;
192     default:                        return kUnknown_SkColorType;
193     }
194 }
195
196 static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
197         jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
198     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
199
200     if (!isSurfaceValid(surface)) {
201         doThrowIAE(env);
202         return 0;
203     }
204
205     Rect dirtyRect;
206     Rect* dirtyRectPtr = NULL;
207
208     if (dirtyRectObj) {
209         dirtyRect.left   = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
210         dirtyRect.top    = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
211         dirtyRect.right  = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
212         dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
213         dirtyRectPtr = &dirtyRect;
214     }
215
216     ANativeWindow_Buffer outBuffer;
217     status_t err = surface->lock(&outBuffer, dirtyRectPtr);
218     if (err < 0) {
219         const char* const exception = (err == NO_MEMORY) ?
220                 OutOfResourcesException :
221                 "java/lang/IllegalArgumentException";
222         jniThrowException(env, exception, NULL);
223         return 0;
224     }
225
226     // Associate a SkCanvas object to this surface
227     env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format);
228
229     SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
230                                          convertPixelFormat(outBuffer.format),
231                                          kPremul_SkAlphaType);
232     if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
233         info.fAlphaType = kOpaque_SkAlphaType;
234     }
235
236     SkBitmap bitmap;
237     ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
238     bitmap.setInfo(info, bpr);
239     if (outBuffer.width > 0 && outBuffer.height > 0) {
240         bitmap.setPixels(outBuffer.bits);
241     } else {
242         // be safe with an empty bitmap.
243         bitmap.setPixels(NULL);
244     }
245
246     env->CallVoidMethod(canvasObj, gCanvasClassInfo.setNativeBitmap,
247                         reinterpret_cast<jlong>(&bitmap));
248
249     if (dirtyRectPtr) {
250         SkCanvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
251         nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
252     }
253
254     if (dirtyRectObj) {
255         env->SetIntField(dirtyRectObj, gRectClassInfo.left,   dirtyRect.left);
256         env->SetIntField(dirtyRectObj, gRectClassInfo.top,    dirtyRect.top);
257         env->SetIntField(dirtyRectObj, gRectClassInfo.right,  dirtyRect.right);
258         env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
259     }
260
261     // Create another reference to the surface and return it.  This reference
262     // should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,
263     // because the latter could be replaced while the surface is locked.
264     sp<Surface> lockedSurface(surface);
265     lockedSurface->incStrong(&sRefBaseOwner);
266     return (jlong) lockedSurface.get();
267 }
268
269 static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
270         jlong nativeObject, jobject canvasObj) {
271     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
272     if (!isSurfaceValid(surface)) {
273         return;
274     }
275
276     // detach the canvas from the surface
277     env->CallVoidMethod(canvasObj, gCanvasClassInfo.setNativeBitmap, (jlong)0);
278
279     // unlock surface
280     status_t err = surface->unlockAndPost();
281     if (err < 0) {
282         doThrowIAE(env);
283     }
284 }
285
286 static void nativeAllocateBuffers(JNIEnv* /* env */ , jclass /* clazz */,
287         jlong nativeObject) {
288     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
289     if (!isSurfaceValid(surface)) {
290         return;
291     }
292
293     surface->allocateBuffers();
294 }
295
296 // ----------------------------------------------------------------------------
297
298 static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
299         jlong surfaceControlNativeObj) {
300     /*
301      * This is used by the WindowManagerService just after constructing
302      * a Surface and is necessary for returning the Surface reference to
303      * the caller. At this point, we should only have a SurfaceControl.
304      */
305
306     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
307     sp<Surface> surface(ctrl->getSurface());
308     if (surface != NULL) {
309         surface->incStrong(&sRefBaseOwner);
310     }
311     return reinterpret_cast<jlong>(surface.get());
312 }
313
314 static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
315         jlong nativeObject, jobject parcelObj) {
316     Parcel* parcel = parcelForJavaObject(env, parcelObj);
317     if (parcel == NULL) {
318         doThrowNPE(env);
319         return 0;
320     }
321
322     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
323     sp<IBinder> binder(parcel->readStrongBinder());
324
325     // update the Surface only if the underlying IGraphicBufferProducer
326     // has changed.
327     if (self != NULL
328             && (self->getIGraphicBufferProducer()->asBinder() == binder)) {
329         // same IGraphicBufferProducer, return ourselves
330         return jlong(self.get());
331     }
332
333     sp<Surface> sur;
334     sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
335     if (gbp != NULL) {
336         // we have a new IGraphicBufferProducer, create a new Surface for it
337         sur = new Surface(gbp, true);
338         // and keep a reference before passing to java
339         sur->incStrong(&sRefBaseOwner);
340     }
341
342     if (self != NULL) {
343         // and loose the java reference to ourselves
344         self->decStrong(&sRefBaseOwner);
345     }
346
347     return jlong(sur.get());
348 }
349
350 static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
351         jlong nativeObject, jobject parcelObj) {
352     Parcel* parcel = parcelForJavaObject(env, parcelObj);
353     if (parcel == NULL) {
354         doThrowNPE(env);
355         return;
356     }
357     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
358     parcel->writeStrongBinder( self != 0 ? self->getIGraphicBufferProducer()->asBinder() : NULL);
359 }
360
361 static jint nativeGetWidth(JNIEnv* env, jclass clazz, jlong nativeObject) {
362     Surface* surface = reinterpret_cast<Surface*>(nativeObject);
363     ANativeWindow* anw = static_cast<ANativeWindow*>(surface);
364     int value = 0;
365     anw->query(anw, NATIVE_WINDOW_WIDTH, &value);
366     return value;
367 }
368
369 static jint nativeGetHeight(JNIEnv* env, jclass clazz, jlong nativeObject) {
370     Surface* surface = reinterpret_cast<Surface*>(nativeObject);
371     ANativeWindow* anw = static_cast<ANativeWindow*>(surface);
372     int value = 0;
373     anw->query(anw, NATIVE_WINDOW_HEIGHT, &value);
374     return value;
375 }
376
377 namespace uirenderer {
378
379 using namespace android::uirenderer::renderthread;
380
381 class ContextFactory : public IContextFactory {
382 public:
383     virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
384         return new AnimationContext(clock);
385     }
386 };
387
388 static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr) {
389     RenderNode* rootNode = reinterpret_cast<RenderNode*>(rootNodePtr);
390     sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
391     ContextFactory factory;
392     RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
393     proxy->loadSystemProperties();
394     proxy->setSwapBehavior(kSwap_discardBuffer);
395     proxy->initialize(surface);
396     // Shadows can't be used via this interface, so just set the light source
397     // to all 0s. (and width & height are unused, TODO remove them)
398     proxy->setup(0, 0, (Vector3){0, 0, 0}, 0, 0, 0, 1.0f);
399     return (jlong) proxy;
400 }
401
402 static void setSurface(JNIEnv* env, jclass clazz, jlong rendererPtr, jlong surfacePtr) {
403     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
404     sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
405     proxy->updateSurface(surface);
406 }
407
408 static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) {
409     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
410     nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
411     UiFrameInfoBuilder(proxy->frameInfo())
412             .setVsync(vsync, vsync)
413             .addFlag(FrameInfoFlags::kSurfaceCanvas);
414     proxy->syncAndDrawFrame();
415 }
416
417 static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) {
418     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
419     delete proxy;
420 }
421
422 } // uirenderer
423
424 // ----------------------------------------------------------------------------
425
426 namespace hwui = android::uirenderer;
427
428 static JNINativeMethod gSurfaceMethods[] = {
429     {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J",
430             (void*)nativeCreateFromSurfaceTexture },
431     {"nativeRelease", "(J)V",
432             (void*)nativeRelease },
433     {"nativeIsValid", "(J)Z",
434             (void*)nativeIsValid },
435     {"nativeIsConsumerRunningBehind", "(J)Z",
436             (void*)nativeIsConsumerRunningBehind },
437     {"nativeLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)J",
438             (void*)nativeLockCanvas },
439     {"nativeUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)V",
440             (void*)nativeUnlockCanvasAndPost },
441     {"nativeAllocateBuffers", "(J)V",
442             (void*)nativeAllocateBuffers },
443     {"nativeCreateFromSurfaceControl", "(J)J",
444             (void*)nativeCreateFromSurfaceControl },
445     {"nativeReadFromParcel", "(JLandroid/os/Parcel;)J",
446             (void*)nativeReadFromParcel },
447     {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
448             (void*)nativeWriteToParcel },
449     {"nativeGetWidth", "(J)I", (void*)nativeGetWidth },
450     {"nativeGetHeight", "(J)I", (void*)nativeGetHeight },
451
452     // HWUI context
453     {"nHwuiCreate", "(JJ)J", (void*) hwui::create },
454     {"nHwuiSetSurface", "(JJ)V", (void*) hwui::setSurface },
455     {"nHwuiDraw", "(J)V", (void*) hwui::draw },
456     {"nHwuiDestroy", "(J)V", (void*) hwui::destroy },
457 };
458
459 int register_android_view_Surface(JNIEnv* env)
460 {
461     int err = AndroidRuntime::registerNativeMethods(env, "android/view/Surface",
462             gSurfaceMethods, NELEM(gSurfaceMethods));
463
464     jclass clazz = env->FindClass("android/view/Surface");
465     gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
466     gSurfaceClassInfo.mNativeObject =
467             env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeObject", "J");
468     gSurfaceClassInfo.mLock =
469             env->GetFieldID(gSurfaceClassInfo.clazz, "mLock", "Ljava/lang/Object;");
470     gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(J)V");
471
472     clazz = env->FindClass("android/graphics/Canvas");
473     gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
474     gCanvasClassInfo.setNativeBitmap = env->GetMethodID(clazz, "setNativeBitmap", "(J)V");
475
476     clazz = env->FindClass("android/graphics/Rect");
477     gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
478     gRectClassInfo.top = env->GetFieldID(clazz, "top", "I");
479     gRectClassInfo.right = env->GetFieldID(clazz, "right", "I");
480     gRectClassInfo.bottom = env->GetFieldID(clazz, "bottom", "I");
481
482     return err;
483 }
484
485 };