mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 686992 - Draw to Android window/surface directly r=blassey
This commit is contained in:
parent
f44def4369
commit
baeb34d321
@ -248,7 +248,6 @@ class GeckoSurfaceView
|
||||
|
||||
mSurfaceLock.lock();
|
||||
|
||||
try {
|
||||
if (mInDrawing) {
|
||||
Log.w(LOG_FILE_NAME, "surfaceChanged while mInDrawing is true!");
|
||||
}
|
||||
@ -277,33 +276,18 @@ class GeckoSurfaceView
|
||||
|
||||
Log.i(LOG_FILE_NAME, "surfaceChanged: fmt: " + format + " dim: " + width + " " + height);
|
||||
|
||||
try {
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
|
||||
GeckoEvent e = new GeckoEvent(GeckoEvent.SIZE_CHANGED, width, height,
|
||||
metrics.widthPixels, metrics.heightPixels);
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
|
||||
if (!doSyncDraw) {
|
||||
if (mDrawMode == DRAW_GLES_2 || mShowingSplashScreen)
|
||||
return;
|
||||
Canvas c = holder.lockCanvas();
|
||||
c.drawARGB(255, 255, 255, 255);
|
||||
holder.unlockCanvasAndPost(c);
|
||||
return;
|
||||
} else {
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
}
|
||||
} finally {
|
||||
mSurfaceLock.unlock();
|
||||
if (mDrawMode == DRAW_GLES_2) {
|
||||
// Force a frame to be drawn before the surfaceChange returns,
|
||||
// otherwise we get artifacts.
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
GeckoAppShell.geckoEventSync();
|
||||
}
|
||||
}
|
||||
|
||||
if (doSyncDraw) {
|
||||
Object syncDrawObject = null;
|
||||
try {
|
||||
syncDrawObject = mSyncDraws.take();
|
||||
@ -318,6 +302,12 @@ class GeckoSurfaceView
|
||||
} else {
|
||||
Log.e("GeckoSurfaceViewJava", "Synchronised draw object is null");
|
||||
}
|
||||
} else if (!mShowingSplashScreen) {
|
||||
// Make sure a frame is drawn before we return
|
||||
// otherwise we see artifacts or a black screen
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
GeckoAppShell.geckoEventSync();
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
@ -372,6 +362,10 @@ class GeckoSurfaceView
|
||||
return mSoftwareBuffer;
|
||||
}
|
||||
|
||||
public Surface getSurface() {
|
||||
return getHolder().getSurface();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called on Gecko thread
|
||||
*/
|
||||
|
@ -106,8 +106,9 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
||||
|
||||
mJNIEnv = nsnull;
|
||||
mThread = nsnull;
|
||||
mOpenedBitmapLibrary = false;
|
||||
mOpenedGraphicsLibraries = false;
|
||||
mHasNativeBitmapAccess = false;
|
||||
mHasNativeWindowAccess = false;
|
||||
|
||||
mGeckoAppShellClass = (jclass) jEnv->NewGlobalRef(jGeckoAppShellClass);
|
||||
|
||||
@ -977,33 +978,46 @@ AndroidBridge::ExecuteNextRunnable()
|
||||
}
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "leaving %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::OpenGraphicsLibraries()
|
||||
{
|
||||
if (!mOpenedGraphicsLibraries) {
|
||||
// Try to dlopen libjnigraphics.so for direct bitmap access on
|
||||
// Android 2.2+ (API level 8)
|
||||
mOpenedGraphicsLibraries = true;
|
||||
|
||||
void *handle = dlopen("/system/lib/libjnigraphics.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (handle) {
|
||||
AndroidBitmap_getInfo = (int (*)(JNIEnv *, jobject, void *))dlsym(handle, "AndroidBitmap_getInfo");
|
||||
AndroidBitmap_lockPixels = (int (*)(JNIEnv *, jobject, void **))dlsym(handle, "AndroidBitmap_lockPixels");
|
||||
AndroidBitmap_unlockPixels = (int (*)(JNIEnv *, jobject))dlsym(handle, "AndroidBitmap_unlockPixels");
|
||||
|
||||
ALOG_BRIDGE("Successfully opened libjnigraphics.so");
|
||||
}
|
||||
|
||||
// Try to dlopen libandroid.so for and native window access on
|
||||
// Android 2.3+ (API level 9)
|
||||
handle = dlopen("/system/lib/libandroid.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (handle) {
|
||||
ANativeWindow_fromSurface = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurface");
|
||||
ANativeWindow_release = (void (*)(void*))dlsym(handle, "ANativeWindow_release");
|
||||
ANativeWindow_setBuffersGeometry = (int (*)(void*, int, int, int)) dlsym(handle, "ANativeWindow_setBuffersGeometry");
|
||||
ANativeWindow_lock = (int (*)(void*, void*, void*)) dlsym(handle, "ANativeWindow_lock");
|
||||
ANativeWindow_unlockAndPost = (int (*)(void*))dlsym(handle, "ANativeWindow_unlockAndPost");
|
||||
|
||||
ALOG_BRIDGE("Successfully opened libandroid.so");
|
||||
}
|
||||
|
||||
mHasNativeBitmapAccess = AndroidBitmap_getInfo && AndroidBitmap_lockPixels && AndroidBitmap_unlockPixels;
|
||||
mHasNativeWindowAccess = ANativeWindow_fromSurface && ANativeWindow_release && ANativeWindow_lock && ANativeWindow_unlockAndPost;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidBridge::HasNativeBitmapAccess()
|
||||
{
|
||||
if (!mOpenedBitmapLibrary) {
|
||||
// Try to dlopen libjnigraphics.so for direct bitmap access on
|
||||
// Android 2.2+ (API level 8)
|
||||
mOpenedBitmapLibrary = true;
|
||||
|
||||
void *handle = dlopen("/system/lib/libjnigraphics.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (handle == nsnull)
|
||||
return false;
|
||||
|
||||
AndroidBitmap_getInfo = (int (*)(JNIEnv *, jobject, void *))dlsym(handle, "AndroidBitmap_getInfo");
|
||||
if (AndroidBitmap_getInfo == nsnull)
|
||||
return false;
|
||||
|
||||
AndroidBitmap_lockPixels = (int (*)(JNIEnv *, jobject, void **))dlsym(handle, "AndroidBitmap_lockPixels");
|
||||
if (AndroidBitmap_lockPixels == nsnull)
|
||||
return false;
|
||||
|
||||
AndroidBitmap_unlockPixels = (int (*)(JNIEnv *, jobject))dlsym(handle, "AndroidBitmap_unlockPixels");
|
||||
if (AndroidBitmap_unlockPixels == nsnull)
|
||||
return false;
|
||||
|
||||
ALOG_BRIDGE("Successfully opened libjnigraphics.so");
|
||||
mHasNativeBitmapAccess = true;
|
||||
}
|
||||
OpenGraphicsLibraries();
|
||||
|
||||
return mHasNativeBitmapAccess;
|
||||
}
|
||||
@ -1057,3 +1071,92 @@ AndroidBridge::UnlockBitmap(jobject bitmap)
|
||||
if ((err = AndroidBitmap_unlockPixels(JNI(), bitmap)) != 0)
|
||||
ALOG_BRIDGE("AndroidBitmap_unlockPixels failed! (error %d)", err);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AndroidBridge::HasNativeWindowAccess()
|
||||
{
|
||||
OpenGraphicsLibraries();
|
||||
|
||||
return mHasNativeWindowAccess;
|
||||
}
|
||||
|
||||
void*
|
||||
AndroidBridge::AcquireNativeWindow(jobject surface)
|
||||
{
|
||||
if (!HasNativeWindowAccess())
|
||||
return nsnull;
|
||||
|
||||
return ANativeWindow_fromSurface(JNI(), surface);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::ReleaseNativeWindow(void *window)
|
||||
{
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
ANativeWindow_release(window);
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidBridge::SetNativeWindowFormat(void *window, int format)
|
||||
{
|
||||
return ANativeWindow_setBuffersGeometry(window, 0, 0, format) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidBridge::LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride)
|
||||
{
|
||||
/* Copied from native_window.h in Android NDK (platform-9) */
|
||||
typedef struct ANativeWindow_Buffer {
|
||||
// The number of pixels that are show horizontally.
|
||||
int32_t width;
|
||||
|
||||
// The number of pixels that are shown vertically.
|
||||
int32_t height;
|
||||
|
||||
// The number of *pixels* that a line in the buffer takes in
|
||||
// memory. This may be >= width.
|
||||
int32_t stride;
|
||||
|
||||
// The format of the buffer. One of WINDOW_FORMAT_*
|
||||
int32_t format;
|
||||
|
||||
// The actual bits.
|
||||
void* bits;
|
||||
|
||||
// Do not touch.
|
||||
uint32_t reserved[6];
|
||||
} ANativeWindow_Buffer;
|
||||
|
||||
int err;
|
||||
ANativeWindow_Buffer buffer;
|
||||
|
||||
*bits = NULL;
|
||||
*width = *height = *format = 0;
|
||||
if ((err = ANativeWindow_lock(window, (void*)&buffer, NULL)) != 0) {
|
||||
ALOG_BRIDGE("ANativeWindow_lock failed! (error %d)", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
*bits = (unsigned char*)buffer.bits;
|
||||
*width = buffer.width;
|
||||
*height = buffer.height;
|
||||
*format = buffer.format;
|
||||
*stride = buffer.stride;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidBridge::UnlockWindow(void* window)
|
||||
{
|
||||
int err;
|
||||
if ((err = ANativeWindow_unlockAndPost(window)) != 0) {
|
||||
ALOG_BRIDGE("ANativeWindow_unlockAndPost failed! (error %d)", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -267,6 +267,22 @@ public:
|
||||
|
||||
void ExecuteNextRunnable();
|
||||
|
||||
/* Copied from Android's native_window.h in newer (platform 9) NDK */
|
||||
enum {
|
||||
WINDOW_FORMAT_RGBA_8888 = 1,
|
||||
WINDOW_FORMAT_RGBX_8888 = 2,
|
||||
WINDOW_FORMAT_RGB_565 = 4,
|
||||
};
|
||||
|
||||
bool HasNativeWindowAccess();
|
||||
|
||||
void *AcquireNativeWindow(jobject surface);
|
||||
void ReleaseNativeWindow(void *window);
|
||||
bool SetNativeWindowFormat(void *window, int format);
|
||||
|
||||
bool LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride);
|
||||
bool UnlockWindow(void *window);
|
||||
|
||||
protected:
|
||||
static AndroidBridge *sBridge;
|
||||
|
||||
@ -288,8 +304,11 @@ protected:
|
||||
|
||||
void EnsureJNIThread();
|
||||
|
||||
bool mOpenedBitmapLibrary;
|
||||
bool mOpenedGraphicsLibraries;
|
||||
void OpenGraphicsLibraries();
|
||||
|
||||
bool mHasNativeBitmapAccess;
|
||||
bool mHasNativeWindowAccess;
|
||||
|
||||
nsCOMArray<nsIRunnable> mRunnableQueue;
|
||||
|
||||
@ -346,6 +365,13 @@ protected:
|
||||
int (* AndroidBitmap_getInfo)(JNIEnv *env, jobject bitmap, void *info);
|
||||
int (* AndroidBitmap_lockPixels)(JNIEnv *env, jobject bitmap, void **buffer);
|
||||
int (* AndroidBitmap_unlockPixels)(JNIEnv *env, jobject bitmap);
|
||||
|
||||
void* (*ANativeWindow_fromSurface)(JNIEnv *env, jobject surface);
|
||||
void (*ANativeWindow_release)(void *window);
|
||||
int (*ANativeWindow_setBuffersGeometry)(void *window, int width, int height, int format);
|
||||
|
||||
int (* ANativeWindow_lock)(void *window, void *outBuffer, void *inOutDirtyBounds);
|
||||
int (* ANativeWindow_unlockAndPost)(void *window);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -109,6 +109,7 @@ jmethodID AndroidGeckoSurfaceView::jDraw2DBitmapMethod = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jDraw2DBufferMethod = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jGetSoftwareDrawBitmapMethod = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jGetSoftwareDrawBufferMethod = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jGetSurfaceMethod = 0;
|
||||
jmethodID AndroidGeckoSurfaceView::jGetHolderMethod = 0;
|
||||
|
||||
#define JNI() (AndroidBridge::JNI())
|
||||
@ -183,6 +184,7 @@ AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(JNIEnv *jEnv)
|
||||
jEndDrawingMethod = getMethod("endDrawing", "()V");
|
||||
jDraw2DBitmapMethod = getMethod("draw2D", "(Landroid/graphics/Bitmap;II)V");
|
||||
jDraw2DBufferMethod = getMethod("draw2D", "(Ljava/nio/ByteBuffer;I)V");
|
||||
jGetSurfaceMethod = getMethod("getSurface", "()Landroid/view/Surface;");
|
||||
jGetHolderMethod = getMethod("getHolder", "()Landroid/view/SurfaceHolder;");
|
||||
}
|
||||
|
||||
@ -516,6 +518,12 @@ AndroidGeckoSurfaceView::GetSoftwareDrawBuffer()
|
||||
return JNI()->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBufferMethod);
|
||||
}
|
||||
|
||||
jobject
|
||||
AndroidGeckoSurfaceView::GetSurface()
|
||||
{
|
||||
return JNI()->CallObjectMethod(wrapped_obj, jGetSurfaceMethod);
|
||||
}
|
||||
|
||||
jobject
|
||||
AndroidGeckoSurfaceView::GetSurfaceHolder()
|
||||
{
|
||||
|
@ -175,6 +175,8 @@ public:
|
||||
void Draw2D(jobject bitmap, int width, int height);
|
||||
void Draw2D(jobject buffer, int stride);
|
||||
|
||||
jobject GetSurface();
|
||||
|
||||
// must have a JNI local frame when calling this,
|
||||
// and you'd better know what you're doing
|
||||
jobject GetSurfaceHolder();
|
||||
@ -187,6 +189,7 @@ protected:
|
||||
static jmethodID jDraw2DBufferMethod;
|
||||
static jmethodID jGetSoftwareDrawBitmapMethod;
|
||||
static jmethodID jGetSoftwareDrawBufferMethod;
|
||||
static jmethodID jGetSurfaceMethod;
|
||||
static jmethodID jGetHolderMethod;
|
||||
};
|
||||
|
||||
|
@ -129,6 +129,7 @@ static nsRefPtr<gl::GLContext> sGLContext;
|
||||
static bool sFailedToCreateGLContext = false;
|
||||
static bool sValidSurface;
|
||||
static bool sSurfaceExists = false;
|
||||
static void *sNativeWindow = nsnull;
|
||||
|
||||
// Multitouch swipe thresholds in inches
|
||||
static const double SWIPE_MAX_PINCH_DELTA_INCHES = 0.4;
|
||||
@ -846,12 +847,27 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
|
||||
|
||||
case AndroidGeckoEvent::SURFACE_CREATED:
|
||||
sSurfaceExists = true;
|
||||
|
||||
if (AndroidBridge::Bridge()->HasNativeWindowAccess()) {
|
||||
AndroidGeckoSurfaceView& sview(AndroidBridge::Bridge()->SurfaceView());
|
||||
jobject surface = sview.GetSurface();
|
||||
if (surface) {
|
||||
sNativeWindow = AndroidBridge::Bridge()->AcquireNativeWindow(surface);
|
||||
if (sNativeWindow) {
|
||||
AndroidBridge::Bridge()->SetNativeWindowFormat(sNativeWindow, AndroidBridge::WINDOW_FORMAT_RGB_565);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AndroidGeckoEvent::SURFACE_DESTROYED:
|
||||
if (sGLContext && sValidSurface) {
|
||||
sGLContext->ReleaseSurface();
|
||||
}
|
||||
if (sNativeWindow) {
|
||||
AndroidBridge::Bridge()->ReleaseNativeWindow(sNativeWindow);
|
||||
sNativeWindow = nsnull;
|
||||
}
|
||||
sSurfaceExists = false;
|
||||
sValidSurface = false;
|
||||
break;
|
||||
@ -1002,7 +1018,35 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||
AndroidBridge::Bridge()->HideProgressDialogOnce();
|
||||
|
||||
if (GetLayerManager(nsnull)->GetBackendType() == LayerManager::LAYERS_BASIC) {
|
||||
if (AndroidBridge::Bridge()->HasNativeBitmapAccess()) {
|
||||
if (sNativeWindow) {
|
||||
unsigned char *bits;
|
||||
int width, height, format, stride;
|
||||
if (!AndroidBridge::Bridge()->LockWindow(sNativeWindow, &bits, &width, &height, &format, &stride)) {
|
||||
ALOG("failed to lock buffer - skipping draw");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bits || format != AndroidBridge::WINDOW_FORMAT_RGB_565 ||
|
||||
width != mBounds.width || height != mBounds.height) {
|
||||
|
||||
ALOG("surface is not expected dimensions or format - skipping draw");
|
||||
AndroidBridge::Bridge()->UnlockWindow(sNativeWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxImageSurface> targetSurface =
|
||||
new gfxImageSurface(bits,
|
||||
gfxIntSize(mBounds.width, mBounds.height),
|
||||
stride * 2,
|
||||
gfxASurface::ImageFormatRGB16_565);
|
||||
if (targetSurface->CairoStatus()) {
|
||||
ALOG("### Failed to create a valid surface from the bitmap");
|
||||
} else {
|
||||
DrawTo(targetSurface);
|
||||
}
|
||||
|
||||
AndroidBridge::Bridge()->UnlockWindow(sNativeWindow);
|
||||
} else if (AndroidBridge::Bridge()->HasNativeBitmapAccess()) {
|
||||
jobject bitmap = sview.GetSoftwareDrawBitmap();
|
||||
if (!bitmap) {
|
||||
ALOG("no bitmap to draw into - skipping draw");
|
||||
|
Loading…
Reference in New Issue
Block a user