Use lock instead of afterOverlayGlDrawn

pull/528/head
Mattia Iavarone 6 years ago
parent d6eea6e08f
commit 9fa43a1120
  1. 16
      cameraview/src/main/java/com/otaliastudios/cameraview/internal/Issue514Workaround.java
  2. 37
      cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayDrawer.java

@ -80,18 +80,14 @@ import com.otaliastudios.cameraview.preview.RendererThread;
* *
* This makes no sense, since overlaySurfaceTexture.updateTexImage() is setting it to overlayTextureId, * 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 * 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 * - {@link #beforeOverlayUpdateTexImage()} to be called before the {@link SurfaceTexture#updateTexImage()} call
* when updateTexImage() is called we have bound the cameraTextureId, and to avoid using a lock, * - {@link #end()} to release and bring things back to normal state
* 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
* *
* If filling the texture and rendering happen on two different threads (with a shared EGL context) * Since updating and rendering can happen on different threads with a shared EGL context,
* there is still a chance that updateTexImage() is called with a current texture that creates this * in case they do, the {@link #beforeOverlayUpdateTexImage()}, the actual updateTexImage() and
* issue (0?), but the alternative would be creating a lock. * finally the {@link EglViewport} drawing operations should be synchronized with a lock.
* *
* REFERENCES * REFERENCES
* https://android.googlesource.com/platform/frameworks/native/+/5c1139f/libs/gui/SurfaceTexture.cpp * https://android.googlesource.com/platform/frameworks/native/+/5c1139f/libs/gui/SurfaceTexture.cpp

@ -4,6 +4,8 @@ import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.view.Surface; import android.view.Surface;
import androidx.annotation.NonNull; 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.internal.egl.EglViewport;
import com.otaliastudios.cameraview.size.Size; 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 { public class OverlayDrawer {
private static final String TAG = OverlayDrawer.class.getSimpleName(); private static final String TAG = OverlayDrawer.class.getSimpleName();
@ -22,9 +42,10 @@ public class OverlayDrawer {
private int mTextureId; private int mTextureId;
private SurfaceTexture mSurfaceTexture; private SurfaceTexture mSurfaceTexture;
private Surface mSurface; private Surface mSurface;
private float[] mTransform = new float[16];
private EglViewport mViewport; private EglViewport mViewport;
private Issue514Workaround mIssue514Workaround; 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) { public OverlayDrawer(@NonNull Overlay overlay, @NonNull Size size, int cameraTextureId) {
mOverlay = overlay; mOverlay = overlay;
@ -46,8 +67,10 @@ public class OverlayDrawer {
} catch (Surface.OutOfResourcesException e) { } catch (Surface.OutOfResourcesException e) {
LOG.w("Got Surface.OutOfResourcesException while drawing video overlays", e); LOG.w("Got Surface.OutOfResourcesException while drawing video overlays", e);
} }
mIssue514Workaround.beforeOverlayUpdateTexImage(); synchronized (mIssue514WorkaroundLock) {
mSurfaceTexture.updateTexImage(); mIssue514Workaround.beforeOverlayUpdateTexImage();
mSurfaceTexture.updateTexImage();
}
mSurfaceTexture.getTransformMatrix(mTransform); mSurfaceTexture.getTransformMatrix(mTransform);
} }
@ -56,9 +79,11 @@ public class OverlayDrawer {
} }
public void render() { public void render() {
mIssue514Workaround.afterOverlayGlDrawn(); synchronized (mIssue514WorkaroundLock) {
mViewport.drawFrame(mTextureId, mTransform); mViewport.drawFrame(mTextureId, mTransform);
mIssue514Workaround.afterOverlayGlDrawn(); }
// mIssue514Workaround.afterOverlayGlDrawn();
// mIssue514Workaround.afterOverlayGlDrawn();
} }
public void release() { public void release() {

Loading…
Cancel
Save