Commit 625a7865 authored by sievers's avatar sievers Committed by Commit bot

android: Use hw acceleration in android_webview_shell

This creates a (GL)SurfaceView overlay on top of the shell
container view which runs its own thread for rendering.
It calls into the native draw functor through a small
dynamic library (drawgl.so).

Committed previously: https://chromium.googlesource.com/chromium/src/+/09acbf59e7e8f1de574498ee5ba8eae0b0775438

Review URL: https://codereview.chromium.org/414503004

Cr-Commit-Position: refs/heads/master@{#292761}
parent b1394741
......@@ -10,6 +10,7 @@
'libwebviewchromium',
'android_webview_java',
'android_webview_pak',
'libdrawgl',
],
'variables': {
'apk_name': 'AndroidWebView',
......@@ -17,6 +18,7 @@
'native_lib_target': 'libstandalonelibwebviewchromium',
'resource_dir': 'test/shell/res',
'extensions_to_not_compress': 'pak',
'extra_native_libs': ['<(SHARED_LIB_DIR)/libdrawgl.>(android_product_extension)'],
'additional_input_paths': [
'<(PRODUCT_DIR)/android_webview_apk/assets/webviewchromium.pak',
'<(PRODUCT_DIR)/android_webview_apk/assets/en-US.pak',
......@@ -162,5 +164,17 @@
],
'includes': [ '../build/apk_test.gypi' ],
},
{
'target_name': 'libdrawgl',
'type': 'shared_library',
# Do not depend on any other component here, since this target
# builds a separate shared library!
'include_dirs': [
'..',
],
'sources': [
'../android_webview/test/shell/src/draw_gl/draw_gl.cc',
],
},
],
}
......@@ -65,7 +65,7 @@ public class AndroidScrollIntegrationTest extends AwTestBase {
new OverScrollByCallbackHelper();
public ScrollTestContainerView(Context context) {
super(context);
super(context, false);
}
public CallbackHelper getOnScrollToCallbackHelper() {
......
......@@ -274,7 +274,7 @@ public class AwTestBase
*/
public static class TestDependencyFactory extends AwContents.DependencyFactory {
public AwTestContainerView createAwTestContainerView(AwTestRunnerActivity activity) {
return new AwTestContainerView(activity);
return new AwTestContainerView(activity, false);
}
public AwSettings createAwSettings(Context context, boolean supportsLegacyQuirks) {
return new AwSettings(context, false, supportsLegacyQuirks);
......
......@@ -10,17 +10,19 @@
package="org.chromium.android_webview.shell">
<application android:name="org.chromium.android_webview.shell.AwShellApplication"
android:label="AwShellApplication" android:hardwareAccelerated="false">
android:label="AwShellApplication">
<activity android:name="org.chromium.android_webview.shell.AwShellActivity"
android:label="Android WebView Test Shell"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize">
android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="org.chromium.android_webview.test.AwTestRunnerActivity"
android:label="AwTestRunnerActivity">
android:label="AwTestRunnerActivity"
android:hardwareAccelerated="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
......
include_rules = [
# draw_gl compiles its own shared library for a single entry point
# for testing. Therefore it cannot depend on any other module,
# except for shared definitions.
"-android_webview",
"+android_webview/public/browser",
]
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <jni.h>
#include "android_webview/public/browser/draw_gl.h"
extern "C" {
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return JNI_VERSION_1_4;
}
// This code goes into its own dynamic library, so we cannot depend on
// any other components like base.
JNIEXPORT void JNICALL
Java_org_chromium_android_1webview_shell_DrawGL_nativeDrawGL(
JNIEnv*,
jclass,
jlong draw_gl,
jlong view,
jint width,
jint height,
jint scroll_x,
jint scroll_y,
jint mode) {
AwDrawGLInfo draw_info;
draw_info.mode = static_cast<AwDrawGLInfo::Mode>(mode);
draw_info.version = kAwDrawGLInfoVersion;
draw_info.is_layer = false;
draw_info.width = width;
draw_info.height = height;
draw_info.clip_left = 0;
draw_info.clip_top = 0;
draw_info.clip_bottom = height;
draw_info.clip_right = width;
draw_info.transform[0] = 1.0;
draw_info.transform[1] = 0.0;
draw_info.transform[2] = 0.0;
draw_info.transform[3] = 0.0;
draw_info.transform[4] = 0.0;
draw_info.transform[5] = 1.0;
draw_info.transform[6] = 0.0;
draw_info.transform[7] = 0.0;
draw_info.transform[8] = 0.0;
draw_info.transform[9] = 0.0;
draw_info.transform[10] = 1.0;
draw_info.transform[11] = 0.0;
draw_info.transform[12] = -scroll_x;
draw_info.transform[13] = -scroll_y;
draw_info.transform[14] = 0.0;
draw_info.transform[15] = 1.0;
AwDrawGLFunction* draw_func = reinterpret_cast<AwDrawGLFunction*>(draw_gl);
draw_func(view, &draw_info, 0);
}
}
......@@ -80,7 +80,7 @@ public class AwShellActivity extends Activity {
private AwTestContainerView createAwTestContainerView() {
AwBrowserProcess.start(this);
AwTestContainerView testContainerView = new AwTestContainerView(this);
AwTestContainerView testContainerView = new AwTestContainerView(this, true);
AwContentsClient awContentsClient = new NullContentsClient() {
private View mCustomView;
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.android_webview.shell;
/**
* Provides an entry point to the native draw functor.
*/
public class DrawGL {
public static void drawGL(long drawGL, long viewContext, int width, int height,
int scrollX, int scrollY, int mode) {
nativeDrawGL(drawGL, viewContext, width, height, scrollX, scrollY, mode);
}
private static native void nativeDrawGL(long drawGL, long viewContext,
int width, int height, int scrollX, int scrollY, int mode);
}
......@@ -7,10 +7,13 @@ package org.chromium.android_webview.test;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
......@@ -20,8 +23,12 @@ import android.view.inputmethod.InputConnection;
import android.widget.FrameLayout;
import org.chromium.android_webview.AwContents;
import org.chromium.android_webview.shell.DrawGL;
import org.chromium.content.browser.ContentViewCore;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* A View used for testing the AwContents internals.
*
......@@ -32,8 +39,180 @@ public class AwTestContainerView extends FrameLayout {
private AwContents.NativeGLDelegate mNativeGLDelegate;
private AwContents.InternalAccessDelegate mInternalAccessDelegate;
public AwTestContainerView(Context context) {
HardwareView mHardwareView = null;
private boolean mAttachedContents = false;
private class HardwareView extends GLSurfaceView {
private static final int MODE_DRAW = 0;
private static final int MODE_PROCESS = 1;
private static final int MODE_PROCESS_NO_CONTEXT = 2;
private static final int MODE_SYNC = 3;
// mSyncLock is used to synchronized requestRender on the UI thread
// and drawGL on the rendering thread. The variables following
// are protected by it.
private final Object mSyncLock = new Object();
private boolean mNeedsProcessGL = false;
private boolean mNeedsDrawGL = false;
private boolean mWaitForCompletion = false;
private int mLastScrollX = 0;
private int mLastScrollY = 0;
private int mCommittedScrollX = 0;
private int mCommittedScrollY = 0;
private boolean mHaveSurface = false;
private Runnable mReadyToRenderCallback = null;
private long mDrawGL = 0;
private long mViewContext = 0;
public HardwareView(Context context) {
super(context);
setEGLContextClientVersion(2); // GLES2
getHolder().setFormat(PixelFormat.OPAQUE);
setPreserveEGLContextOnPause(true);
setRenderer(new Renderer() {
private int mWidth = 0;
private int mHeight = 0;
@Override
public void onDrawFrame(GL10 gl) {
HardwareView.this.drawGL(mWidth, mHeight);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glScissor(0, 0, width, height);
mWidth = width;
mHeight = height;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
});
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
public void initialize(long drawGL, long viewContext) {
mDrawGL = drawGL;
mViewContext = viewContext;
}
public boolean isReadyToRender() {
return mHaveSurface;
}
public void setReadyToRenderCallback(Runnable runner) {
assert !isReadyToRender() || runner == null;
mReadyToRenderCallback = runner;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
boolean didHaveSurface = mHaveSurface;
mHaveSurface = true;
if (!didHaveSurface && mReadyToRenderCallback != null) {
mReadyToRenderCallback.run();
mReadyToRenderCallback = null;
}
super.surfaceCreated(holder);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mHaveSurface = false;
super.surfaceDestroyed(holder);
}
public void updateScroll(int x, int y) {
synchronized (mSyncLock) {
mLastScrollX = x;
mLastScrollY = y;
}
}
public void requestRender(Canvas canvas, boolean waitForCompletion) {
synchronized (mSyncLock) {
super.requestRender();
mWaitForCompletion = waitForCompletion;
if (canvas == null) {
mNeedsProcessGL = true;
} else {
mNeedsDrawGL = true;
if (!waitForCompletion) {
// Wait until SYNC is complete only.
// Do this every time there was a new frame.
try {
while (mNeedsDrawGL) {
mSyncLock.wait();
}
} catch (InterruptedException e) {
// ...
}
}
}
if (waitForCompletion) {
try {
while (mWaitForCompletion) {
mSyncLock.wait();
}
} catch (InterruptedException e) {
// ...
}
}
}
}
public void drawGL(int width, int height) {
final boolean draw;
final boolean process;
final boolean waitForCompletion;
synchronized (mSyncLock) {
draw = mNeedsDrawGL;
process = mNeedsProcessGL;
waitForCompletion = mWaitForCompletion;
if (draw) {
DrawGL.drawGL(mDrawGL, mViewContext, width, height, 0, 0, MODE_SYNC);
mCommittedScrollX = mLastScrollX;
mCommittedScrollY = mLastScrollY;
}
mNeedsDrawGL = false;
mNeedsProcessGL = false;
if (!waitForCompletion) {
mSyncLock.notifyAll();
}
}
if (draw) {
DrawGL.drawGL(mDrawGL, mViewContext, width, height,
mCommittedScrollX, mCommittedScrollY, MODE_DRAW);
} else if (process) {
DrawGL.drawGL(mDrawGL, mViewContext, width, height, 0, 0, MODE_PROCESS);
}
if (waitForCompletion) {
synchronized (mSyncLock) {
mWaitForCompletion = false;
mSyncLock.notifyAll();
}
}
}
}
public AwTestContainerView(Context context, boolean hardwareAccelerated) {
super(context);
if (hardwareAccelerated) {
mHardwareView = new HardwareView(context);
addView(mHardwareView,
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
}
mNativeGLDelegate = new NativeGLDelegate();
mInternalAccessDelegate = new InternalAccessAdapter();
setOverScrollMode(View.OVER_SCROLL_ALWAYS);
......@@ -43,6 +222,10 @@ public class AwTestContainerView extends FrameLayout {
public void initialize(AwContents awContents) {
mAwContents = awContents;
if (mHardwareView != null) {
mHardwareView.initialize(
mAwContents.getAwDrawGLFunction(), mAwContents.getAwDrawGLViewContext());
}
}
public ContentViewCore getContentViewCore() {
......@@ -74,13 +257,28 @@ public class AwTestContainerView extends FrameLayout {
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mAwContents.onAttachedToWindow();
if (mHardwareView == null || mHardwareView.isReadyToRender()) {
mAwContents.onAttachedToWindow();
mAttachedContents = true;
} else {
mHardwareView.setReadyToRenderCallback(new Runnable() {
public void run() {
assert !mAttachedContents;
mAwContents.onAttachedToWindow();
mAttachedContents = true;
}
});
}
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAwContents.onDetachedFromWindow();
if (mHardwareView != null) {
mHardwareView.setReadyToRenderCallback(null);
}
mAttachedContents = false;
}
@Override
......@@ -107,6 +305,7 @@ public class AwTestContainerView extends FrameLayout {
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
......@@ -153,6 +352,9 @@ public class AwTestContainerView extends FrameLayout {
@Override
public void onDraw(Canvas canvas) {
if (mHardwareView != null) {
mHardwareView.updateScroll(getScrollX(), getScrollY());
}
mAwContents.onDraw(canvas);
super.onDraw(canvas);
}
......@@ -183,11 +385,13 @@ public class AwTestContainerView extends FrameLayout {
return mAwContents.performAccessibilityAction(action, arguments);
}
private static class NativeGLDelegate implements AwContents.NativeGLDelegate {
private class NativeGLDelegate implements AwContents.NativeGLDelegate {
@Override
public boolean requestDrawGL(Canvas canvas, boolean waitForCompletion,
View containerview) {
return false;
if (mHardwareView == null) return false;
mHardwareView.requestRender(canvas, waitForCompletion);
return true;
}
@Override
......@@ -234,6 +438,12 @@ public class AwTestContainerView extends FrameLayout {
public void super_scrollTo(int scrollX, int scrollY) {
// We're intentionally not calling super.scrollTo here to make testing easier.
AwTestContainerView.this.scrollTo(scrollX, scrollY);
if (mHardwareView != null) {
// Undo the scroll that will be applied because of mHardwareView
// being a child of |this|.
mHardwareView.setTranslationX(scrollX);
mHardwareView.setTranslationY(scrollY);
}
}
@Override
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment