diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/Issue514Workaround.java b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/Issue514Workaround.java index 62733a5a..c794bb1c 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/Issue514Workaround.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/Issue514Workaround.java @@ -80,18 +80,14 @@ import com.otaliastudios.cameraview.preview.RendererThread; * * This makes no sense, since overlaySurfaceTexture.updateTexImage() is setting it to overlayTextureId, * but it fixes the issue. Specifically, after any draw operation with {@link EglViewport}, the bound - * texture is reset to 0. + * texture is reset to 0 so this must be undone here. We offer: * - * So, since updating and drawing can happen on different threads, to maximize the chances that - * when updateTexImage() is called we have bound the cameraTextureId, and to avoid using a lock, - * we require to call - * - {@link #beforeOverlayUpdateTexImage()} right before the {@link SurfaceTexture#updateTexImage()} call - * - {@link #afterOverlayGlDrawn()} right after the last {@link EglViewport#drawFrame(int, float[])} call - * - {@link #end()} to release + * - {@link #beforeOverlayUpdateTexImage()} to be called before the {@link SurfaceTexture#updateTexImage()} call + * - {@link #end()} to release and bring things back to normal state * - * If filling the texture and rendering happen on two different threads (with a shared EGL context) - * there is still a chance that updateTexImage() is called with a current texture that creates this - * issue (0?), but the alternative would be creating a lock. + * Since updating and rendering can happen on different threads with a shared EGL context, + * in case they do, the {@link #beforeOverlayUpdateTexImage()}, the actual updateTexImage() and + * finally the {@link EglViewport} drawing operations should be synchronized with a lock. * * REFERENCES * https://android.googlesource.com/platform/frameworks/native/+/5c1139f/libs/gui/SurfaceTexture.cpp diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayDrawer.java b/cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayDrawer.java index 06bd74c9..16b23aed 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayDrawer.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayDrawer.java @@ -4,6 +4,8 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.SurfaceTexture; +import android.opengl.GLES11Ext; +import android.opengl.GLES20; import android.view.Surface; import androidx.annotation.NonNull; @@ -13,6 +15,24 @@ import com.otaliastudios.cameraview.internal.Issue514Workaround; import com.otaliastudios.cameraview.internal.egl.EglViewport; import com.otaliastudios.cameraview.size.Size; +import java.nio.Buffer; + + +/** + * Draws overlays through {@link Overlay}. + * + * - Provides a {@link Canvas} to be passed to the Overlay + * - Lets the overlay draw there: {@link #draw(Overlay.Target)} + * - Renders this into the current EGL window: {@link #render()} + * - Applies the {@link Issue514Workaround} the correct way + * + * In the future we might want to use a different approach than {@link EglViewport}, + * {@link SurfaceTexture} and {@link GLES11Ext#GL_TEXTURE_EXTERNAL_OES}, + * for example by using a regular {@link GLES20#GL_TEXTURE_2D} that might + * be filled through {@link GLES20#glTexImage2D(int, int, int, int, int, int, int, int, Buffer)}. + * + * The current approach has some issues, for example see {@link Issue514Workaround}. + */ public class OverlayDrawer { private static final String TAG = OverlayDrawer.class.getSimpleName(); @@ -22,9 +42,10 @@ public class OverlayDrawer { private int mTextureId; private SurfaceTexture mSurfaceTexture; private Surface mSurface; + private float[] mTransform = new float[16]; private EglViewport mViewport; private Issue514Workaround mIssue514Workaround; - private float[] mTransform = new float[16]; + private final Object mIssue514WorkaroundLock = new Object(); public OverlayDrawer(@NonNull Overlay overlay, @NonNull Size size, int cameraTextureId) { mOverlay = overlay; @@ -46,8 +67,10 @@ public class OverlayDrawer { } catch (Surface.OutOfResourcesException e) { LOG.w("Got Surface.OutOfResourcesException while drawing video overlays", e); } - mIssue514Workaround.beforeOverlayUpdateTexImage(); - mSurfaceTexture.updateTexImage(); + synchronized (mIssue514WorkaroundLock) { + mIssue514Workaround.beforeOverlayUpdateTexImage(); + mSurfaceTexture.updateTexImage(); + } mSurfaceTexture.getTransformMatrix(mTransform); } @@ -56,9 +79,11 @@ public class OverlayDrawer { } public void render() { - mIssue514Workaround.afterOverlayGlDrawn(); - mViewport.drawFrame(mTextureId, mTransform); - mIssue514Workaround.afterOverlayGlDrawn(); + synchronized (mIssue514WorkaroundLock) { + mViewport.drawFrame(mTextureId, mTransform); + } + // mIssue514Workaround.afterOverlayGlDrawn(); + // mIssue514Workaround.afterOverlayGlDrawn(); } public void release() {