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 // ----------------------------------------------------------------------------
51
52 namespace android {
53
54 static const char* const OutOfResourcesException =
55 "android/view/Surface$OutOfResourcesException";
56
57 static struct {
58 jclass clazz;
59 jfieldID mNativeObject;
60 jfieldID mLock;
61 jmethodID ctor;
62 } gSurfaceClassInfo;
63
64 static struct {
65 jfieldID left;
66 jfieldID top;
67 jfieldID right;
68 jfieldID bottom;
69 } gRectClassInfo;
70
71 static struct {
72 jfieldID mFinalizer;
73 jfieldID mNativeCanvas;
74 jfieldID mSurfaceFormat;
75 } gCanvasClassInfo;
76
77 static struct {
78 jfieldID mNativeCanvas;
79 } gCanvasFinalizerClassInfo;
80
81 // ----------------------------------------------------------------------------
82
83 // this is just a pointer we use to pass to inc/decStrong
84 static const void *sRefBaseOwner;
85
android_view_Surface_isInstanceOf(JNIEnv * env,jobject obj)86 bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
87 return env->IsInstanceOf(obj, gSurfaceClassInfo.clazz);
88 }
89
android_view_Surface_getNativeWindow(JNIEnv * env,jobject surfaceObj)90 sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
91 return android_view_Surface_getSurface(env, surfaceObj);
92 }
93
android_view_Surface_getSurface(JNIEnv * env,jobject surfaceObj)94 sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
95 sp<Surface> sur;
96 jobject lock = env->GetObjectField(surfaceObj,
97 gSurfaceClassInfo.mLock);
98 if (env->MonitorEnter(lock) == JNI_OK) {
99 sur = reinterpret_cast<Surface *>(
100 env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeObject));
101 env->MonitorExit(lock);
102 }
103 return sur;
104 }
105
android_view_Surface_createFromIGraphicBufferProducer(JNIEnv * env,const sp<IGraphicBufferProducer> & bufferProducer)106 jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
107 const sp<IGraphicBufferProducer>& bufferProducer) {
108 if (bufferProducer == NULL) {
109 return NULL;
110 }
111
112 sp<Surface> surface(new Surface(bufferProducer, true));
113 if (surface == NULL) {
114 return NULL;
115 }
116
117 jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor, surface.get());
118 if (surfaceObj == NULL) {
119 if (env->ExceptionCheck()) {
120 ALOGE("Could not create instance of Surface from IGraphicBufferProducer.");
121 LOGE_EX(env);
122 env->ExceptionClear();
123 }
124 return NULL;
125 }
126 surface->incStrong(&sRefBaseOwner);
127 return surfaceObj;
128 }
129
130 // ----------------------------------------------------------------------------
131
isSurfaceValid(const sp<Surface> & sur)132 static inline bool isSurfaceValid(const sp<Surface>& sur) {
133 return Surface::isValid(sur);
134 }
135
136 // ----------------------------------------------------------------------------
137
nativeCreateFromSurfaceTexture(JNIEnv * env,jclass clazz,jobject surfaceTextureObj)138 static jint nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz,
139 jobject surfaceTextureObj) {
140 sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj));
141 if (producer == NULL) {
142 jniThrowException(env, "java/lang/IllegalArgumentException",
143 "SurfaceTexture has already been released");
144 return 0;
145 }
146
147 sp<Surface> surface(new Surface(producer, true));
148 if (surface == NULL) {
149 jniThrowException(env, OutOfResourcesException, NULL);
150 return 0;
151 }
152
153 surface->incStrong(&sRefBaseOwner);
154 return int(surface.get());
155 }
156
nativeRelease(JNIEnv * env,jclass clazz,jint nativeObject)157 static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) {
158 sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
159 sur->decStrong(&sRefBaseOwner);
160 }
161
nativeIsValid(JNIEnv * env,jclass clazz,jint nativeObject)162 static jboolean nativeIsValid(JNIEnv* env, jclass clazz, jint nativeObject) {
163 sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
164 return isSurfaceValid(sur) ? JNI_TRUE : JNI_FALSE;
165 }
166
nativeIsConsumerRunningBehind(JNIEnv * env,jclass clazz,jint nativeObject)167 static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jint nativeObject) {
168 sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
169 if (!isSurfaceValid(sur)) {
170 doThrowIAE(env);
171 return JNI_FALSE;
172 }
173 int value = 0;
174 ANativeWindow* anw = static_cast<ANativeWindow*>(sur.get());
175 anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value);
176 return value;
177 }
178
convertPixelFormat(PixelFormat format)179 static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
180 /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
181 we can map to SkBitmap::kARGB_8888_Config, and optionally call
182 bitmap.setAlphaType(kOpaque_SkAlphaType) on the resulting SkBitmap
183 (as an accelerator)
184 */
185 switch (format) {
186 case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config;
187 case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config;
188 case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config;
189 default: return SkBitmap::kNo_Config;
190 }
191 }
192
swapCanvasPtr(JNIEnv * env,jobject canvasObj,SkCanvas * newCanvas)193 static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
194 jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
195 SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
196 env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
197 env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas);
198 env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas);
199 SkSafeUnref(previousCanvas);
200 }
201
nativeLockCanvas(JNIEnv * env,jclass clazz,jint nativeObject,jobject canvasObj,jobject dirtyRectObj)202 static jint nativeLockCanvas(JNIEnv* env, jclass clazz,
203 jint nativeObject, jobject canvasObj, jobject dirtyRectObj) {
204 sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
205
206 if (!isSurfaceValid(surface)) {
207 doThrowIAE(env);
208 return 0;
209 }
210
211 Rect dirtyRect;
212 Rect* dirtyRectPtr = NULL;
213
214 if (dirtyRectObj) {
215 dirtyRect.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
216 dirtyRect.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
217 dirtyRect.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
218 dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
219 dirtyRectPtr = &dirtyRect;
220 }
221
222 ANativeWindow_Buffer outBuffer;
223 status_t err = surface->lock(&outBuffer, dirtyRectPtr);
224 if (err < 0) {
225 const char* const exception = (err == NO_MEMORY) ?
226 OutOfResourcesException :
227 "java/lang/IllegalArgumentException";
228 jniThrowException(env, exception, NULL);
229 return 0;
230 }
231
232 // Associate a SkCanvas object to this surface
233 env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format);
234
235 SkBitmap bitmap;
236 ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
237 bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr);
238 if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
239 bitmap.setAlphaType(kOpaque_SkAlphaType);
240 }
241 if (outBuffer.width > 0 && outBuffer.height > 0) {
242 bitmap.setPixels(outBuffer.bits);
243 } else {
244 // be safe with an empty bitmap.
245 bitmap.setPixels(NULL);
246 }
247
248 SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
249 swapCanvasPtr(env, canvasObj, nativeCanvas);
250
251 if (dirtyRectPtr) {
252 nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
253 }
254
255 if (dirtyRectObj) {
256 env->SetIntField(dirtyRectObj, gRectClassInfo.left, dirtyRect.left);
257 env->SetIntField(dirtyRectObj, gRectClassInfo.top, dirtyRect.top);
258 env->SetIntField(dirtyRectObj, gRectClassInfo.right, dirtyRect.right);
259 env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
260 }
261
262 // Create another reference to the surface and return it. This reference
263 // should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,
264 // because the latter could be replaced while the surface is locked.
265 sp<Surface> lockedSurface(surface);
266 lockedSurface->incStrong(&sRefBaseOwner);
267 return (int) lockedSurface.get();
268 }
269
nativeUnlockCanvasAndPost(JNIEnv * env,jclass clazz,jint nativeObject,jobject canvasObj)270 static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
271 jint nativeObject, jobject canvasObj) {
272 sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
273 if (!isSurfaceValid(surface)) {
274 return;
275 }
276
277 // detach the canvas from the surface
278 SkCanvas* nativeCanvas = SkNEW(SkCanvas);
279 swapCanvasPtr(env, canvasObj, nativeCanvas);
280
281 // unlock surface
282 status_t err = surface->unlockAndPost();
283 if (err < 0) {
284 doThrowIAE(env);
285 }
286 }
287
288 // ----------------------------------------------------------------------------
289
nativeCreateFromSurfaceControl(JNIEnv * env,jclass clazz,jint surfaceControlNativeObj)290 static jint nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
291 jint surfaceControlNativeObj) {
292 /*
293 * This is used by the WindowManagerService just after constructing
294 * a Surface and is necessary for returning the Surface reference to
295 * the caller. At this point, we should only have a SurfaceControl.
296 */
297
298 sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
299 sp<Surface> surface(ctrl->getSurface());
300 if (surface != NULL) {
301 surface->incStrong(&sRefBaseOwner);
302 }
303 return reinterpret_cast<jint>(surface.get());
304 }
305
nativeReadFromParcel(JNIEnv * env,jclass clazz,jint nativeObject,jobject parcelObj)306 static jint nativeReadFromParcel(JNIEnv* env, jclass clazz,
307 jint nativeObject, jobject parcelObj) {
308 Parcel* parcel = parcelForJavaObject(env, parcelObj);
309 if (parcel == NULL) {
310 doThrowNPE(env);
311 return 0;
312 }
313
314 sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
315 sp<IBinder> binder(parcel->readStrongBinder());
316
317 // update the Surface only if the underlying IGraphicBufferProducer
318 // has changed.
319 if (self != NULL
320 && (self->getIGraphicBufferProducer()->asBinder() == binder)) {
321 // same IGraphicBufferProducer, return ourselves
322 return int(self.get());
323 }
324
325 sp<Surface> sur;
326 sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
327 if (gbp != NULL) {
328 // we have a new IGraphicBufferProducer, create a new Surface for it
329 sur = new Surface(gbp, true);
330 // and keep a reference before passing to java
331 sur->incStrong(&sRefBaseOwner);
332 }
333
334 if (self != NULL) {
335 // and loose the java reference to ourselves
336 self->decStrong(&sRefBaseOwner);
337 }
338
339 return int(sur.get());
340 }
341
nativeWriteToParcel(JNIEnv * env,jclass clazz,jint nativeObject,jobject parcelObj)342 static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
343 jint nativeObject, jobject parcelObj) {
344 Parcel* parcel = parcelForJavaObject(env, parcelObj);
345 if (parcel == NULL) {
346 doThrowNPE(env);
347 return;
348 }
349 sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
350 parcel->writeStrongBinder( self != 0 ? self->getIGraphicBufferProducer()->asBinder() : NULL);
351 }
352
353 // ----------------------------------------------------------------------------
354
355 static JNINativeMethod gSurfaceMethods[] = {
356 {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)I",
357 (void*)nativeCreateFromSurfaceTexture },
358 {"nativeRelease", "(I)V",
359 (void*)nativeRelease },
360 {"nativeIsValid", "(I)Z",
361 (void*)nativeIsValid },
362 {"nativeIsConsumerRunningBehind", "(I)Z",
363 (void*)nativeIsConsumerRunningBehind },
364 {"nativeLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)I",
365 (void*)nativeLockCanvas },
366 {"nativeUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V",
367 (void*)nativeUnlockCanvasAndPost },
368 {"nativeCreateFromSurfaceControl", "(I)I",
369 (void*)nativeCreateFromSurfaceControl },
370 {"nativeReadFromParcel", "(ILandroid/os/Parcel;)I",
371 (void*)nativeReadFromParcel },
372 {"nativeWriteToParcel", "(ILandroid/os/Parcel;)V",
373 (void*)nativeWriteToParcel },
374 };
375
register_android_view_Surface(JNIEnv * env)376 int register_android_view_Surface(JNIEnv* env)
377 {
378 int err = AndroidRuntime::registerNativeMethods(env, "android/view/Surface",
379 gSurfaceMethods, NELEM(gSurfaceMethods));
380
381 jclass clazz = env->FindClass("android/view/Surface");
382 gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
383 gSurfaceClassInfo.mNativeObject =
384 env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeObject", "I");
385 gSurfaceClassInfo.mLock =
386 env->GetFieldID(gSurfaceClassInfo.clazz, "mLock", "Ljava/lang/Object;");
387 gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(I)V");
388
389 clazz = env->FindClass("android/graphics/Canvas");
390 gCanvasClassInfo.mFinalizer = env->GetFieldID(clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
391 gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
392 gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
393
394 clazz = env->FindClass("android/graphics/Canvas$CanvasFinalizer");
395 gCanvasFinalizerClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
396
397 clazz = env->FindClass("android/graphics/Rect");
398 gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
399 gRectClassInfo.top = env->GetFieldID(clazz, "top", "I");
400 gRectClassInfo.right = env->GetFieldID(clazz, "right", "I");
401 gRectClassInfo.bottom = env->GetFieldID(clazz, "bottom", "I");
402
403 return err;
404 }
405
406 };
407