summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java')
-rw-r--r--mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java143
1 files changed, 143 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java
new file mode 100644
index 0000000000..89fba6c2f9
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java
@@ -0,0 +1,143 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.gfx;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.LongSparseArray;
+import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.annotation.WrapForJNI;
+import org.mozilla.gecko.process.GeckoProcessManager;
+import org.mozilla.gecko.process.GeckoServiceChildProcess;
+
+/* package */ final class SurfaceAllocator {
+ private static final String LOGTAG = "SurfaceAllocator";
+
+ private static ISurfaceAllocator sAllocator;
+
+ // Keep a reference to all allocated Surfaces, so that we can release them if we lose the
+ // connection to the allocator service.
+ private static final LongSparseArray<GeckoSurface> sSurfaces =
+ new LongSparseArray<GeckoSurface>();
+
+ private static synchronized void ensureConnection() {
+ if (sAllocator != null) {
+ return;
+ }
+
+ try {
+ if (GeckoAppShell.isParentProcess()) {
+ sAllocator = GeckoProcessManager.getInstance().getSurfaceAllocator();
+ } else {
+ sAllocator = GeckoServiceChildProcess.getSurfaceAllocator();
+ }
+
+ if (sAllocator == null) {
+ Log.w(LOGTAG, "Failed to connect to RemoteSurfaceAllocator");
+ return;
+ }
+ sAllocator
+ .asBinder()
+ .linkToDeath(
+ new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ Log.w(LOGTAG, "RemoteSurfaceAllocator died");
+ synchronized (SurfaceAllocator.class) {
+ // Our connection to the remote allocator has died, so all our surfaces are
+ // invalid. Release them all now. When their owners attempt to render in to
+ // them they can detect they have been released and allocate new ones instead.
+ for (int i = 0; i < sSurfaces.size(); i++) {
+ sSurfaces.valueAt(i).release();
+ }
+ sSurfaces.clear();
+ sAllocator = null;
+ }
+ }
+ },
+ 0);
+ } catch (final RemoteException e) {
+ Log.w(LOGTAG, "Failed to connect to RemoteSurfaceAllocator", e);
+ sAllocator = null;
+ }
+ }
+
+ @WrapForJNI
+ public static synchronized GeckoSurface acquireSurface(
+ final int width, final int height, final boolean singleBufferMode) {
+ try {
+ ensureConnection();
+
+ if (sAllocator == null) {
+ Log.w(LOGTAG, "Failed to acquire GeckoSurface: not connected");
+ return null;
+ }
+
+ if (singleBufferMode && !GeckoSurfaceTexture.isSingleBufferSupported()) {
+ return null;
+ }
+
+ final GeckoSurface surface = sAllocator.acquireSurface(width, height, singleBufferMode);
+ if (surface == null) {
+ Log.w(LOGTAG, "Failed to acquire GeckoSurface: RemoteSurfaceAllocator returned null");
+ return null;
+ }
+ sSurfaces.put(surface.getHandle(), surface);
+
+ if (!surface.inProcess()) {
+ final SyncConfig config = surface.initSyncSurface(width, height);
+ if (config != null) {
+ sAllocator.configureSync(config);
+ }
+ }
+ return surface;
+ } catch (final RemoteException e) {
+ Log.w(LOGTAG, "Failed to acquire GeckoSurface", e);
+ return null;
+ }
+ }
+
+ @WrapForJNI
+ public static synchronized void disposeSurface(final GeckoSurface surface) {
+ // If the surface has already been released (probably due to losing connection to the remote
+ // allocator) then there is nothing to do here.
+ if (surface.isReleased()) {
+ return;
+ }
+
+ sSurfaces.remove(surface.getHandle());
+
+ // Release our Surface
+ surface.release();
+
+ if (sAllocator == null) {
+ return;
+ }
+
+ // Release the SurfaceTexture on the other side. If we have lost connection then do nothing, as
+ // there is nothing on the other side to release.
+ try {
+ if (sAllocator != null) {
+ sAllocator.releaseSurface(surface.getHandle());
+ }
+ } catch (final RemoteException e) {
+ Log.w(LOGTAG, "Failed to release surface texture", e);
+ }
+ }
+
+ public static synchronized void sync(final long upstream) {
+ // Sync from the SurfaceTexture on the other side. If we have lost connection then do nothing,
+ // as there is nothing on the other side to sync from.
+ try {
+ if (sAllocator != null) {
+ sAllocator.sync(upstream);
+ }
+ } catch (final RemoteException e) {
+ Log.w(LOGTAG, "Failed to sync texture", e);
+ }
+ }
+}