Bug 575421 - Improve 2D drawing path on Android, r=vlad

This commit is contained in:
Michael Wu 2010-06-28 23:42:28 -07:00
parent 00e8f7da8b
commit 63f56cde6f
6 changed files with 72 additions and 142 deletions

View File

@ -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

View File

@ -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

View File

@ -87,8 +87,11 @@ already_AddRefed<gfxASurface>
gfxAndroidPlatform::CreateOffscreenSurface(const gfxIntSize& size,
gfxASurface::gfxImageFormat imageFormat)
{
nsRefPtr<gfxASurface> newSurface =
new gfxImageSurface (size, imageFormat);
nsRefPtr<gfxASurface> newSurface;
if (imageFormat == gfxImageSurface::ImageFormatRGB24)
newSurface = new gfxImageSurface (size, gfxASurface::ImageFormatRGB16_565);
else
newSurface = new gfxImageSurface (size, imageFormat);
return newSurface.forget();
}

View File

@ -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

View File

@ -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;
};

View File

@ -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<gfxContext> 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<mozilla::layers::LayerManagerOGL*>(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<gfxImageSurface> 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