From 63f56cde6fa0a65cd90e0bfad3d29612ae67d1aa Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 28 Jun 2010 23:42:28 -0700 Subject: [PATCH] Bug 575421 - Improve 2D drawing path on Android, r=vlad --- embedding/android/GeckoApp.java | 4 - embedding/android/GeckoSurfaceView.java | 92 +++++++--------------- gfx/thebes/gfxAndroidPlatform.cpp | 7 +- widget/src/android/AndroidJavaWrappers.cpp | 25 +++--- widget/src/android/AndroidJavaWrappers.h | 7 +- widget/src/android/nsWindow.cpp | 79 ++++++------------- 6 files changed, 72 insertions(+), 142 deletions(-) diff --git a/embedding/android/GeckoApp.java b/embedding/android/GeckoApp.java index 9c0d47755bb..40a81f933fe 100644 --- a/embedding/android/GeckoApp.java +++ b/embedding/android/GeckoApp.java @@ -60,8 +60,6 @@ abstract public class GeckoApp public static GeckoSurfaceView surfaceView; public static GeckoApp mAppContext; - public static boolean useSoftwareDrawing; - void launch() { // unpack files in the components directory @@ -121,8 +119,6 @@ abstract public class GeckoApp new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - useSoftwareDrawing = true; //isInEmulator() == 1; - if (!GeckoAppShell.sGeckoRunning) { // Load our JNI libs; we need to do this before launch() because // setInitialSize will be called even before Gecko is actually up diff --git a/embedding/android/GeckoSurfaceView.java b/embedding/android/GeckoSurfaceView.java index ae0f53ea9a5..fdd86e2eac1 100644 --- a/embedding/android/GeckoSurfaceView.java +++ b/embedding/android/GeckoSurfaceView.java @@ -100,6 +100,13 @@ class GeckoSurfaceView Log.w("GeckoAppJava", "surfaceChanged while mInDrawing is true!"); } + if (width == 0 || height == 0) + mSoftwareBuffer = null; + else if (mSoftwareBuffer == null || + mSoftwareBuffer.capacity() < (width * height * 2) || + mWidth != width || mHeight != height) + mSoftwareBuffer = ByteBuffer.allocateDirect(width * height * 2); + mFormat = format; mWidth = width; mHeight = height; @@ -122,8 +129,6 @@ class GeckoSurfaceView } mSurfaceChanged = true; - - //Log.i("GeckoAppJava", "<< surfaceChanged"); } finally { mSurfaceLock.unlock(); } @@ -137,14 +142,10 @@ class GeckoSurfaceView public void surfaceDestroyed(SurfaceHolder holder) { Log.i("GeckoAppJava", "surface destroyed"); mSurfaceValid = false; + mSoftwareBuffer = null; } public ByteBuffer getSoftwareDrawBuffer() { - //#ifdef DEBUG - if (!mSurfaceLock.isHeldByCurrentThread()) - Log.e("GeckoAppJava", "getSoftwareDrawBuffer called outside of mSurfaceLock!"); - //#endif - return mSoftwareBuffer; } @@ -154,42 +155,8 @@ class GeckoSurfaceView public static final int DRAW_ERROR = 0; public static final int DRAW_GLES_2 = 1; - public static final int DRAW_SOFTWARE = 2; - - int innerBeginDrawing() { - /* - * Software (non-GL) rendering - */ - if (GeckoApp.useSoftwareDrawing) { - if (mWidth != mBufferWidth || - mHeight != mBufferHeight || - mSurfaceChanged) - { - if (mWidth*mHeight != mBufferWidth*mBufferHeight) - mSoftwareBuffer = ByteBuffer.allocateDirect(mWidth*mHeight*4); - - mSoftwareBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888); - - mBufferWidth = mWidth; - mBufferHeight = mHeight; - mSurfaceChanged = false; - } - - mSoftwareCanvas = getHolder().lockCanvas(null); - if (mSoftwareCanvas == null) { - Log.e("GeckoAppJava", "lockCanvas failed! << beginDrawing"); - return DRAW_ERROR; - } - - return DRAW_SOFTWARE; - } - - return DRAW_GLES_2; - } public int beginDrawing() { - //Log.i("GeckoAppJava", ">> beginDrawing"); - if (mInDrawing) { Log.e("GeckoAppJava", "Recursive beginDrawing call!"); return DRAW_ERROR; @@ -214,21 +181,11 @@ class GeckoSurfaceView return DRAW_ERROR; } - // call the inner function to do the work, so we can sanely unlock on error - int result = innerBeginDrawing(); - - if (result == DRAW_ERROR) { - mSurfaceLock.unlock(); - return DRAW_ERROR; - } - mInDrawing = true; - return result; + return DRAW_GLES_2; } public void endDrawing() { - //Log.w("GeckoAppJava", ">> endDrawing"); - if (!mInDrawing) { Log.e("GeckoAppJava", "endDrawing without beginDrawing!"); return; @@ -239,30 +196,36 @@ class GeckoSurfaceView Log.e("GeckoAppJava", "endDrawing with false mSurfaceValid"); return; } - - if (GeckoApp.useSoftwareDrawing) { - if (!mSurfaceChanged) { - mSoftwareBitmap.copyPixelsFromBuffer(mSoftwareBuffer); - mSoftwareCanvas.drawBitmap(mSoftwareBitmap, 0, 0, null); - - getHolder().unlockCanvasAndPost(mSoftwareCanvas); - mSoftwareCanvas = null; - } - } } catch (java.lang.IllegalArgumentException ex) { mSurfaceChanged = true; } finally { mInDrawing = false; - //#ifdef DEBUG if (!mSurfaceLock.isHeldByCurrentThread()) Log.e("GeckoAppJava", "endDrawing while mSurfaceLock not held by current thread!"); - //#endif mSurfaceLock.unlock(); } } + public void draw2D(ByteBuffer buffer) { + Canvas c = getHolder().lockCanvas(); + if (c == null) + return; + if (buffer != mSoftwareBuffer) { + getHolder().unlockCanvasAndPost(c); + return; + } + if (mSoftwareBitmap == null || + mSoftwareBitmap.getHeight() != mHeight || + mSoftwareBitmap.getWidth() != mWidth) { + mSoftwareBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565); + } + mSoftwareBitmap.copyPixelsFromBuffer(mSoftwareBuffer); + c.drawBitmap(mSoftwareBitmap, 0, 0, null); + getHolder().unlockCanvasAndPost(c); + } + @Override public boolean onCheckIsTextEditor () { return false; @@ -347,7 +310,6 @@ class GeckoSurfaceView // Software rendering ByteBuffer mSoftwareBuffer; Bitmap mSoftwareBitmap; - Canvas mSoftwareCanvas; } class GeckoInputConnection diff --git a/gfx/thebes/gfxAndroidPlatform.cpp b/gfx/thebes/gfxAndroidPlatform.cpp index ebe54c1cfc2..f66f5a284ee 100644 --- a/gfx/thebes/gfxAndroidPlatform.cpp +++ b/gfx/thebes/gfxAndroidPlatform.cpp @@ -87,8 +87,11 @@ already_AddRefed gfxAndroidPlatform::CreateOffscreenSurface(const gfxIntSize& size, gfxASurface::gfxImageFormat imageFormat) { - nsRefPtr newSurface = - new gfxImageSurface (size, imageFormat); + nsRefPtr newSurface; + if (imageFormat == gfxImageSurface::ImageFormatRGB24) + newSurface = new gfxImageSurface (size, gfxASurface::ImageFormatRGB16_565); + else + newSurface = new gfxImageSurface (size, imageFormat); return newSurface.forget(); } diff --git a/widget/src/android/AndroidJavaWrappers.cpp b/widget/src/android/AndroidJavaWrappers.cpp index 596a85f9c7a..86ee310d48a 100644 --- a/widget/src/android/AndroidJavaWrappers.cpp +++ b/widget/src/android/AndroidJavaWrappers.cpp @@ -83,6 +83,7 @@ jmethodID AndroidLocation::jGetTimeMethod = 0; jclass AndroidGeckoSurfaceView::jGeckoSurfaceViewClass = 0; jmethodID AndroidGeckoSurfaceView::jBeginDrawingMethod = 0; jmethodID AndroidGeckoSurfaceView::jEndDrawingMethod = 0; +jmethodID AndroidGeckoSurfaceView::jDraw2DMethod = 0; jmethodID AndroidGeckoSurfaceView::jGetSoftwareDrawBufferMethod = 0; jmethodID AndroidGeckoSurfaceView::jGetHolderMethod = 0; @@ -147,6 +148,7 @@ AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(JNIEnv *jEnv) jBeginDrawingMethod = getMethod("beginDrawing", "()I"); jGetSoftwareDrawBufferMethod = getMethod("getSoftwareDrawBuffer", "()Ljava/nio/ByteBuffer;"); jEndDrawingMethod = getMethod("endDrawing", "()V"); + jDraw2DMethod = getMethod("draw2D", "(Ljava/nio/ByteBuffer;)V"); jGetHolderMethod = getMethod("getHolder", "()Landroid/view/SurfaceHolder;"); } @@ -361,23 +363,16 @@ AndroidGeckoSurfaceView::EndDrawing() JNI()->CallVoidMethod(wrapped_obj, jEndDrawingMethod); } -unsigned char * -AndroidGeckoSurfaceView::GetSoftwareDrawBuffer(int *cap) +void +AndroidGeckoSurfaceView::Draw2D(jobject buffer) { - jobject buf = JNI()->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBufferMethod); - if (!buf) - return nsnull; + JNI()->CallVoidMethod(wrapped_obj, jDraw2DMethod, buffer); +} - void *bp = JNI()->GetDirectBufferAddress(buf); - jlong blen = JNI()->GetDirectBufferCapacity(buf); - - if (!bp || blen == -1) - return nsnull; - - if (cap) - *cap = blen; - - return (unsigned char*) bp; +jobject +AndroidGeckoSurfaceView::GetSoftwareDrawBuffer() +{ + return JNI()->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBufferMethod); } jobject diff --git a/widget/src/android/AndroidJavaWrappers.h b/widget/src/android/AndroidJavaWrappers.h index 5d4b05c2ac5..4d6e2e0924b 100644 --- a/widget/src/android/AndroidJavaWrappers.h +++ b/widget/src/android/AndroidJavaWrappers.h @@ -163,13 +163,13 @@ public: enum { DRAW_ERROR = 0, - DRAW_GLES_2 = 1, - DRAW_SOFTWARE = 2 + DRAW_GLES_2 = 1 }; int BeginDrawing(); - unsigned char *GetSoftwareDrawBuffer(int *cap); + jobject GetSoftwareDrawBuffer(); void EndDrawing(); + void Draw2D(jobject buffer); // must have a JNI local frame when calling this, // and you'd better know what you're doing @@ -179,6 +179,7 @@ protected: static jclass jGeckoSurfaceViewClass; static jmethodID jBeginDrawingMethod; static jmethodID jEndDrawingMethod; + static jmethodID jDraw2DMethod; static jmethodID jGetSoftwareDrawBufferMethod; static jmethodID jGetHolderMethod; }; diff --git a/widget/src/android/nsWindow.cpp b/widget/src/android/nsWindow.cpp index c2973ab460b..e123413839b 100644 --- a/widget/src/android/nsWindow.cpp +++ b/widget/src/android/nsWindow.cpp @@ -580,8 +580,7 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae) int nh = ae->P0().y; if (nw == gAndroidBounds.width && - nh == gAndroidBounds.height) - { + nh == gAndroidBounds.height) { return; } @@ -683,12 +682,12 @@ nsWindow::DrawTo(gfxASurface *targetSurface) if (coveringChildIndex == -1) { ALOG("nsWindow[%p]::DrawTo no covering child, drawing this", (void*) this); + nsPaintEvent event(PR_TRUE, NS_PAINT, this); + event.region = boundsRect; switch (GetLayerManager()->GetBackendType()) { case LayerManager::LAYERS_BASIC: { nsRefPtr ctx = new gfxContext(targetSurface); - nsPaintEvent event(PR_TRUE, NS_PAINT, this); - event.region = boundsRect; { AutoLayerManagerSetup setupLayerManager(this, ctx); status = DispatchEvent(&event); @@ -703,19 +702,16 @@ nsWindow::DrawTo(gfxASurface *targetSurface) // XXX if we got an ignore for the parent, do we still want to draw the children? // We don't really have a good way not to... - - } break; + } case LayerManager::LAYERS_OPENGL: { static_cast(GetLayerManager())-> SetClippingRegion(nsIntRegion(boundsRect)); - nsPaintEvent event(PR_TRUE, NS_PAINT, this); - event.region = boundsRect; status = DispatchEvent(&event); - } break; + } default: NS_ERROR("Invalid layer manager"); @@ -733,8 +729,7 @@ nsWindow::DrawTo(gfxASurface *targetSurface) for (PRUint32 i = coveringChildIndex; i < mChildren.Length(); ++i) { if (mChildren[i]->mBounds.IsEmpty() || - !mChildren[i]->mBounds.Intersects(boundsRect)) - { + !mChildren[i]->mBounds.Intersects(boundsRect)) { continue; } @@ -755,20 +750,6 @@ nsWindow::DrawTo(gfxASurface *targetSurface) return PR_TRUE; } -static int -next_power_of_two(int v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - - return v; -} - void nsWindow::OnDraw(AndroidGeckoEvent *ae) { @@ -794,43 +775,36 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) return; } - int drawType = sview.BeginDrawing(); - - if (drawType == AndroidGeckoSurfaceView::DRAW_ERROR) { - ALOG("##### BeginDrawing failed!"); - return; - } - if (GetLayerManager()->GetBackendType() == LayerManager::LAYERS_BASIC) { - drawType = AndroidGeckoSurfaceView::DRAW_SOFTWARE; - } else { - drawType = AndroidGeckoSurfaceView::DRAW_GLES_2; - } + jobject bytebuf = sview.GetSoftwareDrawBuffer(); + if (!bytebuf) { + ALOG("no buffer to draw into - skipping draw"); + return; + } - if (drawType == AndroidGeckoSurfaceView::DRAW_SOFTWARE) { - int bufCap; - unsigned char *buf = sview.GetSoftwareDrawBuffer(&bufCap); - if (!buf || bufCap != mBounds.width * mBounds.height * 4) { - ALOG("### Software drawing, but too small a buffer %d expected %d (or no buffer %p)!", bufCap, mBounds.width * mBounds.height * 4, (void*)buf); - sview.EndDrawing(); + void *buf = AndroidBridge::JNI()->GetDirectBufferAddress(bytebuf); + int cap = AndroidBridge::JNI()->GetDirectBufferCapacity(bytebuf); + if (!buf || cap < (mBounds.width * mBounds.height * 2)) { + ALOG("### Software drawing, but too small a buffer %d expected %d (or no buffer %p)!", cap, mBounds.width * mBounds.height * 2, buf); return; } nsRefPtr targetSurface = - new gfxImageSurface(buf, + new gfxImageSurface((unsigned char *)buf, gfxIntSize(mBounds.width, mBounds.height), - mBounds.width * 4, - gfxASurface::ImageFormatARGB32); + mBounds.width * 2, + gfxASurface::ImageFormatRGB16_565); DrawTo(targetSurface); + sview.Draw2D(bytebuf); + } else { + int drawType = sview.BeginDrawing(); - // need to swap B and R channels, to get ABGR instead of ARGB - unsigned int *ibuf = (unsigned int*) buf; - unsigned int *ibufMax = ibuf + mBounds.width * mBounds.height; - while (ibuf < ibufMax) { - *ibuf++ = (*ibuf & 0xff00ff00) | ((*ibuf & 0x00ff0000) >> 16) | ((*ibuf & 0x000000ff) << 16); + if (drawType == AndroidGeckoSurfaceView::DRAW_ERROR) { + ALOG("##### BeginDrawing failed!"); + return; } - } else if (drawType == AndroidGeckoSurfaceView::DRAW_GLES_2) { + NS_ASSERTION(sGLContext, "Drawing with GLES without a GL context?"); sGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); @@ -839,9 +813,8 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) if (sGLContext) sGLContext->SwapBuffers(); + sview.EndDrawing(); } - - sview.EndDrawing(); } void