diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoSurfaceTexture.java | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoSurfaceTexture.java')
-rw-r--r-- | mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoSurfaceTexture.java | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoSurfaceTexture.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoSurfaceTexture.java new file mode 100644 index 0000000000..2d045edb44 --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoSurfaceTexture.java @@ -0,0 +1,330 @@ +/* -*- 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.graphics.SurfaceTexture; +import android.os.Build; +import android.util.Log; +import android.util.LongSparseArray; +import androidx.annotation.RequiresApi; +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicInteger; +import org.mozilla.gecko.GeckoAppShell; +import org.mozilla.gecko.annotation.WrapForJNI; +import org.mozilla.gecko.mozglue.JNIObject; + +/* package */ final class GeckoSurfaceTexture extends SurfaceTexture { + private static final String LOGTAG = "GeckoSurfaceTexture"; + private static final int MAX_SURFACE_TEXTURES = 200; + private static final LongSparseArray<GeckoSurfaceTexture> sSurfaceTextures = + new LongSparseArray<GeckoSurfaceTexture>(); + + private static LongSparseArray<LinkedList<GeckoSurfaceTexture>> sUnusedTextures = + new LongSparseArray<LinkedList<GeckoSurfaceTexture>>(); + + private long mHandle; + private boolean mIsSingleBuffer; + + private long mAttachedContext; + private int mTexName; + + private GeckoSurfaceTexture.Callbacks mListener; + private AtomicInteger mUseCount; + private boolean mFinalized; + + private long mUpstream; + private NativeGLBlitHelper mBlitter; + + private GeckoSurfaceTexture(final long handle) { + super(0); + init(handle, false); + } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private GeckoSurfaceTexture(final long handle, final boolean singleBufferMode) { + super(0, singleBufferMode); + init(handle, singleBufferMode); + } + + @Override + protected void finalize() throws Throwable { + // We only want finalize() to be called once + if (mFinalized) { + return; + } + + mFinalized = true; + super.finalize(); + } + + private void init(final long handle, final boolean singleBufferMode) { + mHandle = handle; + mIsSingleBuffer = singleBufferMode; + mUseCount = new AtomicInteger(1); + + // Start off detached + detachFromGLContext(); + } + + @WrapForJNI + public long getHandle() { + return mHandle; + } + + @WrapForJNI + public int getTexName() { + return mTexName; + } + + @WrapForJNI(exceptionMode = "nsresult") + public synchronized void attachToGLContext(final long context, final int texName) { + if (context == mAttachedContext && texName == mTexName) { + return; + } + + attachToGLContext(texName); + + mAttachedContext = context; + mTexName = texName; + } + + @Override + @WrapForJNI(exceptionMode = "nsresult") + public synchronized void detachFromGLContext() { + super.detachFromGLContext(); + + mAttachedContext = mTexName = 0; + } + + @WrapForJNI + public synchronized boolean isAttachedToGLContext(final long context) { + return mAttachedContext == context; + } + + @WrapForJNI + public boolean isSingleBuffer() { + return mIsSingleBuffer; + } + + @Override + @WrapForJNI + public synchronized void updateTexImage() { + try { + if (mUpstream != 0) { + SurfaceAllocator.sync(mUpstream); + } + super.updateTexImage(); + if (mListener != null) { + mListener.onUpdateTexImage(); + } + } catch (final Exception e) { + Log.w(LOGTAG, "updateTexImage() failed", e); + } + } + + @Override + public synchronized void release() { + mUpstream = 0; + if (mBlitter != null) { + mBlitter.close(); + } + try { + super.release(); + synchronized (sSurfaceTextures) { + sSurfaceTextures.remove(mHandle); + } + } catch (final Exception e) { + Log.w(LOGTAG, "release() failed", e); + } + } + + @Override + @WrapForJNI + public synchronized void releaseTexImage() { + if (!mIsSingleBuffer) { + return; + } + + try { + super.releaseTexImage(); + if (mListener != null) { + mListener.onReleaseTexImage(); + } + } catch (final Exception e) { + Log.w(LOGTAG, "releaseTexImage() failed", e); + } + } + + public synchronized void setListener(final GeckoSurfaceTexture.Callbacks listener) { + mListener = listener; + } + + @WrapForJNI + public static boolean isSingleBufferSupported() { + return Build.VERSION.SDK_INT >= 19; + } + + @WrapForJNI + public synchronized void incrementUse() { + mUseCount.incrementAndGet(); + } + + @WrapForJNI + public synchronized void decrementUse() { + final int useCount = mUseCount.decrementAndGet(); + + if (useCount == 0) { + setListener(null); + + if (mAttachedContext == 0) { + release(); + synchronized (sUnusedTextures) { + sSurfaceTextures.remove(mHandle); + } + return; + } + + synchronized (sUnusedTextures) { + LinkedList<GeckoSurfaceTexture> list = sUnusedTextures.get(mAttachedContext); + if (list == null) { + list = new LinkedList<GeckoSurfaceTexture>(); + sUnusedTextures.put(mAttachedContext, list); + } + list.addFirst(this); + } + } + } + + @WrapForJNI + public static void destroyUnused(final long context) { + final LinkedList<GeckoSurfaceTexture> list; + synchronized (sUnusedTextures) { + list = sUnusedTextures.get(context); + sUnusedTextures.delete(context); + } + + if (list == null) { + return; + } + + for (final GeckoSurfaceTexture tex : list) { + try { + if (tex.isSingleBuffer()) { + tex.releaseTexImage(); + } + + tex.detachFromGLContext(); + tex.release(); + + // We need to manually call finalize here, otherwise we can run out + // of file descriptors if the GC doesn't kick in soon enough. Bug 1416015. + try { + tex.finalize(); + } catch (final Throwable t) { + Log.e(LOGTAG, "Failed to finalize SurfaceTexture", t); + } + } catch (final Exception e) { + Log.e(LOGTAG, "Failed to destroy SurfaceTexture", e); + } + } + } + + public static GeckoSurfaceTexture acquire(final boolean singleBufferMode, final long handle) { + if (singleBufferMode && !isSingleBufferSupported()) { + throw new IllegalArgumentException("single buffer mode not supported on API version < 19"); + } + + // Attempting to create a SurfaceTexture from an isolated process on Android versions prior to + // 8.0 results in an indefinite hang. See bug 1706656. + if (GeckoAppShell.isIsolatedProcess() && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return null; + } + + synchronized (sSurfaceTextures) { + // We want to limit the maximum number of SurfaceTextures at any one time. + // This is because they use a large number of fds, and once the process' limit + // is reached bad things happen. See bug 1421586. + if (sSurfaceTextures.size() >= MAX_SURFACE_TEXTURES) { + return null; + } + + if (sSurfaceTextures.indexOfKey(handle) >= 0) { + throw new IllegalArgumentException("Already have a GeckoSurfaceTexture with that handle"); + } + + final GeckoSurfaceTexture gst; + if (isSingleBufferSupported()) { + gst = new GeckoSurfaceTexture(handle, singleBufferMode); + } else { + gst = new GeckoSurfaceTexture(handle); + } + + sSurfaceTextures.put(handle, gst); + + return gst; + } + } + + @WrapForJNI + public static GeckoSurfaceTexture lookup(final long handle) { + synchronized (sSurfaceTextures) { + return sSurfaceTextures.get(handle); + } + } + + /* package */ synchronized void track(final long upstream) { + mUpstream = upstream; + } + + /* package */ synchronized void configureSnapshot( + final GeckoSurface target, final int width, final int height) { + mBlitter = NativeGLBlitHelper.create(mHandle, target, width, height); + } + + /* package */ synchronized void takeSnapshot() { + mBlitter.blit(); + } + + public interface Callbacks { + void onUpdateTexImage(); + + void onReleaseTexImage(); + } + + @WrapForJNI + public static final class NativeGLBlitHelper extends JNIObject { + public static NativeGLBlitHelper create( + final long textureHandle, + final GeckoSurface targetSurface, + final int width, + final int height) { + final NativeGLBlitHelper helper = nativeCreate(textureHandle, targetSurface, width, height); + helper.mTargetSurface = targetSurface; // Take ownership of surface. + return helper; + } + + public static native NativeGLBlitHelper nativeCreate( + final long textureHandle, + final GeckoSurface targetSurface, + final int width, + final int height); + + public native void blit(); + + public void close() { + disposeNative(); + if (mTargetSurface != null) { + mTargetSurface.release(); + mTargetSurface = null; + } + } + + @Override + protected native void disposeNative(); + + private GeckoSurface mTargetSurface; + } +} |