Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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;
}
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);
}
}
}