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