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();
52a78791f22af6c6985d186494737468bb19b69540Eino-Ville Talvala    private static final boolean DEBUG = false;
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
251091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh    private void drawFrame(SurfaceTexture st, int width, int height, int flipType)
252091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh            throws LegacyExceptionUtils.BufferQueueAbandonedException {
253feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("onDrawFrame start");
254feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        st.getTransformMatrix(mSTMatrix);
255feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
256a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        Matrix.setIdentityM(mMVPMatrix, /*smOffset*/0);
257a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk
258a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        // Find intermediate buffer dimensions
25928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        Size dimens;
26028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        try {
26128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            dimens = LegacyCameraDevice.getTextureSize(st);
26228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
26328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            // Should never hit this.
26428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            throw new IllegalStateException("Surface abandoned, skipping drawFrame...", e);
26528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        }
26628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        float texWidth = dimens.getWidth();
26728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        float texHeight = dimens.getHeight();
26828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
26928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        if (texWidth <= 0 || texHeight <= 0) {
27028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            throw new IllegalStateException("Illegal intermediate texture with dimension of 0");
27128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        }
27228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
273259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // Letterbox or pillar-box output dimensions into intermediate dimensions.
274a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        RectF intermediate = new RectF(/*left*/0, /*top*/0, /*right*/texWidth, /*bottom*/texHeight);
275a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        RectF output = new RectF(/*left*/0, /*top*/0, /*right*/width, /*bottom*/height);
276a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        android.graphics.Matrix boxingXform = new android.graphics.Matrix();
277a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        boxingXform.setRectToRect(output, intermediate, android.graphics.Matrix.ScaleToFit.CENTER);
278a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        boxingXform.mapRect(output);
27928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
280259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // Find scaling factor from pillar-boxed/letter-boxed output dimensions to intermediate
281a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        // buffer dimensions.
282a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        float scaleX = intermediate.width() / output.width();
283a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        float scaleY = intermediate.height() / output.height();
28428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
285259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // Intermediate texture is implicitly scaled to 'fill' the output dimensions in clip space
286259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // coordinates in the shader.  To avoid stretching, we need to scale the larger dimension
287259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // of the intermediate buffer so that the output buffer is actually letter-boxed
288259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        // or pillar-boxed into the intermediate buffer after clipping.
289259f3d90b8784e150e4b903f9810f089f2d9bd42Ruben Brunk        Matrix.scaleM(mMVPMatrix, /*offset*/0, /*x*/scaleX, /*y*/scaleY, /*z*/1);
29028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
291feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (DEBUG) {
292a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk            Log.d(TAG, "Scaling factors (S_x = " + scaleX + ",S_y = " + scaleY + ") used for " +
293a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk                    width + "x" + height + " surface, intermediate buffer size is " + texWidth +
294a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk                    "x" + texHeight);
29528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        }
29628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
297a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        // Set viewport to be output buffer dimensions
298a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk        GLES20.glViewport(0, 0, width, height);
29928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
30028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        if (DEBUG) {
30128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
302feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
303feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
304feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
305feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glUseProgram(mProgram);
306feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glUseProgram");
307feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
308feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
309feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
310feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
311433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        FloatBuffer triangleVertices;
312433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        switch(flipType) {
313433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            case FLIP_TYPE_HORIZONTAL:
314433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                triangleVertices = mHorizontalFlipTriangleVertices;
315433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                break;
316433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            case FLIP_TYPE_VERTICAL:
317433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                triangleVertices = mVerticalFlipTriangleVertices;
318433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                break;
319433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            case FLIP_TYPE_BOTH:
320433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                triangleVertices = mBothFlipTriangleVertices;
321433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                break;
322433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk            default:
323433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                triangleVertices = mRegularTriangleVertices;
324433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                break;
325433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        }
326433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk
327433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
328feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glVertexAttribPointer(maPositionHandle, VERTEX_POS_SIZE, GLES20.GL_FLOAT,
329433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
330feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glVertexAttribPointer maPosition");
331feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glEnableVertexAttribArray(maPositionHandle);
332feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glEnableVertexAttribArray maPositionHandle");
333feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
334433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk        triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
335feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glVertexAttribPointer(maTextureHandle, VERTEX_UV_SIZE, GLES20.GL_FLOAT,
336433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
337feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glVertexAttribPointer maTextureHandle");
338feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glEnableVertexAttribArray(maTextureHandle);
339feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glEnableVertexAttribArray maTextureHandle");
340feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
341feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, /*count*/ 1, /*transpose*/ false, mMVPMatrix,
342feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                /*offset*/ 0);
343feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glUniformMatrix4fv(muSTMatrixHandle, /*count*/ 1, /*transpose*/ false, mSTMatrix,
344feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                /*offset*/ 0);
345feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
346feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /*offset*/ 0, /*count*/ 4);
347091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        checkGlDrawError("glDrawArrays");
348feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
349feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
350feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
351feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Initializes GL state.  Call this after the EGL surface has been created and made current.
352feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
353feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void initializeGLState() {
354feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
355feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mProgram == 0) {
356feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("failed creating program");
357feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
358feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
359feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glGetAttribLocation aPosition");
360feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (maPositionHandle == -1) {
361feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not get attrib location for aPosition");
362feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
363feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
364feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glGetAttribLocation aTextureCoord");
365feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (maTextureHandle == -1) {
366feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not get attrib location for aTextureCoord");
367feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
368feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
369feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
370feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glGetUniformLocation uMVPMatrix");
371feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (muMVPMatrixHandle == -1) {
372feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not get attrib location for uMVPMatrix");
373feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
374feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
375feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
376feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glGetUniformLocation uSTMatrix");
377feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (muSTMatrixHandle == -1) {
378feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Could not get attrib location for uSTMatrix");
379feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
380feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
381feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] textures = new int[1];
382feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glGenTextures(/*n*/ 1, textures, /*offset*/ 0);
383feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
384feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mTextureID = textures[0];
385feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
386feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glBindTexture mTextureID");
387feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
388feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
389feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                GLES20.GL_NEAREST);
390feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
391feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                GLES20.GL_LINEAR);
392feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
393feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                GLES20.GL_CLAMP_TO_EDGE);
394feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
395feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                GLES20.GL_CLAMP_TO_EDGE);
396feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("glTexParameter");
397feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
398feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
399feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private int getTextureId() {
400feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return mTextureID;
401feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
402feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
403feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void clearState() {
404feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mSurfaces.clear();
40529c3630563452c9635f0510d071839c112d3017dChien-Yu Chen        for (EGLSurfaceHolder holder : mConversionSurfaces) {
40629c3630563452c9635f0510d071839c112d3017dChien-Yu Chen            try {
40729c3630563452c9635f0510d071839c112d3017dChien-Yu Chen                LegacyCameraDevice.disconnectSurface(holder.surface);
40829c3630563452c9635f0510d071839c112d3017dChien-Yu Chen            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
40929c3630563452c9635f0510d071839c112d3017dChien-Yu Chen                Log.w(TAG, "Surface abandoned, skipping...", e);
41029c3630563452c9635f0510d071839c112d3017dChien-Yu Chen            }
41129c3630563452c9635f0510d071839c112d3017dChien-Yu Chen        }
412feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mConversionSurfaces.clear();
413feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mPBufferPixels = null;
4143fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk        if (mSurfaceTexture != null) {
4153fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk            mSurfaceTexture.release();
4163fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk        }
417feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mSurfaceTexture = null;
418feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
419feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
420feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void configureEGLContext() {
421feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
422feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
423feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("No EGL14 display");
424feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
425feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] version = new int[2];
426feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (!EGL14.eglInitialize(mEGLDisplay, version, /*offset*/ 0, version, /*offset*/ 1)) {
427feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("Cannot initialize EGL14");
428feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
429feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
430feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] attribList = {
431feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_RED_SIZE, EGL_COLOR_BITLENGTH,
432feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_GREEN_SIZE, EGL_COLOR_BITLENGTH,
433feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_BLUE_SIZE, EGL_COLOR_BITLENGTH,
434feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
435feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL_RECORDABLE_ANDROID, 1,
436feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT | EGL14.EGL_WINDOW_BIT,
437feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_NONE
438feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        };
439feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        EGLConfig[] configs = new EGLConfig[1];
440feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] numConfigs = new int[1];
441feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        EGL14.eglChooseConfig(mEGLDisplay, attribList, /*offset*/ 0, configs, /*offset*/ 0,
442feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                configs.length, numConfigs, /*offset*/ 0);
443feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkEglError("eglCreateContext RGB888+recordable ES2");
444feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mConfigs = configs[0];
445feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] attrib_list = {
446feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
447feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_NONE
448feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        };
449feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
450feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                attrib_list, /*offset*/ 0);
451feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkEglError("eglCreateContext");
452feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if(mEGLContext == EGL14.EGL_NO_CONTEXT) {
453feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("No EGLContext could be made");
454feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
455feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
456feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
457feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void configureEGLOutputSurfaces(Collection<EGLSurfaceHolder> surfaces) {
458feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (surfaces == null || surfaces.size() == 0) {
459feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("No Surfaces were provided to draw to");
460feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
461feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int[] surfaceAttribs = {
462feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                EGL14.EGL_NONE
463feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        };
464feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        for (EGLSurfaceHolder holder : surfaces) {
465f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            holder.eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs,
466f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    holder.surface, surfaceAttribs, /*offset*/ 0);
467f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            checkEglError("eglCreateWindowSurface");
468feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
469feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
470feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
471feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void configureEGLPbufferSurfaces(Collection<EGLSurfaceHolder> surfaces) {
472feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (surfaces == null || surfaces.size() == 0) {
473feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException("No Surfaces were provided to draw to");
474feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
475feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
476feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int maxLength = 0;
477feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        for (EGLSurfaceHolder holder : surfaces) {
478f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            int length = holder.width * holder.height;
479f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            // Find max surface size, ensure PBuffer can hold this many pixels
480f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            maxLength = (length > maxLength) ? length : maxLength;
481f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            int[] surfaceAttribs = {
482f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    EGL14.EGL_WIDTH, holder.width,
483f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    EGL14.EGL_HEIGHT, holder.height,
484f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    EGL14.EGL_NONE
485f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            };
486f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            holder.eglSurface =
487f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    EGL14.eglCreatePbufferSurface(mEGLDisplay, mConfigs, surfaceAttribs, 0);
488f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            checkEglError("eglCreatePbufferSurface");
489feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
490feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mPBufferPixels = ByteBuffer.allocateDirect(maxLength * PBUFFER_PIXEL_BYTES)
491feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                .order(ByteOrder.nativeOrder());
492feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
493feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
494feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void releaseEGLContext() {
495feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
496feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
497feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    EGL14.EGL_NO_CONTEXT);
498e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            dumpGlTiming();
499feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            if (mSurfaces != null) {
500feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                for (EGLSurfaceHolder holder : mSurfaces) {
501feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    if (holder.eglSurface != null) {
502feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                        EGL14.eglDestroySurface(mEGLDisplay, holder.eglSurface);
503feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    }
504feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                }
505feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
506feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            if (mConversionSurfaces != null) {
507feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                for (EGLSurfaceHolder holder : mConversionSurfaces) {
508feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    if (holder.eglSurface != null) {
509feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                        EGL14.eglDestroySurface(mEGLDisplay, holder.eglSurface);
510feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                    }
511feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                }
512feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
513feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
514feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            EGL14.eglReleaseThread();
515feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            EGL14.eglTerminate(mEGLDisplay);
516feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
517feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
518feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mConfigs = null;
519feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mEGLDisplay = EGL14.EGL_NO_DISPLAY;
520feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mEGLContext = EGL14.EGL_NO_CONTEXT;
521feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        clearState();
522feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
523feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
524feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void makeCurrent(EGLSurface surface) {
525feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        EGL14.eglMakeCurrent(mEGLDisplay, surface, surface, mEGLContext);
526feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkEglError("makeCurrent");
527feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
528feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
5292da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen    private boolean swapBuffers(EGLSurface surface)
5302da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen            throws LegacyExceptionUtils.BufferQueueAbandonedException {
531feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        boolean result = EGL14.eglSwapBuffers(mEGLDisplay, surface);
5322da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen        int error = EGL14.eglGetError();
5332da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen        if (error == EGL14.EGL_BAD_SURFACE) {
5342da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen            throw new LegacyExceptionUtils.BufferQueueAbandonedException();
5352da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen        } else if (error != EGL14.EGL_SUCCESS) {
5362da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen            throw new IllegalStateException("swapBuffers: EGL error: 0x" +
5372da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen                    Integer.toHexString(error));
5382da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen        }
539feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return result;
540feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
541feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
542feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void checkEglError(String msg) {
543feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int error;
544feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
545feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            throw new IllegalStateException(msg + ": EGL error: 0x" + Integer.toHexString(error));
546feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
547feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
548feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
549feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private void checkGlError(String msg) {
550feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int error;
551feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
552091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh            throw new IllegalStateException(
553091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                    msg + ": GLES20 error: 0x" + Integer.toHexString(error));
554091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        }
555091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh    }
556091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh
557091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh    private void checkGlDrawError(String msg)
558091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh            throws LegacyExceptionUtils.BufferQueueAbandonedException {
559091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        int error;
560091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        boolean surfaceAbandoned = false;
561091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        boolean glError = false;
562091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
563091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh            if (error == GLES20.GL_OUT_OF_MEMORY) {
564091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                surfaceAbandoned = true;
565091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh            } else {
566091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                glError = true;
567091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh            }
568091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        }
569091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        if (glError) {
570091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh            throw new IllegalStateException(
571091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                    msg + ": GLES20 error: 0x" + Integer.toHexString(error));
572091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        }
573091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh        if (surfaceAbandoned) {
574091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh            throw new LegacyExceptionUtils.BufferQueueAbandonedException();
575feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
576feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
577feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
578feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
579e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala     * Save a measurement dump to disk, in
580e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala     * {@code /sdcard/CameraLegacy/durations_<time>_<width1>x<height1>_...txt}
581e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala     */
582e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void dumpGlTiming() {
583e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (mPerfMeasurer == null) return;
584e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
585e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        File legacyStorageDir = new File(Environment.getExternalStorageDirectory(), "CameraLegacy");
586e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (!legacyStorageDir.exists()){
587e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            if (!legacyStorageDir.mkdirs()){
588e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala                Log.e(TAG, "Failed to create directory for data dump");
589e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala                return;
590e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            }
591e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
592e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
593e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        StringBuilder path = new StringBuilder(legacyStorageDir.getPath());
594e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append(File.separator);
595e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append("durations_");
596e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
597e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        Time now = new Time();
598e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        now.setToNow();
599e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append(now.format2445());
600e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append("_S");
601e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        for (EGLSurfaceHolder surface : mSurfaces) {
602e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            path.append(String.format("_%d_%d", surface.width, surface.height));
603e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
604e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append("_C");
605e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        for (EGLSurfaceHolder surface : mConversionSurfaces) {
606e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            path.append(String.format("_%d_%d", surface.width, surface.height));
607e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
608e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        path.append(".txt");
609e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        mPerfMeasurer.dumpPerformanceData(path.toString());
610e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
611e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
612e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void setupGlTiming() {
613e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (PerfMeasurement.isGlTimingSupported()) {
614e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            Log.d(TAG, "Enabling GL performance measurement");
615e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            mPerfMeasurer = new PerfMeasurement();
616e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        } else {
617e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            Log.d(TAG, "GL performance measurement not supported on this device");
618e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            mPerfMeasurer = null;
619e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
620e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
621e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
622e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void beginGlTiming() {
623e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (mPerfMeasurer == null) return;
624e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        mPerfMeasurer.startTimer();
625e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
626e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
627e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void addGlTimestamp(long timestamp) {
628e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (mPerfMeasurer == null) return;
629e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        mPerfMeasurer.addTimestamp(timestamp);
630e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
631e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
632e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    private void endGlTiming() {
633e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (mPerfMeasurer == null) return;
634e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        mPerfMeasurer.stopTimer();
635e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    }
636e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
637e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala    /**
638feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Return the surface texture to draw to - this is the texture use to when producing output
639feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * surface buffers.
640feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
641feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @return a {@link SurfaceTexture}.
642feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
643feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public SurfaceTexture getSurfaceTexture() {
644feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return mSurfaceTexture;
645feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
646feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
647feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
648feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Set a collection of output {@link Surface}s that can be drawn to.
649feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
650feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param surfaces a {@link Collection} of surfaces.
651feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
652f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk    public void configureSurfaces(Collection<Pair<Surface, Size>> surfaces) {
653feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        releaseEGLContext();
654feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
655d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        if (surfaces == null || surfaces.size() == 0) {
656d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            Log.w(TAG, "No output surfaces configured for GL drawing.");
657d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            return;
658d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        }
659d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk
660f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk        for (Pair<Surface, Size> p : surfaces) {
661f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            Surface s = p.first;
662f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk            Size surfaceSize = p.second;
663feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            // If pixel conversions aren't handled by egl, use a pbuffer
664ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            try {
665f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                EGLSurfaceHolder holder = new EGLSurfaceHolder();
666f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                holder.surface = s;
667f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                holder.width = surfaceSize.getWidth();
668f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                holder.height = surfaceSize.getHeight();
669ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                if (LegacyCameraDevice.needsConversion(s)) {
670ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    mConversionSurfaces.add(holder);
67129c3630563452c9635f0510d071839c112d3017dChien-Yu Chen                    // LegacyCameraDevice is the producer of surfaces if it's not handled by EGL,
67229c3630563452c9635f0510d071839c112d3017dChien-Yu Chen                    // so LegacyCameraDevice needs to connect to the surfaces.
67329c3630563452c9635f0510d071839c112d3017dChien-Yu Chen                    LegacyCameraDevice.connectSurface(s);
674ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                } else {
675ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    mSurfaces.add(holder);
676ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                }
677ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
678ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                Log.w(TAG, "Surface abandoned, skipping configuration... ", e);
679feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
680feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
681feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
682feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // Set up egl display
683feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        configureEGLContext();
684feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
685feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // Set up regular egl surfaces if needed
686feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mSurfaces.size() > 0) {
687feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            configureEGLOutputSurfaces(mSurfaces);
688feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
689feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
690feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // Set up pbuffer surface if needed
691feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (mConversionSurfaces.size() > 0) {
692feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            configureEGLPbufferSurfaces(mConversionSurfaces);
693feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
694feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        makeCurrent((mSurfaces.size() > 0) ? mSurfaces.get(0).eglSurface :
695feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                mConversionSurfaces.get(0).eglSurface);
696feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        initializeGLState();
697feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mSurfaceTexture = new SurfaceTexture(getTextureId());
698e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
699e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        // Set up performance tracking if enabled
700e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        if (SystemProperties.getBoolean(LEGACY_PERF_PROPERTY, false)) {
701e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala            setupGlTiming();
702e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
703feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
704feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
705feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
706feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Draw the current buffer in the {@link SurfaceTexture} returned from
70791838ded36131525312739c0929913b215519c2aRuben Brunk     * {@link #getSurfaceTexture()} into the set of target {@link Surface}s
70891838ded36131525312739c0929913b215519c2aRuben Brunk     * in the next request from the given {@link CaptureCollector}, or drop
70991838ded36131525312739c0929913b215519c2aRuben Brunk     * the frame if none is available.
710feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
711feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * <p>
71291838ded36131525312739c0929913b215519c2aRuben Brunk     * Any {@link Surface}s targeted must be a subset of the {@link Surface}s
71391838ded36131525312739c0929913b215519c2aRuben Brunk     * set in the last {@link #configureSurfaces(java.util.Collection)} call.
714feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * </p>
715feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
71691838ded36131525312739c0929913b215519c2aRuben Brunk     * @param targetCollector the surfaces to draw to.
717feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
71891838ded36131525312739c0929913b215519c2aRuben Brunk    public void drawIntoSurfaces(CaptureCollector targetCollector) {
719feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if ((mSurfaces == null || mSurfaces.size() == 0)
720feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                && (mConversionSurfaces == null || mConversionSurfaces.size() == 0)) {
721feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            return;
722feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
7233c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
72491838ded36131525312739c0929913b215519c2aRuben Brunk        boolean doTiming = targetCollector.hasPendingPreviewCaptures();
725feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        checkGlError("before updateTexImage");
726e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
72791838ded36131525312739c0929913b215519c2aRuben Brunk        if (doTiming) {
72891838ded36131525312739c0929913b215519c2aRuben Brunk            beginGlTiming();
729e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        }
730e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
731feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mSurfaceTexture.updateTexImage();
732e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
733e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala        long timestamp = mSurfaceTexture.getTimestamp();
73491838ded36131525312739c0929913b215519c2aRuben Brunk
73591838ded36131525312739c0929913b215519c2aRuben Brunk        Pair<RequestHolder, Long> captureHolder = targetCollector.previewCaptured(timestamp);
73691838ded36131525312739c0929913b215519c2aRuben Brunk
73791838ded36131525312739c0929913b215519c2aRuben Brunk        // No preview request queued, drop frame.
73891838ded36131525312739c0929913b215519c2aRuben Brunk        if (captureHolder == null) {
739e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (DEBUG) {
740e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                Log.d(TAG, "Dropping preview frame.");
741e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
74291838ded36131525312739c0929913b215519c2aRuben Brunk            if (doTiming) {
74391838ded36131525312739c0929913b215519c2aRuben Brunk                endGlTiming();
74491838ded36131525312739c0929913b215519c2aRuben Brunk            }
74591838ded36131525312739c0929913b215519c2aRuben Brunk            return;
74691838ded36131525312739c0929913b215519c2aRuben Brunk        }
74791838ded36131525312739c0929913b215519c2aRuben Brunk
74891838ded36131525312739c0929913b215519c2aRuben Brunk        RequestHolder request = captureHolder.first;
74991838ded36131525312739c0929913b215519c2aRuben Brunk
75091838ded36131525312739c0929913b215519c2aRuben Brunk        Collection<Surface> targetSurfaces = request.getHolderTargets();
75191838ded36131525312739c0929913b215519c2aRuben Brunk        if (doTiming) {
75291838ded36131525312739c0929913b215519c2aRuben Brunk            addGlTimestamp(timestamp);
75391838ded36131525312739c0929913b215519c2aRuben Brunk        }
754e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
7552da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen        List<Long> targetSurfaceIds = new ArrayList();
7562da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen        try {
7572da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen            targetSurfaceIds = LegacyCameraDevice.getSurfaceIds(targetSurfaces);
7582da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen        } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
7592da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen            Log.w(TAG, "Surface abandoned, dropping frame. ", e);
7602da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen            request.setOutputAbandoned();
7612da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen        }
7622da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen
763feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        for (EGLSurfaceHolder holder : mSurfaces) {
7643c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
765f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                try{
766a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk                    LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width,
767a9bc3559109836efe7479a3279713bd58810b153Ruben Brunk                            holder.height);
768f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    makeCurrent(holder.eglSurface);
769f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk
77091838ded36131525312739c0929913b215519c2aRuben Brunk                    LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
771433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                    drawFrame(mSurfaceTexture, holder.width, holder.height,
772433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                            (mFacing == CameraCharacteristics.LENS_FACING_FRONT) ?
773433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                                    FLIP_TYPE_HORIZONTAL : FLIP_TYPE_NONE);
77491838ded36131525312739c0929913b215519c2aRuben Brunk                    swapBuffers(holder.eglSurface);
77591838ded36131525312739c0929913b215519c2aRuben Brunk                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
77691838ded36131525312739c0929913b215519c2aRuben Brunk                    Log.w(TAG, "Surface abandoned, dropping frame. ", e);
7772da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen                    request.setOutputAbandoned();
77891838ded36131525312739c0929913b215519c2aRuben Brunk                }
779feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
780feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
781feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        for (EGLSurfaceHolder holder : mConversionSurfaces) {
7823c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
783feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                makeCurrent(holder.eglSurface);
784433e715cc0040ce22a31964c71bff71b1fe1a14fRuben Brunk                // glReadPixels reads from the bottom of the buffer, so add an extra vertical flip
785091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                try {
786091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                    drawFrame(mSurfaceTexture, holder.width, holder.height,
787091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                            (mFacing == CameraCharacteristics.LENS_FACING_FRONT) ?
788091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                                    FLIP_TYPE_BOTH : FLIP_TYPE_VERTICAL);
789091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
790091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                    // Should never hit this.
791091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                    throw new IllegalStateException("Surface abandoned, skipping drawFrame...", e);
792091661334b25c1bc282463d13622236b1ac79e64Yin-Chia Yeh                }
793feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                mPBufferPixels.clear();
79428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                GLES20.glReadPixels(/*x*/ 0, /*y*/ 0, holder.width, holder.height,
79528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                        GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mPBufferPixels);
796feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                checkGlError("glReadPixels");
79728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
798ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                try {
799ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    int format = LegacyCameraDevice.detectSurfaceType(holder.surface);
800f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                    LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width,
801f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                            holder.height);
80291838ded36131525312739c0929913b215519c2aRuben Brunk                    LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
803ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    LegacyCameraDevice.produceFrame(holder.surface, mPBufferPixels.array(),
804ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                            holder.width, holder.height, format);
805ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
806ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                    Log.w(TAG, "Surface abandoned, dropping frame. ", e);
8072da496f1ce63548486fe28e074f6af90c970db8cChien-Yu Chen                    request.setOutputAbandoned();
808ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                }
809feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
810feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
81191838ded36131525312739c0929913b215519c2aRuben Brunk        targetCollector.previewProduced();
812e1f57d6f44909a66c7ab0af33dbc5289287e823aEino-Ville Talvala
81391838ded36131525312739c0929913b215519c2aRuben Brunk        if (doTiming) {
81491838ded36131525312739c0929913b215519c2aRuben Brunk            endGlTiming();
81591838ded36131525312739c0929913b215519c2aRuben Brunk        }
816feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
817feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
818feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
819feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Clean up the current GL context.
820feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
821feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void cleanupEGLContext() {
822feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        releaseEGLContext();
823feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
824feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
825feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
826feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Drop all current GL operations on the floor.
827feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
828feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void flush() {
829feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // TODO: implement flush
830feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        Log.e(TAG, "Flush not yet implemented.");
831feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
832feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk}
833