Bug 670930 - Use asynchronous direct texturing on Android when available

This commit is contained in:
James Willcox 2011-12-16 16:40:58 -05:00
parent c95ce8cb7c
commit f2138c4d9f
10 changed files with 267 additions and 12 deletions

View File

@ -138,6 +138,8 @@ public class GeckoAppShell
public static native void notifySmsReceived(String aSender, String aBody, long aTimestamp);
public static native ByteBuffer allocateDirectBuffer(long size);
public static native void freeDirectBuffer(ByteBuffer buf);
public static native void bindWidgetTexture();
public static native boolean testDirectTexture();
// A looper thread, accessed by GeckoAppShell.getHandler
private static class LooperThread extends Thread {
@ -425,6 +427,14 @@ public class GeckoAppShell
Log.i(LOGTAG, "post native init");
// If we have direct texture available, use it
if (GeckoAppShell.testDirectTexture()) {
Log.i(LOGTAG, "Using direct texture for widget layer");
GeckoApp.mAppContext.getSoftwareLayerClient().installWidgetLayer();
} else {
Log.i(LOGTAG, "Falling back to traditional texture upload");
}
// Tell Gecko where the target byte buffer is for rendering
GeckoAppShell.setSoftwareLayerClient(GeckoApp.mAppContext.getSoftwareLayerClient());

View File

@ -107,6 +107,7 @@ JAVAFILES = \
gfx/TextureReaper.java \
gfx/TileLayer.java \
gfx/ViewportMetrics.java \
gfx/WidgetTileLayer.java \
ui/PanZoomController.java \
$(NULL)

View File

@ -45,6 +45,7 @@ import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.gfx.LayerRenderer;
import org.mozilla.gecko.gfx.PointUtils;
import org.mozilla.gecko.gfx.SingleTileLayer;
import org.mozilla.gecko.gfx.WidgetTileLayer;
import org.mozilla.gecko.FloatUtils;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
@ -76,7 +77,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
private IntSize mScreenSize, mViewportSize;
private IntSize mBufferSize;
private ByteBuffer mBuffer;
private final SingleTileLayer mTileLayer;
private Layer mTileLayer;
/* The viewport rect that Gecko is currently displaying. */
private ViewportMetrics mGeckoViewport;
@ -125,6 +126,10 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
}
}
public void installWidgetLayer() {
mTileLayer = new WidgetTileLayer(mCairoImage);
}
/** Attaches the root layer to the layer controller so that Gecko appears. */
@Override
public void setLayerController(LayerController layerController) {
@ -188,7 +193,9 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
updateViewport(metadata, !mUpdateViewportOnEndDraw);
mUpdateViewportOnEndDraw = false;
Rect rect = new Rect(x, y, x + width, y + height);
mTileLayer.invalidate(rect);
if (mTileLayer instanceof SingleTileLayer)
((SingleTileLayer)mTileLayer).invalidate(rect);
} finally {
endTransaction(mTileLayer);
}

View File

@ -53,24 +53,24 @@ public abstract class LayerClient {
}
/**
* A utility function for calling TileLayer.beginTransaction with the
* A utility function for calling Layer.beginTransaction with the
* appropriate LayerView.
*/
public void beginTransaction(TileLayer aTileLayer) {
public void beginTransaction(Layer aLayer) {
if (mLayerController != null) {
LayerView view = mLayerController.getView();
if (view != null) {
aTileLayer.beginTransaction(view);
aLayer.beginTransaction(view);
return;
}
}
aTileLayer.beginTransaction();
aLayer.beginTransaction();
}
// Included for symmetry.
public void endTransaction(TileLayer aTileLayer) {
aTileLayer.endTransaction();
public void endTransaction(Layer aLayer) {
aLayer.endTransaction();
}
}

View File

@ -0,0 +1,116 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009-2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* James Willcox <jwillcox@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.gfx.SingleTileLayer;
import org.mozilla.gecko.GeckoAppShell;
import android.opengl.GLES11;
import android.opengl.GLES11Ext;
import android.graphics.RectF;
import android.util.Log;
import javax.microedition.khronos.opengles.GL10;
/**
* Encapsulates the logic needed to draw the single-tiled Gecko texture
*/
public class WidgetTileLayer extends Layer {
private int[] mTextureIDs;
private CairoImage mImage;
public WidgetTileLayer(CairoImage image) {
mImage = image;
}
protected boolean initialized() { return mTextureIDs != null; }
@Override
public IntSize getSize() { return mImage.getSize(); }
protected void bindAndSetGLParameters() {
GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]);
GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
}
@Override
protected void finalize() throws Throwable {
if (mTextureIDs != null)
TextureReaper.get().add(mTextureIDs);
}
@Override
protected void performUpdates(GL10 gl) {
super.performUpdates(gl);
if (mTextureIDs == null) {
mTextureIDs = new int[1];
GLES11.glGenTextures(1, mTextureIDs, 0);
}
bindAndSetGLParameters();
GeckoAppShell.bindWidgetTexture();
}
@Override
public void draw(RenderContext context) {
// mTextureIDs may be null here during startup if Layer.java's draw method
// failed to acquire the transaction lock and call performUpdates.
if (!initialized())
return;
GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]);
RectF bounds;
int[] cropRect;
IntSize size = getSize();
RectF viewport = context.viewport;
bounds = getBounds(context, new FloatSize(size));
cropRect = new int[] { 0, size.height, size.width, -size.height };
bounds.offset(-viewport.left, -viewport.top);
GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect,
0);
float top = viewport.height() - (bounds.top + bounds.height());
GLES11Ext.glDrawTexfOES(bounds.left, top, 0.0f, bounds.width(), bounds.height());
}
}

View File

@ -299,6 +299,8 @@ SHELL_WRAPPER1(cameraCallbackBridge, jbyteArray)
SHELL_WRAPPER1(notifyUriVisited, jstring)
SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble);
SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong);
SHELL_WRAPPER0(bindWidgetTexture);
SHELL_WRAPPER0_WITH_RETURN(testDirectTexture, bool);
static void * xul_handle = NULL;
static time_t apk_mtime = 0;
@ -638,7 +640,7 @@ loadLibs(const char *apkName)
gettimeofday(&t0, 0);
struct rusage usage1;
getrusage(RUSAGE_THREAD, &usage1);
void *zip = map_file(apkName);
struct cdir_end *dirend = (struct cdir_end *)((char *)zip + zip_size - sizeof(*dirend));
while ((void *)dirend > zip &&
@ -704,6 +706,8 @@ loadLibs(const char *apkName)
GETFUNC(notifyUriVisited);
GETFUNC(notifyBatteryChange);
GETFUNC(notifySmsReceived);
GETFUNC(bindWidgetTexture);
GETFUNC(testDirectTexture);
#undef GETFUNC
sStartupTimeline = (uint64_t *)__wrap_dlsym(xul_handle, "_ZN7mozilla15StartupTimeline16sStartupTimelineE");
gettimeofday(&t1, 0);

View File

@ -40,6 +40,7 @@
#include "nsString.h"
#include "AndroidBridge.h"
#include "AndroidGraphicBuffer.h"
#include <jni.h>
#include <pthread.h>
@ -88,6 +89,11 @@ extern "C" {
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited(JNIEnv *, jclass, jstring uri);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyBatteryChange(JNIEnv* jenv, jclass, jdouble, jboolean, jdouble);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifySmsReceived(JNIEnv* jenv, jclass, jstring, jstring, jlong);
#ifdef MOZ_JAVA_COMPOSITOR
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass);
NS_EXPORT bool JNICALL Java_org_mozilla_gecko_GeckoAppShell_testDirectTexture(JNIEnv* jenv, jclass);
#endif
}
@ -278,3 +284,19 @@ Java_org_mozilla_gecko_GeckoAppShell_notifySmsReceived(JNIEnv* jenv, jclass,
nsCOMPtr<nsIRunnable> runnable = new NotifySmsReceivedRunnable(message);
NS_DispatchToMainThread(runnable);
}
#ifdef MOZ_JAVA_COMPOSITOR
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass)
{
nsWindow::BindToTexture();
}
NS_EXPORT bool JNICALL
Java_org_mozilla_gecko_GeckoAppShell_testDirectTexture(JNIEnv* jenv, jclass)
{
return nsWindow::HasDirectTexture();
}
#endif

View File

@ -61,6 +61,8 @@ CPPSRCS = \
nsAppShell.cpp \
AndroidJavaWrappers.cpp \
AndroidBridge.cpp \
AndroidDirectTexture.cpp \
AndroidGraphicBuffer.cpp \
AndroidJNI.cpp \
nsWindow.cpp \
nsLookAndFeel.cpp \

View File

@ -39,6 +39,7 @@
#include <android/log.h>
#include <math.h>
#include <unistd.h>
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentChild.h"
@ -92,6 +93,20 @@ static gfxIntSize gAndroidScreenBounds;
bool nsWindow::sAccessibilityEnabled = false;
#endif
#ifdef MOZ_JAVA_COMPOSITOR
#include "mozilla/Mutex.h"
#include "nsThreadUtils.h"
#include "AndroidDirectTexture.h"
static AndroidDirectTexture* sDirectTexture = new AndroidDirectTexture(2048, 2048,
AndroidGraphicBuffer::UsageSoftwareWrite | AndroidGraphicBuffer::UsageTexture,
gfxASurface::ImageFormatRGB16_565);
static bool sHasDirectTexture = true;
#endif
class ContentCreationNotifier;
static nsCOMPtr<ContentCreationNotifier> gContentCreationNotifier;
// A helper class to send updates when content processes
@ -808,6 +823,53 @@ nsWindow::GetThebesSurface()
return new gfxImageSurface(gfxIntSize(5,5), gfxImageSurface::ImageFormatRGB24);
}
#ifdef MOZ_JAVA_COMPOSITOR
void
nsWindow::BindToTexture()
{
sDirectTexture->Bind();
}
bool
nsWindow::HasDirectTexture()
{
// If we already tested, return early
if (!sHasDirectTexture)
return false;
AndroidGraphicBuffer* buffer = new AndroidGraphicBuffer(512, 512,
AndroidGraphicBuffer::UsageSoftwareWrite | AndroidGraphicBuffer::UsageTexture,
gfxASurface::ImageFormatRGB16_565);
unsigned char* bits = NULL;
if (!buffer->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, &bits) || !bits) {
ALOG("failed to lock graphic buffer");
buffer->Unlock();
sHasDirectTexture = false;
goto cleanup;
}
if (!buffer->Unlock()) {
ALOG("failed to unlock graphic buffer");
sHasDirectTexture = false;
goto cleanup;
}
if (!buffer->Reallocate(1024, 1024, gfxASurface::ImageFormatRGB16_565)) {
ALOG("failed to reallocate graphic buffer");
sHasDirectTexture = false;
goto cleanup;
}
cleanup:
delete buffer;
return sHasDirectTexture;
}
#endif
void
nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
{
@ -1111,9 +1173,26 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
client.BeginDrawing();
nsAutoString metadata;
unsigned char *bits = client.LockBufferBits();
unsigned char *bits = NULL;
if (sHasDirectTexture) {
if ((sDirectTexture->Width() != gAndroidBounds.width ||
sDirectTexture->Height() != gAndroidBounds.height) &&
gAndroidBounds.width != 0 && gAndroidBounds.height != 0) {
sDirectTexture->Reallocate(gAndroidBounds.width, gAndroidBounds.height);
}
sDirectTexture->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, &bits);
} else {
bits = client.LockBufferBits();
}
if (!bits) {
ALOG("### Failed to lock buffer");
if (sHasDirectTexture) {
sDirectTexture->Unlock();
} else {
client.UnlockBuffer();
}
} else {
nsRefPtr<gfxImageSurface> targetSurface =
new gfxImageSurface(bits, gfxIntSize(gAndroidBounds.width, gAndroidBounds.height), gAndroidBounds.width * 2,
@ -1121,7 +1200,12 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
if (targetSurface->CairoStatus()) {
ALOG("### Failed to create a valid surface from the bitmap");
} else {
DrawTo(targetSurface, ae->Rect());
if (sHasDirectTexture) {
// XXX: lock only the dirty rect above and pass it in here
DrawTo(targetSurface);
} else {
DrawTo(targetSurface, ae->Rect());
}
{
nsCOMPtr<nsIAndroidDrawMetadataProvider> metadataProvider =
@ -1130,7 +1214,11 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
metadataProvider->GetDrawMetadata(metadata);
}
}
client.UnlockBuffer();
if (sHasDirectTexture) {
sDirectTexture->Unlock();
} else {
client.UnlockBuffer();
}
}
client.EndDrawing(ae->Rect(), metadata);
return;

View File

@ -177,6 +177,11 @@ public:
static bool sAccessibilityEnabled;
#endif
#ifdef MOZ_JAVA_COMPOSITOR
static void BindToTexture();
static bool HasDirectTexture();
#endif
protected:
void BringToFront();
nsWindow *FindTopLevel();