1feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk/*
228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk * Copyright (C) 2014 The Android Open Source Project
328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk *
428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk * you may not use this file except in compliance with the License.
628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk * You may obtain a copy of the License at
728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk *
828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk *
1028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk * Unless required by applicable law or agreed to in writing, software
1128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
1228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk * See the License for the specific language governing permissions and
1428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk * limitations under the License.
1528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk */
16feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkpackage android.hardware.camera2.legacy;
17feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
18feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.graphics.ImageFormat;
19a9bc3559109836efe7479a3279713bd58810b153Ruben Brunkimport android.graphics.RectF;
20feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.graphics.SurfaceTexture;
21b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunkimport android.hardware.camera2.CameraCharacteristics;
22e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvalaimport android.os.Environment;
23feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.opengl.EGL14;
24feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.opengl.EGLConfig;
25feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.opengl.EGLContext;
26feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.opengl.EGLDisplay;
27feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.opengl.EGLSurface;
28feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.opengl.GLES11Ext;
29feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.opengl.GLES20;
30feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.opengl.Matrix;
31e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvalaimport android.text.format.Time;
32feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.util.Log;
3391838ded36131525312739c0929913b215519c2aRuben Brunkimport android.util.Pair;
34ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunkimport android.util.Size;
35feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.view.Surface;
36e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvalaimport android.os.SystemProperties;
37feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
38e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvalaimport java.io.File;
39feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.nio.ByteBuffer;
40feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.nio.ByteOrder;
41feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.nio.FloatBuffer;
42feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.util.ArrayList;
43feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.util.Collection;
44feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.util.List;
45feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
46feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk/**
47feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * A renderer class that manages the GL state, and can draw a frame into a set of output
48feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * {@link Surface}s.
49feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk */
50feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkpublic class SurfaceTextureRenderer {
51feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final String TAG = SurfaceTextureRenderer.class.getSimpleName();
52feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG);
53feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int EGL_RECORDABLE_ANDROID = 0x3142; // from EGL/eglext.h
54feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int GL_MATRIX_SIZE = 16;
55feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int VERTEX_POS_SIZE = 3;
56feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int VERTEX_UV_SIZE = 2;
57feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int EGL_COLOR_BITLENGTH = 8;
58feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int GLES_VERSION = 2;
59feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int PBUFFER_PIXEL_BYTES = 4;
60feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
61433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private static final int FLIP_TYPE_NONE = 0;
62433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private static final int FLIP_TYPE_HORIZONTAL = 1;
63433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private static final int FLIP_TYPE_VERTICAL = 2;
64433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private static final int FLIP_TYPE_BOTH = FLIP_TYPE_HORIZONTAL | FLIP_TYPE_VERTICAL;
65433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
66feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
67feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;
68feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private EGLConfig mConfigs;
69feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
70feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private class EGLSurfaceHolder {
71feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        Surface surface;
72feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        EGLSurface eglSurface;
73feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int width;
74feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int height;
75feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
76feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
77feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private List<EGLSurfaceHolder> mSurfaces = new ArrayList<EGLSurfaceHolder>();
78feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private List<EGLSurfaceHolder> mConversionSurfaces = new ArrayList<EGLSurfaceHolder>();
79feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
80feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private ByteBuffer mPBufferPixels;
81feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
82feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    // Hold this to avoid GC
83feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private volatile SurfaceTexture mSurfaceTexture;
84feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
85feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int FLOAT_SIZE_BYTES = 4;
86feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
87feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
88feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
89b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk
90433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    // Sampling is mirrored across the horizontal axis
91433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private static final float[] sHorizontalFlipTriangleVertices = {
92b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk            // X, Y, Z, U, V
93b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk            -1.0f, -1.0f, 0, 1.f, 0.f,
94b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk            1.0f, -1.0f, 0, 0.f, 0.f,
95b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk            -1.0f,  1.0f, 0, 1.f, 1.f,
96b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk            1.0f,  1.0f, 0, 0.f, 1.f,
97b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk    };
98b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk
99433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    // Sampling is mirrored across the vertical axis
100433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private static final float[] sVerticalFlipTriangleVertices = {
101433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            // X, Y, Z, U, V
102433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            -1.0f, -1.0f, 0, 0.f, 1.f,
103433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            1.0f, -1.0f, 0, 1.f, 1.f,
104433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            -1.0f,  1.0f, 0, 0.f, 0.f,
105433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            1.0f,  1.0f, 0, 1.f, 0.f,
106433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    };
107433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
108433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    // Sampling is mirrored across the both axes
109433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private static final float[] sBothFlipTriangleVertices = {
110433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            // X, Y, Z, U, V
111433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            -1.0f, -1.0f, 0, 1.f, 1.f,
112433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            1.0f, -1.0f, 0, 0.f, 1.f,
113433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            -1.0f,  1.0f, 0, 1.f, 0.f,
114433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            1.0f,  1.0f, 0, 0.f, 0.f,
115433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    };
116433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
117b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk    // Sampling is 1:1 for a straight copy for the back camera
118433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private static final float[] sRegularTriangleVertices = {
119feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            // X, Y, Z, U, V
120feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            -1.0f, -1.0f, 0, 0.f, 0.f,
121feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            1.0f, -1.0f, 0, 1.f, 0.f,
122feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            -1.0f,  1.0f, 0, 0.f, 1.f,
123feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            1.0f,  1.0f, 0, 1.f, 1.f,
124feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    };
125feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
126433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private FloatBuffer mRegularTriangleVertices;
127433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private FloatBuffer mHorizontalFlipTriangleVertices;
128433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private FloatBuffer mVerticalFlipTriangleVertices;
129433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private FloatBuffer mBothFlipTriangleVertices;
130433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private final int mFacing;
131feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
132feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
133feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * As used in this file, this vertex shader maps a unit square to the view, and
134feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * tells the fragment shader to interpolate over it.  Each surface pixel position
135feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * is mapped to a 2D homogeneous texture coordinate of the form (s, t, 0, 1) with
136feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * s and t in the inclusive range [0, 1], and the matrix from
137feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * {@link SurfaceTexture#getTransformMatrix(float[])} is used to map this
138feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * coordinate to a texture location.
139feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
140feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final String VERTEX_SHADER =
141feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            "uniform mat4 uMVPMatrix;\n" +
14228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "uniform mat4 uSTMatrix;\n" +
14328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "attribute vec4 aPosition;\n" +
14428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "attribute vec4 aTextureCoord;\n" +
14528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "varying vec2 vTextureCoord;\n" +
14628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "void main() {\n" +
14728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "  gl_Position = uMVPMatrix * aPosition;\n" +
14828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "  vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
14928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "}\n";
150feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
151feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
152feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * This fragment shader simply draws the color in the 2D texture at
153feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * the location from the {@code VERTEX_SHADER}.
154feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
155feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final String FRAGMENT_SHADER =
156feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            "#extension GL_OES_EGL_image_external : require\n" +
15728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "precision mediump float;\n" +
15828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "varying vec2 vTextureCoord;\n" +
15928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "uniform samplerExternalOES sTexture;\n" +
16028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "void main() {\n" +
16128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
16228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            "}\n";
163feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
164feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private float[] mMVPMatrix = new float[GL_MATRIX_SIZE];
165feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private float[] mSTMatrix = new float[GL_MATRIX_SIZE];
166feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
167feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int mProgram;
168feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int mTextureID = 0;
169feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int muMVPMatrixHandle;
170feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int muSTMatrixHandle;
171feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int maPositionHandle;
172feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int maTextureHandle;
173feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
174e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private PerfMeasurement mPerfMeasurer = null;
175e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private static final String LEGACY_PERF_PROPERTY = "persist.camera.legacy_perf";
176e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
177b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk    public SurfaceTextureRenderer(int facing) {
178433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        mFacing = facing;
179433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
180433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        mRegularTriangleVertices = ByteBuffer.allocateDirect(sRegularTriangleVertices.length *
181433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
182433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        mRegularTriangleVertices.put(sRegularTriangleVertices).position(0);
183433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
184433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        mHorizontalFlipTriangleVertices = ByteBuffer.allocateDirect(
185433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                sHorizontalFlipTriangleVertices.length * FLOAT_SIZE_BYTES).
186433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                order(ByteOrder.nativeOrder()).asFloatBuffer();
187433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        mHorizontalFlipTriangleVertices.put(sHorizontalFlipTriangleVertices).position(0);
188433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
189433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        mVerticalFlipTriangleVertices = ByteBuffer.allocateDirect(
190433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                sVerticalFlipTriangleVertices.length * FLOAT_SIZE_BYTES).
191433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                order(ByteOrder.nativeOrder()).asFloatBuffer();
192433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        mVerticalFlipTriangleVertices.put(sVerticalFlipTriangleVertices).position(0);
193433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
194433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        mBothFlipTriangleVertices = ByteBuffer.allocateDirect(
195433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                sBothFlipTriangleVertices.length * FLOAT_SIZE_BYTES).
196433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                order(ByteOrder.nativeOrder()).asFloatBuffer();
197433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        mBothFlipTriangleVertices.put(sBothFlipTriangleVertices).position(0);
198433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
199feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        Matrix.setIdentityM(mSTMatrix, 0);
200feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
201feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
202feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int loadShader(int shaderType, String source) {
203feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int shader = GLES20.glCreateShader(shaderType);
204feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glCreateShader type=" + shaderType);
205feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glShaderSource(shader, source);
206feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glCompileShader(shader);
207feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] compiled = new int[1];
208feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
209feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (compiled[0] == 0) {
210feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            Log.e(TAG, "Could not compile shader " + shaderType + ":");
211feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            Log.e(TAG, " " + GLES20.glGetShaderInfoLog(shader));
212feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            GLES20.glDeleteShader(shader);
213feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            // TODO: handle this more gracefully
214feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not compile shader " + shaderType);
215feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
216feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return shader;
217feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
218feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
219feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int createProgram(String vertexSource, String fragmentSource) {
220feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
221feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (vertexShader == 0) {
222feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            return 0;
223feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
224feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
225feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (pixelShader == 0) {
226feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            return 0;
227feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
228feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
229feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int program = GLES20.glCreateProgram();
230feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glCreateProgram");
231feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (program == 0) {
232feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            Log.e(TAG, "Could not create program");
233feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
234feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glAttachShader(program, vertexShader);
235feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glAttachShader");
236feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glAttachShader(program, pixelShader);
237feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glAttachShader");
238feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glLinkProgram(program);
239feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] linkStatus = new int[1];
240feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
241feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (linkStatus[0] != GLES20.GL_TRUE) {
242feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            Log.e(TAG, "Could not link program: ");
243feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            Log.e(TAG, GLES20.glGetProgramInfoLog(program));
244feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            GLES20.glDeleteProgram(program);
245feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            // TODO: handle this more gracefully
246feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not link program");
247feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
248feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return program;
249feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
250feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
251433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk    private void drawFrame(SurfaceTexture st, int width, int height, int flipType) {
252feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("onDrawFrame start");
253feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        st.getTransformMatrix(mSTMatrix);
254feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
255a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        Matrix.setIdentityM(mMVPMatrix, /*smOffset*/0);
256a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk
257a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        // Find intermediate buffer dimensions
25828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        Size dimens;
25928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        try {
26028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            dimens = LegacyCameraDevice.getTextureSize(st);
26128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
26228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            // Should never hit this.
26328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            throw new IllegalStateException("Surface abandoned, skipping drawFrame...", e);
26428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        }
26528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        float texWidth = dimens.getWidth();
26628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        float texHeight = dimens.getHeight();
26728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
26828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        if (texWidth <= 0 || texHeight <= 0) {
26928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            throw new IllegalStateException("Illegal intermediate texture with dimension of 0");
27028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        }
27128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
272259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // Letterbox or pillar-box output dimensions into intermediate dimensions.
273a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        RectF intermediate = new RectF(/*left*/0, /*top*/0, /*right*/texWidth, /*bottom*/texHeight);
274a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        RectF output = new RectF(/*left*/0, /*top*/0, /*right*/width, /*bottom*/height);
275a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        android.graphics.Matrix boxingXform = new android.graphics.Matrix();
276a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        boxingXform.setRectToRect(output, intermediate, android.graphics.Matrix.ScaleToFit.CENTER);
277a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        boxingXform.mapRect(output);
27828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
279259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // Find scaling factor from pillar-boxed/letter-boxed output dimensions to intermediate
280a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        // buffer dimensions.
281a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        float scaleX = intermediate.width() / output.width();
282a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        float scaleY = intermediate.height() / output.height();
28328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
284259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // Intermediate texture is implicitly scaled to 'fill' the output dimensions in clip space
285259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // coordinates in the shader.  To avoid stretching, we need to scale the larger dimension
286259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // of the intermediate buffer so that the output buffer is actually letter-boxed
287259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // or pillar-boxed into the intermediate buffer after clipping.
288259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        Matrix.scaleM(mMVPMatrix, /*offset*/0, /*x*/scaleX, /*y*/scaleY, /*z*/1);
28928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
290feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (DEBUG) {
291a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk            Log.d(TAG, "Scaling factors (S_x = " + scaleX + ",S_y = " + scaleY + ") used for " +
292a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk                    width + "x" + height + " surface, intermediate buffer size is " + texWidth +
293a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk                    "x" + texHeight);
29428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        }
29528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
296a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        // Set viewport to be output buffer dimensions
297a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        GLES20.glViewport(0, 0, width, height);
29828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
29928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        if (DEBUG) {
30028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
301feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
302feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
303feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
304feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glUseProgram(mProgram);
305feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glUseProgram");
306feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
307feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
308feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
309feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
310433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        FloatBuffer triangleVertices;
311433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        switch(flipType) {
312433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            case FLIP_TYPE_HORIZONTAL:
313433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                triangleVertices = mHorizontalFlipTriangleVertices;
314433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                break;
315433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            case FLIP_TYPE_VERTICAL:
316433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                triangleVertices = mVerticalFlipTriangleVertices;
317433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                break;
318433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            case FLIP_TYPE_BOTH:
319433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                triangleVertices = mBothFlipTriangleVertices;
320433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                break;
321433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            default:
322433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                triangleVertices = mRegularTriangleVertices;
323433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                break;
324433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        }
325433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
326433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
327feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glVertexAttribPointer(maPositionHandle, VERTEX_POS_SIZE, GLES20.GL_FLOAT,
328433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
329feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glVertexAttribPointer maPosition");
330feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glEnableVertexAttribArray(maPositionHandle);
331feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glEnableVertexAttribArray maPositionHandle");
332feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
333433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
334feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glVertexAttribPointer(maTextureHandle, VERTEX_UV_SIZE, GLES20.GL_FLOAT,
335433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
336feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glVertexAttribPointer maTextureHandle");
337feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glEnableVertexAttribArray(maTextureHandle);
338feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glEnableVertexAttribArray maTextureHandle");
339feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
340feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, /*count*/ 1, /*transpose*/ false, mMVPMatrix,
341feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                /*offset*/ 0);
342feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glUniformMatrix4fv(muSTMatrixHandle, /*count*/ 1, /*transpose*/ false, mSTMatrix,
343feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                /*offset*/ 0);
344feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
345feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /*offset*/ 0, /*count*/ 4);
346feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glDrawArrays");
347feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
348feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
349feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
350feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Initializes GL state.  Call this after the EGL surface has been created and made current.
351feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
352feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void initializeGLState() {
353feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
354feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mProgram == 0) {
355feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("failed creating program");
356feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
357feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
358feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glGetAttribLocation aPosition");
359feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (maPositionHandle == -1) {
360feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not get attrib location for aPosition");
361feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
362feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
363feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glGetAttribLocation aTextureCoord");
364feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (maTextureHandle == -1) {
365feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not get attrib location for aTextureCoord");
366feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
367feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
368feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
369feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glGetUniformLocation uMVPMatrix");
370feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (muMVPMatrixHandle == -1) {
371feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not get attrib location for uMVPMatrix");
372feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
373feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
374feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
375feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glGetUniformLocation uSTMatrix");
376feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (muSTMatrixHandle == -1) {
377feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not get attrib location for uSTMatrix");
378feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
379feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
380feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] textures = new int[1];
381feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glGenTextures(/*n*/ 1, textures, /*offset*/ 0);
382feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
383feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mTextureID = textures[0];
384feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
385feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glBindTexture mTextureID");
386feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
387feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
388feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                GLES20.GL_NEAREST);
389feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
390feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                GLES20.GL_LINEAR);
391feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
392feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                GLES20.GL_CLAMP_TO_EDGE);
393feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
394feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                GLES20.GL_CLAMP_TO_EDGE);
395feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glTexParameter");
396feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
397feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
398feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int getTextureId() {
399feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return mTextureID;
400feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
401feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
402feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void clearState() {
403feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mSurfaces.clear();
404feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mConversionSurfaces.clear();
405feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mPBufferPixels = null;
4063fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk        if (mSurfaceTexture != null) {
4073fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk            mSurfaceTexture.release();
4083fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk        }
409feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mSurfaceTexture = null;
410feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
411feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
412feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void configureEGLContext() {
413feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
414feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
415feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("No EGL14 display");
416feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
417feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] version = new int[2];
418feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (!EGL14.eglInitialize(mEGLDisplay, version, /*offset*/ 0, version, /*offset*/ 1)) {
419feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Cannot initialize EGL14");
420feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
421feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
422feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] attribList = {
423feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_RED_SIZE, EGL_COLOR_BITLENGTH,
424feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_GREEN_SIZE, EGL_COLOR_BITLENGTH,
425feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_BLUE_SIZE, EGL_COLOR_BITLENGTH,
426feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
427feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL_RECORDABLE_ANDROID, 1,
428feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT | EGL14.EGL_WINDOW_BIT,
429feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_NONE
430feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        };
431feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        EGLConfig[] configs = new EGLConfig[1];
432feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] numConfigs = new int[1];
433feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        EGL14.eglChooseConfig(mEGLDisplay, attribList, /*offset*/ 0, configs, /*offset*/ 0,
434feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                configs.length, numConfigs, /*offset*/ 0);
435feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkEglError("eglCreateContext RGB888+recordable ES2");
436feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mConfigs = configs[0];
437feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] attrib_list = {
438feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
439feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_NONE
440feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        };
441feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
442feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                attrib_list, /*offset*/ 0);
443feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkEglError("eglCreateContext");
444feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if(mEGLContext == EGL14.EGL_NO_CONTEXT) {
445feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("No EGLContext could be made");
446feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
447feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
448feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
449feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void configureEGLOutputSurfaces(Collection<EGLSurfaceHolder> surfaces) {
450feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (surfaces == null || surfaces.size() == 0) {
451feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("No Surfaces were provided to draw to");
452feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
453feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] surfaceAttribs = {
454feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_NONE
455feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        };
456feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        for (EGLSurfaceHolder holder : surfaces) {
457f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            holder.eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs,
458f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    holder.surface, surfaceAttribs, /*offset*/ 0);
459f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            checkEglError("eglCreateWindowSurface");
460feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
461feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
462feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
463feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void configureEGLPbufferSurfaces(Collection<EGLSurfaceHolder> surfaces) {
464feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (surfaces == null || surfaces.size() == 0) {
465feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("No Surfaces were provided to draw to");
466feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
467feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
468feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int maxLength = 0;
469feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        for (EGLSurfaceHolder holder : surfaces) {
470f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            int length = holder.width * holder.height;
471f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            // Find max surface size, ensure PBuffer can hold this many pixels
472f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            maxLength = (length > maxLength) ? length : maxLength;
473f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            int[] surfaceAttribs = {
474f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    EGL14.EGL_WIDTH, holder.width,
475f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    EGL14.EGL_HEIGHT, holder.height,
476f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    EGL14.EGL_NONE
477f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            };
478f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            holder.eglSurface =
479f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    EGL14.eglCreatePbufferSurface(mEGLDisplay, mConfigs, surfaceAttribs, 0);
480f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            checkEglError("eglCreatePbufferSurface");
481feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
482feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mPBufferPixels = ByteBuffer.allocateDirect(maxLength * PBUFFER_PIXEL_BYTES)
483feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                .order(ByteOrder.nativeOrder());
484feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
485feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
486feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void releaseEGLContext() {
487feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
488feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
489feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    EGL14.EGL_NO_CONTEXT);
490e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            dumpGlTiming();
491feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            if (mSurfaces != null) {
492feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                for (EGLSurfaceHolder holder : mSurfaces) {
493feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    if (holder.eglSurface != null) {
494feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                        EGL14.eglDestroySurface(mEGLDisplay, holder.eglSurface);
495feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    }
496feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                }
497feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
498feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            if (mConversionSurfaces != null) {
499feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                for (EGLSurfaceHolder holder : mConversionSurfaces) {
500feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    if (holder.eglSurface != null) {
501feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                        EGL14.eglDestroySurface(mEGLDisplay, holder.eglSurface);
502feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    }
503feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                }
504feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
505feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
506feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            EGL14.eglReleaseThread();
507feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            EGL14.eglTerminate(mEGLDisplay);
508feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
509feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
510feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mConfigs = null;
511feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mEGLDisplay = EGL14.EGL_NO_DISPLAY;
512feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mEGLContext = EGL14.EGL_NO_CONTEXT;
513feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        clearState();
514feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
515feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
516feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void makeCurrent(EGLSurface surface) {
517feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        EGL14.eglMakeCurrent(mEGLDisplay, surface, surface, mEGLContext);
518feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkEglError("makeCurrent");
519feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
520feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
521feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private boolean swapBuffers(EGLSurface surface) {
522feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        boolean result = EGL14.eglSwapBuffers(mEGLDisplay, surface);
523feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkEglError("swapBuffers");
524feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return result;
525feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
526feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
527feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void checkEglError(String msg) {
528feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int error;
529feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
530feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException(msg + ": EGL error: 0x" + Integer.toHexString(error));
531feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
532feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
533feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
534feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void checkGlError(String msg) {
535feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int error;
536feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
537feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException(msg + ": GLES20 error: 0x" + Integer.toHexString(error));
538feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
539feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
540feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
541feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
542e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala     * Save a measurement dump to disk, in
543e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala     * {@code /sdcard/CameraLegacy/durations_<time>_<width1>x<height1>_...txt}
544e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala     */
545e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void dumpGlTiming() {
546e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (mPerfMeasurer == null) return;
547e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
548e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        File legacyStorageDir = new File(Environment.getExternalStorageDirectory(), "CameraLegacy");
549e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (!legacyStorageDir.exists()){
550e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            if (!legacyStorageDir.mkdirs()){
551e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala                Log.e(TAG, "Failed to create directory for data dump");
552e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala                return;
553e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            }
554e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
555e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
556e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        StringBuilder path = new StringBuilder(legacyStorageDir.getPath());
557e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append(File.separator);
558e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append("durations_");
559e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
560e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        Time now = new Time();
561e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        now.setToNow();
562e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append(now.format2445());
563e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append("_S");
564e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        for (EGLSurfaceHolder surface : mSurfaces) {
565e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            path.append(String.format("_%d_%d", surface.width, surface.height));
566e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
567e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append("_C");
568e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        for (EGLSurfaceHolder surface : mConversionSurfaces) {
569e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            path.append(String.format("_%d_%d", surface.width, surface.height));
570e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
571e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append(".txt");
572e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        mPerfMeasurer.dumpPerformanceData(path.toString());
573e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
574e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
575e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void setupGlTiming() {
576e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (PerfMeasurement.isGlTimingSupported()) {
577e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            Log.d(TAG, "Enabling GL performance measurement");
578e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            mPerfMeasurer = new PerfMeasurement();
579e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        } else {
580e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            Log.d(TAG, "GL performance measurement not supported on this device");
581e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            mPerfMeasurer = null;
582e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
583e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
584e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
585e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void beginGlTiming() {
586e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (mPerfMeasurer == null) return;
587e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        mPerfMeasurer.startTimer();
588e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
589e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
590e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void addGlTimestamp(long timestamp) {
591e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (mPerfMeasurer == null) return;
592e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        mPerfMeasurer.addTimestamp(timestamp);
593e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
594e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
595e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void endGlTiming() {
596e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (mPerfMeasurer == null) return;
597e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        mPerfMeasurer.stopTimer();
598e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
599e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
600e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    /**
601feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Return the surface texture to draw to - this is the texture use to when producing output
602feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * surface buffers.
603feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
604feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @return a {@link SurfaceTexture}.
605feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
606feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public SurfaceTexture getSurfaceTexture() {
607feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return mSurfaceTexture;
608feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
609feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
610feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
611feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Set a collection of output {@link Surface}s that can be drawn to.
612feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
613feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param surfaces a {@link Collection} of surfaces.
614feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
615f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk    public void configureSurfaces(Collection<Pair<Surface, Size>> surfaces) {
616feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        releaseEGLContext();
617feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
618d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        if (surfaces == null || surfaces.size() == 0) {
619d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            Log.w(TAG, "No output surfaces configured for GL drawing.");
620d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            return;
621d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        }
622d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk
623f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk        for (Pair<Surface, Size> p : surfaces) {
624f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            Surface s = p.first;
625f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            Size surfaceSize = p.second;
626feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            // If pixel conversions aren't handled by egl, use a pbuffer
627ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            try {
628f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                EGLSurfaceHolder holder = new EGLSurfaceHolder();
629f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                holder.surface = s;
630f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                holder.width = surfaceSize.getWidth();
631f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                holder.height = surfaceSize.getHeight();
632ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                if (LegacyCameraDevice.needsConversion(s)) {
6330fd198ad89ec9c600bb1761b10d938146c28bb98Ruben Brunk                    // Always override to YV12 output for YUV surface formats.
634ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    LegacyCameraDevice.setSurfaceFormat(s, ImageFormat.YV12);
635ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    mConversionSurfaces.add(holder);
636ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                } else {
637ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    mSurfaces.add(holder);
638ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                }
639ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
640ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                Log.w(TAG, "Surface abandoned, skipping configuration... ", e);
641feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
642feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
643feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
644feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // Set up egl display
645feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        configureEGLContext();
646feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
647feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // Set up regular egl surfaces if needed
648feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mSurfaces.size() > 0) {
649feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            configureEGLOutputSurfaces(mSurfaces);
650feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
651feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
652feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // Set up pbuffer surface if needed
653feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mConversionSurfaces.size() > 0) {
654feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            configureEGLPbufferSurfaces(mConversionSurfaces);
655feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
656feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        makeCurrent((mSurfaces.size() > 0) ? mSurfaces.get(0).eglSurface :
657feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                mConversionSurfaces.get(0).eglSurface);
658feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        initializeGLState();
659feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mSurfaceTexture = new SurfaceTexture(getTextureId());
660e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
661e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        // Set up performance tracking if enabled
662e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (SystemProperties.getBoolean(LEGACY_PERF_PROPERTY, false)) {
663e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            setupGlTiming();
664e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
665feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
666feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
667feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
668feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Draw the current buffer in the {@link SurfaceTexture} returned from
66991838ded36131525312739c0929913b215519c2aRuben Brunk     * {@link #getSurfaceTexture()} into the set of target {@link Surface}s
67091838ded36131525312739c0929913b215519c2aRuben Brunk     * in the next request from the given {@link CaptureCollector}, or drop
67191838ded36131525312739c0929913b215519c2aRuben Brunk     * the frame if none is available.
672feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
673feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * <p>
67491838ded36131525312739c0929913b215519c2aRuben Brunk     * Any {@link Surface}s targeted must be a subset of the {@link Surface}s
67591838ded36131525312739c0929913b215519c2aRuben Brunk     * set in the last {@link #configureSurfaces(java.util.Collection)} call.
676feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * </p>
677feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
67891838ded36131525312739c0929913b215519c2aRuben Brunk     * @param targetCollector the surfaces to draw to.
679feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
68091838ded36131525312739c0929913b215519c2aRuben Brunk    public void drawIntoSurfaces(CaptureCollector targetCollector) {
681feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if ((mSurfaces == null || mSurfaces.size() == 0)
682feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                && (mConversionSurfaces == null || mConversionSurfaces.size() == 0)) {
683feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            return;
684feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
6853c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
68691838ded36131525312739c0929913b215519c2aRuben Brunk        boolean doTiming = targetCollector.hasPendingPreviewCaptures();
687feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("before updateTexImage");
688e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
68991838ded36131525312739c0929913b215519c2aRuben Brunk        if (doTiming) {
69091838ded36131525312739c0929913b215519c2aRuben Brunk            beginGlTiming();
691e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
692e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
693feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mSurfaceTexture.updateTexImage();
694e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
695e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        long timestamp = mSurfaceTexture.getTimestamp();
69691838ded36131525312739c0929913b215519c2aRuben Brunk
69791838ded36131525312739c0929913b215519c2aRuben Brunk        Pair<RequestHolder, Long> captureHolder = targetCollector.previewCaptured(timestamp);
69891838ded36131525312739c0929913b215519c2aRuben Brunk
69991838ded36131525312739c0929913b215519c2aRuben Brunk        // No preview request queued, drop frame.
70091838ded36131525312739c0929913b215519c2aRuben Brunk        if (captureHolder == null) {
701e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (DEBUG) {
702e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                Log.d(TAG, "Dropping preview frame.");
703e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
70491838ded36131525312739c0929913b215519c2aRuben Brunk            if (doTiming) {
70591838ded36131525312739c0929913b215519c2aRuben Brunk                endGlTiming();
70691838ded36131525312739c0929913b215519c2aRuben Brunk            }
70791838ded36131525312739c0929913b215519c2aRuben Brunk            return;
70891838ded36131525312739c0929913b215519c2aRuben Brunk        }
70991838ded36131525312739c0929913b215519c2aRuben Brunk
71091838ded36131525312739c0929913b215519c2aRuben Brunk        RequestHolder request = captureHolder.first;
71191838ded36131525312739c0929913b215519c2aRuben Brunk
71291838ded36131525312739c0929913b215519c2aRuben Brunk        Collection<Surface> targetSurfaces = request.getHolderTargets();
71391838ded36131525312739c0929913b215519c2aRuben Brunk        if (doTiming) {
71491838ded36131525312739c0929913b215519c2aRuben Brunk            addGlTimestamp(timestamp);
71591838ded36131525312739c0929913b215519c2aRuben Brunk        }
716e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
7173c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        List<Long> targetSurfaceIds = LegacyCameraDevice.getSurfaceIds(targetSurfaces);
718feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        for (EGLSurfaceHolder holder : mSurfaces) {
7193c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
720f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                try{
721a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk                    LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width,
722a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk                            holder.height);
723f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    makeCurrent(holder.eglSurface);
724f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk
72591838ded36131525312739c0929913b215519c2aRuben Brunk                    LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
726433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                    drawFrame(mSurfaceTexture, holder.width, holder.height,
727433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                            (mFacing == CameraCharacteristics.LENS_FACING_FRONT) ?
728433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                                    FLIP_TYPE_HORIZONTAL : FLIP_TYPE_NONE);
72991838ded36131525312739c0929913b215519c2aRuben Brunk                    swapBuffers(holder.eglSurface);
73091838ded36131525312739c0929913b215519c2aRuben Brunk                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
73191838ded36131525312739c0929913b215519c2aRuben Brunk                    Log.w(TAG, "Surface abandoned, dropping frame. ", e);
73291838ded36131525312739c0929913b215519c2aRuben Brunk                }
733feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
734feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
735feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        for (EGLSurfaceHolder holder : mConversionSurfaces) {
7363c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
737feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                makeCurrent(holder.eglSurface);
738433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                // glReadPixels reads from the bottom of the buffer, so add an extra vertical flip
739433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                drawFrame(mSurfaceTexture, holder.width, holder.height,
740433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                        (mFacing == CameraCharacteristics.LENS_FACING_FRONT) ?
741433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                                FLIP_TYPE_BOTH : FLIP_TYPE_VERTICAL);
742feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                mPBufferPixels.clear();
74328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                GLES20.glReadPixels(/*x*/ 0, /*y*/ 0, holder.width, holder.height,
74428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                        GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mPBufferPixels);
745feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                checkGlError("glReadPixels");
74628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
747ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                try {
748ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    int format = LegacyCameraDevice.detectSurfaceType(holder.surface);
749f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width,
750f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                            holder.height);
75191838ded36131525312739c0929913b215519c2aRuben Brunk                    LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
752ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    LegacyCameraDevice.produceFrame(holder.surface, mPBufferPixels.array(),
753ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                            holder.width, holder.height, format);
754ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
755ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    Log.w(TAG, "Surface abandoned, dropping frame. ", e);
756ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                }
757feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
758feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
75991838ded36131525312739c0929913b215519c2aRuben Brunk        targetCollector.previewProduced();
760e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
76191838ded36131525312739c0929913b215519c2aRuben Brunk        if (doTiming) {
76291838ded36131525312739c0929913b215519c2aRuben Brunk            endGlTiming();
76391838ded36131525312739c0929913b215519c2aRuben Brunk        }
764feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
765feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
766feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
767feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Clean up the current GL context.
768feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
769feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void cleanupEGLContext() {
770feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        releaseEGLContext();
771feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
772feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
773feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
774feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Drop all current GL operations on the floor.
775feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
776feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void flush() {
777feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // TODO: implement flush
778feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        Log.e(TAG, "Flush not yet implemented.");
779feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
780feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk}
781