Disable hardware acceleration on Android

It serves no purpose and causes tearing.  Uploading the bitmap
to the GPU takes about as long as it does to incrementally
update the surface in software.

* java/AndroidManifest.xml.in: Disable hardware acceleration.
* java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): Make
lastClosedMenu static.
* java/org/gnu/emacs/EmacsDialog.java (toAlertDialog): Enable
hardware acceleration within alert dialogs.
* java/org/gnu/emacs/EmacsSurfaceView.java (onDraw): Describe
why hardware acceleration is disabled.
* java/org/gnu/emacs/EmacsWindow.java (run): Remove redundant
call.
This commit is contained in:
Po Lu 2023-07-13 12:05:50 +08:00
parent 4e2fda28ed
commit 140755f2cf
5 changed files with 39 additions and 4 deletions

View file

@ -77,10 +77,14 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
@ANDROID_SHARED_USER_ID@
android:extractNativeLibs="true">
<!-- See EmacsSurfaceView.onDraw for why hardware acceleration is
disabled. -->
<activity android:name="org.gnu.emacs.EmacsActivity"
android:launchMode="singleInstance"
android:windowSoftInputMode="adjustResize"
android:exported="true"
android:hardwareAccelerated="false"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -173,6 +177,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
<activity android:name="org.gnu.emacs.EmacsMultitaskActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true"
android:hardwareAccelerated="false"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"/>
<activity android:autoRemoveFromRecents="true"

View file

@ -70,7 +70,7 @@ public class EmacsActivity extends Activity
private boolean isFullscreen;
/* The last context menu to be closed. */
private Menu lastClosedMenu;
private static Menu lastClosedMenu;
static
{

View file

@ -152,7 +152,7 @@ private final class EmacsButton implements View.OnClickListener,
toAlertDialog (Context context)
{
AlertDialog dialog;
int size, styleId;
int size, styleId, flag;
int[] attrs;
EmacsButton button;
EmacsDialogButtonLayout layout;
@ -160,6 +160,7 @@ private final class EmacsButton implements View.OnClickListener,
ViewGroup.LayoutParams layoutParams;
Theme theme;
TypedArray attributes;
Window window;
size = buttons.size ();
styleId = -1;
@ -273,6 +274,17 @@ private final class EmacsButton implements View.OnClickListener,
}
}
/* Make sure the dialog is hardware accelerated. Hardware
acceleration is disabled for dialogs by default, because they
aren't enabled in EmacsActivity either. */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
{
flag = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
window = dialog.getWindow ();
window.addFlags (flag);
}
return dialog;
}

View file

@ -176,7 +176,25 @@ else if (bitmap != null)
onDraw (Canvas canvas)
{
/* Paint the view's bitmap; the bitmap might be recycled right
now. */
now.
Hardware acceleration is disabled in AndroidManifest.xml to
prevent Android from uploading the front buffer to the GPU from
a separate thread. This is important for two reasons: first,
the GPU command queue uses a massive amount of memory (dozens
of MiB) to upload bitmaps to the GPU, regardless of how much of
the bitmap has actually changed.
Secondly, asynchronous texturization leads to race conditions
when a buffer swap occurs before the front buffer is fully
uploaded to the GPU. Normally, only slight and tolerable
tearing should result from this behavior, but Android does not
properly interlock the ``generation ID'' used to avoid
texturizing unchanged bitmaps with the bitmap contents,
consequentially leading to textures in an incomplete state
remaining in use to the GPU if a buffer swap happens between
the image data being uploaded and the ``generation ID'' being
read. */
if (frontBuffer != null)
canvas.drawBitmap (frontBuffer, 0f, 0f, uiThreadPaint);

View file

@ -1377,7 +1377,7 @@ else if (EmacsWindow.this.isMapped)
if (tem != null)
{
activity = (EmacsActivity) getAttachedConsumer ();
activity = (EmacsActivity) tem;
activity.syncFullscreenWith (EmacsWindow.this);
}
}