632 lines
20 KiB
Java
632 lines
20 KiB
Java
package com.serenegiant.glutils;
|
||
/*
|
||
* libcommon
|
||
* utility/helper classes for myself
|
||
*
|
||
* Copyright (c) 2014-2018 saki t_saki@serenegiant.com
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
import android.annotation.SuppressLint;
|
||
import android.annotation.TargetApi;
|
||
import android.graphics.SurfaceTexture;
|
||
import android.opengl.EGL14;
|
||
import android.opengl.EGLConfig;
|
||
import android.opengl.EGLContext;
|
||
import android.opengl.EGLDisplay;
|
||
import android.opengl.EGLExt;
|
||
import android.opengl.EGLSurface;
|
||
import android.opengl.GLES10;
|
||
import android.opengl.GLES20;
|
||
import android.os.Build;
|
||
import android.util.Log;
|
||
import android.view.Surface;
|
||
import android.view.SurfaceHolder;
|
||
import android.view.SurfaceView;
|
||
|
||
import androidx.annotation.NonNull;
|
||
|
||
import com.serenegiant.utils.BuildCheck;
|
||
|
||
/**
|
||
* EGLレンダリングコンテキストを生成&使用するためのヘルパークラス
|
||
*/
|
||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||
/*package*/ class EGLBase14 extends EGLBase { // API >= 17
|
||
// private static final boolean DEBUG = false; // TODO set false on release
|
||
private static final String TAG = "EGLBase14";
|
||
|
||
private static final Context EGL_NO_CONTEXT = new Context(EGL14.EGL_NO_CONTEXT);
|
||
|
||
private Config mEglConfig = null;
|
||
@NonNull private Context mContext = EGL_NO_CONTEXT;
|
||
// private EGLContext mEglContext = EGL14.EGL_NO_CONTEXT;
|
||
private EGLDisplay mEglDisplay = EGL14.EGL_NO_DISPLAY;
|
||
private EGLContext mDefaultContext = EGL14.EGL_NO_CONTEXT;
|
||
private int mGlVersion = 2;
|
||
|
||
/**
|
||
* EGLレンダリングコンテキストのホルダークラス
|
||
*/
|
||
public static class Context extends IContext {
|
||
public final EGLContext eglContext;
|
||
|
||
private Context(final EGLContext context) {
|
||
eglContext = context;
|
||
}
|
||
|
||
@Override
|
||
@SuppressLint("NewApi")
|
||
public long getNativeHandle() {
|
||
return eglContext != null ?
|
||
(BuildCheck.isLollipop()
|
||
? eglContext.getNativeHandle() : eglContext.getHandle()) : 0L;
|
||
}
|
||
|
||
@Override
|
||
public Object getEGLContext() {
|
||
return eglContext;
|
||
}
|
||
}
|
||
|
||
public static class Config extends IConfig {
|
||
public final EGLConfig eglConfig;
|
||
|
||
private Config(final EGLConfig eglConfig) {
|
||
this.eglConfig = eglConfig;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* EGLレンダリングコンテキストに紐付ける描画オブジェクト
|
||
*/
|
||
public static class EglSurface implements IEglSurface {
|
||
private final EGLBase14 mEglBase;
|
||
private EGLSurface mEglSurface = EGL14.EGL_NO_SURFACE;
|
||
|
||
private EglSurface(final EGLBase14 eglBase, final Object surface)
|
||
throws IllegalArgumentException {
|
||
|
||
// if (DEBUG) Log.v(TAG, "EglSurface:");
|
||
mEglBase = eglBase;
|
||
if ((surface instanceof Surface)
|
||
|| (surface instanceof SurfaceHolder)
|
||
|| (surface instanceof SurfaceTexture)
|
||
|| (surface instanceof SurfaceView)) {
|
||
mEglSurface = mEglBase.createWindowSurface(surface);
|
||
} else {
|
||
throw new IllegalArgumentException("unsupported surface");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 指定した大きさを持つオフスクリーンEglSurface(PBuffer)
|
||
* @param eglBase
|
||
* @param width
|
||
* @param height
|
||
*/
|
||
private EglSurface(final EGLBase14 eglBase,
|
||
final int width, final int height) {
|
||
|
||
// if (DEBUG) Log.v(TAG, "EglSurface:");
|
||
mEglBase = eglBase;
|
||
if ((width <= 0) || (height <= 0)) {
|
||
mEglSurface = mEglBase.createOffscreenSurface(1, 1);
|
||
} else {
|
||
mEglSurface = mEglBase.createOffscreenSurface(width, height);
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void makeCurrent() {
|
||
mEglBase.makeCurrent(mEglSurface);
|
||
if (mEglBase.getGlVersion() >= 2) {
|
||
GLES20.glViewport(0, 0,
|
||
mEglBase.getSurfaceWidth(mEglSurface),
|
||
mEglBase.getSurfaceHeight(mEglSurface));
|
||
} else {
|
||
GLES10.glViewport(0, 0,
|
||
mEglBase.getSurfaceWidth(mEglSurface),
|
||
mEglBase.getSurfaceHeight(mEglSurface));
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void swap() {
|
||
mEglBase.swap(mEglSurface);
|
||
}
|
||
|
||
@Override
|
||
public void swap(final long presentationTimeNs) {
|
||
mEglBase.swap(mEglSurface, presentationTimeNs);
|
||
}
|
||
|
||
public void setPresentationTime(final long presentationTimeNs) {
|
||
EGLExt.eglPresentationTimeANDROID(mEglBase.mEglDisplay,
|
||
mEglSurface, presentationTimeNs);
|
||
}
|
||
|
||
@Override
|
||
public IContext getContext() {
|
||
return mEglBase.getContext();
|
||
}
|
||
|
||
@Override
|
||
public boolean isValid() {
|
||
return (mEglSurface != null)
|
||
&& (mEglSurface != EGL14.EGL_NO_SURFACE)
|
||
&& (mEglBase.getSurfaceWidth(mEglSurface) > 0)
|
||
&& (mEglBase.getSurfaceHeight(mEglSurface) > 0);
|
||
}
|
||
|
||
@Override
|
||
public void release() {
|
||
// if (DEBUG) Log.v(TAG, "EglSurface:release:");
|
||
mEglBase.makeDefault();
|
||
mEglBase.destroyWindowSurface(mEglSurface);
|
||
mEglSurface = EGL14.EGL_NO_SURFACE;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* コンストラクタ
|
||
* @param maxClientVersion
|
||
* @param sharedContext
|
||
* @param withDepthBuffer
|
||
* @param isRecordable
|
||
*/
|
||
public EGLBase14(final int maxClientVersion,
|
||
final Context sharedContext, final boolean withDepthBuffer,
|
||
final int stencilBits, final boolean isRecordable) {
|
||
|
||
// if (DEBUG) Log.v(TAG, "Constructor:");
|
||
init(maxClientVersion, sharedContext, withDepthBuffer, stencilBits, isRecordable);
|
||
}
|
||
|
||
/**
|
||
* 関連するリソースを破棄する
|
||
*/
|
||
@Override
|
||
public void release() {
|
||
// if (DEBUG) Log.v(TAG, "release:");
|
||
if (mEglDisplay != EGL14.EGL_NO_DISPLAY) {
|
||
destroyContext();
|
||
EGL14.eglTerminate(mEglDisplay);
|
||
EGL14.eglReleaseThread();
|
||
}
|
||
mEglDisplay = EGL14.EGL_NO_DISPLAY;
|
||
mContext = EGL_NO_CONTEXT;
|
||
}
|
||
|
||
/**
|
||
* 指定したSurfaceからEglSurfaceを生成する
|
||
* 生成したEglSurfaceをmakeCurrentした状態で戻る
|
||
* @param nativeWindow Surface/SurfaceTexture/SurfaceHolder
|
||
* @return
|
||
*/
|
||
@Override
|
||
public EglSurface createFromSurface(final Object nativeWindow) {
|
||
// if (DEBUG) Log.v(TAG, "createFromSurface:");
|
||
final EglSurface eglSurface = new EglSurface(this, nativeWindow);
|
||
eglSurface.makeCurrent();
|
||
return eglSurface;
|
||
}
|
||
|
||
/**
|
||
* 指定した大きさのオフスクリーンEglSurfaceを生成する
|
||
* 生成したEglSurfaceをmakeCurrentした状態で戻る
|
||
* @param width PBufferオフスクリーンのサイズ(0以下はだめ)
|
||
* @param height
|
||
* @return
|
||
*/
|
||
@Override
|
||
public EglSurface createOffscreen(final int width, final int height) {
|
||
// if (DEBUG) Log.v(TAG, "createOffscreen:");
|
||
final EglSurface eglSurface = new EglSurface(this, width, height);
|
||
eglSurface.makeCurrent();
|
||
return eglSurface;
|
||
}
|
||
|
||
/**
|
||
* GLESに文字列を問い合わせる
|
||
* @param what
|
||
* @return
|
||
*/
|
||
public String queryString(final int what) {
|
||
return EGL14.eglQueryString(mEglDisplay, what);
|
||
}
|
||
|
||
/**
|
||
* GLESバージョンを取得する
|
||
* @return 1, 2または3
|
||
*/
|
||
@Override
|
||
public int getGlVersion() {
|
||
return mGlVersion;
|
||
}
|
||
|
||
/**
|
||
* EGLレンダリングコンテキストを取得する
|
||
* このEGLBaseインスタンスを使って生成したEglSurfaceをmakeCurrentした状態で
|
||
* eglGetCurrentContextを呼び出すのと一緒
|
||
* @return
|
||
*/
|
||
@Override
|
||
public Context getContext() {
|
||
return mContext;
|
||
}
|
||
|
||
/**
|
||
* EGLコンフィグを取得する
|
||
* @return
|
||
*/
|
||
@Override
|
||
public Config getConfig() {
|
||
return mEglConfig;
|
||
}
|
||
|
||
/**
|
||
* EGLレンダリングコンテキストとスレッドの紐付けを解除する
|
||
*/
|
||
@Override
|
||
public void makeDefault() {
|
||
// if (DEBUG) Log.v(TAG, "makeDefault:");
|
||
if (!EGL14.eglMakeCurrent(mEglDisplay,
|
||
EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) {
|
||
|
||
Log.w("TAG", "makeDefault" + EGL14.eglGetError());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* eglWaitGLとeglWaitNativeを呼ぶ
|
||
*
|
||
* eglWaitGL: コマンドキュー内のコマンドをすべて転送する, GLES20.glFinish()と同様の効果
|
||
* eglWaitNative: GPU側の描画処理が終了するまで実行をブロックする
|
||
*/
|
||
@Override
|
||
public void sync() {
|
||
EGL14.eglWaitGL(); // GLES20.glFinish()と同様の効果
|
||
EGL14.eglWaitNative(EGL14.EGL_CORE_NATIVE_ENGINE);
|
||
}
|
||
|
||
private void init(final int maxClientVersion, Context sharedContext,
|
||
final boolean withDepthBuffer, final int stencilBits, final boolean isRecordable) {
|
||
|
||
// if (DEBUG) Log.v(TAG, "init:");
|
||
if (mEglDisplay != EGL14.EGL_NO_DISPLAY) {
|
||
throw new RuntimeException("EGL already set up");
|
||
}
|
||
|
||
mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
|
||
if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
|
||
throw new RuntimeException("eglGetDisplay failed");
|
||
}
|
||
// EGLのバージョンを取得
|
||
final int[] version = new int[2];
|
||
if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
|
||
mEglDisplay = null;
|
||
throw new RuntimeException("eglInitialize failed");
|
||
}
|
||
|
||
sharedContext = (sharedContext != null) ? sharedContext : EGL_NO_CONTEXT;
|
||
|
||
EGLConfig config;
|
||
if (maxClientVersion >= 3) {
|
||
// GLES3で取得できるかどうか試してみる
|
||
config = getConfig(3, withDepthBuffer, stencilBits, isRecordable);
|
||
if (config != null) {
|
||
final EGLContext context = createContext(sharedContext, config, 3);
|
||
if (EGL14.eglGetError() == EGL14.EGL_SUCCESS) {
|
||
// ここは例外生成したくないのでcheckEglErrorの代わりに自前でチェック
|
||
mEglConfig = new Config(config);
|
||
mContext = new Context(context);
|
||
mGlVersion = 3;
|
||
}
|
||
}
|
||
}
|
||
// GLES3で取得できなかった時はGLES2を試みる
|
||
if ((maxClientVersion >= 2)
|
||
&& ((mContext == null) || (mContext.eglContext == EGL14.EGL_NO_CONTEXT))) {
|
||
|
||
config = getConfig(2, withDepthBuffer, stencilBits, isRecordable);
|
||
if (config == null) {
|
||
throw new RuntimeException("chooseConfig failed");
|
||
}
|
||
try {
|
||
// create EGL rendering context
|
||
final EGLContext context = createContext(sharedContext, config, 2);
|
||
checkEglError("eglCreateContext");
|
||
mEglConfig = new Config(config);
|
||
mContext = new Context(context);
|
||
mGlVersion = 2;
|
||
} catch (final Exception e) {
|
||
if (isRecordable) {
|
||
config = getConfig(2, withDepthBuffer, stencilBits, false);
|
||
if (config == null) {
|
||
throw new RuntimeException("chooseConfig failed");
|
||
}
|
||
// create EGL rendering context
|
||
final EGLContext context = createContext(sharedContext, config, 2);
|
||
checkEglError("eglCreateContext");
|
||
mEglConfig = new Config(config);
|
||
mContext = new Context(context);
|
||
mGlVersion = 2;
|
||
}
|
||
}
|
||
}
|
||
if ((mContext == null) || (mContext.eglContext == EGL14.EGL_NO_CONTEXT)) {
|
||
config = getConfig(1, withDepthBuffer, stencilBits, isRecordable);
|
||
if (config == null) {
|
||
throw new RuntimeException("chooseConfig failed");
|
||
}
|
||
// create EGL rendering context
|
||
final EGLContext context = createContext(sharedContext, config, 1);
|
||
checkEglError("eglCreateContext");
|
||
mEglConfig = new Config(config);
|
||
mContext = new Context(context);
|
||
mGlVersion = 1;
|
||
}
|
||
// confirm whether the EGL rendering context is successfully created
|
||
final int[] values = new int[1];
|
||
EGL14.eglQueryContext(mEglDisplay,
|
||
mContext.eglContext, EGL14.EGL_CONTEXT_CLIENT_VERSION, values, 0);
|
||
Log.d(TAG, "EGLContext created, client version " + values[0]);
|
||
makeDefault(); // makeCurrent(EGL14.EGL_NO_SURFACE);
|
||
}
|
||
|
||
/**
|
||
* change context to draw this window surface
|
||
* @return
|
||
*/
|
||
private boolean makeCurrent(final EGLSurface surface) {
|
||
// if (DEBUG) Log.v(TAG, "makeCurrent:");
|
||
/* if (mEglDisplay == null) {
|
||
if (DEBUG) Log.d(TAG, "makeCurrent:eglDisplay not initialized");
|
||
} */
|
||
if (surface == null || surface == EGL14.EGL_NO_SURFACE) {
|
||
final int error = EGL14.eglGetError();
|
||
if (error == EGL14.EGL_BAD_NATIVE_WINDOW) {
|
||
Log.e(TAG, "makeCurrent:returned EGL_BAD_NATIVE_WINDOW.");
|
||
}
|
||
return false;
|
||
}
|
||
// attach EGL rendering context to specific EGL window surface
|
||
if (!EGL14.eglMakeCurrent(mEglDisplay, surface, surface, mContext.eglContext)) {
|
||
Log.w("TAG", "eglMakeCurrent" + EGL14.eglGetError());
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
private int swap(final EGLSurface surface) {
|
||
// if (DEBUG) Log.v(TAG, "swap:");
|
||
if (!EGL14.eglSwapBuffers(mEglDisplay, surface)) {
|
||
final int err = EGL14.eglGetError();
|
||
// if (DEBUG) Log.w(TAG, "swap:err=" + err);
|
||
return err;
|
||
}
|
||
return EGL14.EGL_SUCCESS;
|
||
}
|
||
|
||
private int swap(final EGLSurface surface, final long presentationTimeNs) {
|
||
// if (DEBUG) Log.v(TAG, "swap:");
|
||
EGLExt.eglPresentationTimeANDROID(mEglDisplay, surface, presentationTimeNs);
|
||
if (!EGL14.eglSwapBuffers(mEglDisplay, surface)) {
|
||
final int err = EGL14.eglGetError();
|
||
// if (DEBUG) Log.w(TAG, "swap:err=" + err);
|
||
return err;
|
||
}
|
||
return EGL14.EGL_SUCCESS;
|
||
}
|
||
|
||
private EGLContext createContext(final Context sharedContext,
|
||
final EGLConfig config, final int version) {
|
||
|
||
// if (DEBUG) Log.v(TAG, "createContext:");
|
||
|
||
final int[] attrib_list = {
|
||
EGL14.EGL_CONTEXT_CLIENT_VERSION, version,
|
||
EGL14.EGL_NONE
|
||
};
|
||
final EGLContext context = EGL14.eglCreateContext(mEglDisplay,
|
||
config, sharedContext.eglContext, attrib_list, 0);
|
||
// checkEglError("eglCreateContext");
|
||
return context;
|
||
}
|
||
|
||
private void destroyContext() {
|
||
// if (DEBUG) Log.v(TAG, "destroyContext:");
|
||
|
||
if (!EGL14.eglDestroyContext(mEglDisplay, mContext.eglContext)) {
|
||
Log.e("destroyContext", "display:" + mEglDisplay
|
||
+ " context: " + mContext.eglContext);
|
||
Log.e(TAG, "eglDestroyContext:" + EGL14.eglGetError());
|
||
}
|
||
mContext = EGL_NO_CONTEXT;
|
||
if (mDefaultContext != EGL14.EGL_NO_CONTEXT) {
|
||
if (!EGL14.eglDestroyContext(mEglDisplay, mDefaultContext)) {
|
||
Log.e("destroyContext", "display:" + mEglDisplay
|
||
+ " context: " + mDefaultContext);
|
||
Log.e(TAG, "eglDestroyContext:" + EGL14.eglGetError());
|
||
}
|
||
mDefaultContext = EGL14.EGL_NO_CONTEXT;
|
||
}
|
||
}
|
||
|
||
private final int[] mSurfaceDimension = new int[2];
|
||
private final int getSurfaceWidth(final EGLSurface surface) {
|
||
final boolean ret = EGL14.eglQuerySurface(mEglDisplay,
|
||
surface, EGL14.EGL_WIDTH, mSurfaceDimension, 0);
|
||
if (!ret) mSurfaceDimension[0] = 0;
|
||
return mSurfaceDimension[0];
|
||
}
|
||
|
||
private final int getSurfaceHeight(final EGLSurface surface) {
|
||
final boolean ret = EGL14.eglQuerySurface(mEglDisplay,
|
||
surface, EGL14.EGL_HEIGHT, mSurfaceDimension, 1);
|
||
if (!ret) mSurfaceDimension[1] = 0;
|
||
return mSurfaceDimension[1];
|
||
}
|
||
|
||
/**
|
||
* nativeWindow should be one of the Surface, SurfaceHolder and SurfaceTexture
|
||
* @param nativeWindow
|
||
* @return
|
||
*/
|
||
private final EGLSurface createWindowSurface(final Object nativeWindow) {
|
||
// if (DEBUG) Log.v(TAG, "createWindowSurface:nativeWindow=" + nativeWindow);
|
||
|
||
final int[] surfaceAttribs = {
|
||
EGL14.EGL_NONE
|
||
};
|
||
EGLSurface result = null;
|
||
try {
|
||
result = EGL14.eglCreateWindowSurface(mEglDisplay,
|
||
mEglConfig.eglConfig, nativeWindow, surfaceAttribs, 0);
|
||
if (result == null || result == EGL14.EGL_NO_SURFACE) {
|
||
final int error = EGL14.eglGetError();
|
||
if (error == EGL14.EGL_BAD_NATIVE_WINDOW) {
|
||
Log.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
|
||
}
|
||
throw new RuntimeException("createWindowSurface failed error=" + error);
|
||
}
|
||
makeCurrent(result);
|
||
// 画面サイズ・フォーマットの取得
|
||
} catch (final Exception e) {
|
||
Log.e(TAG, "eglCreateWindowSurface", e);
|
||
throw new IllegalArgumentException(e);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates an EGL surface associated with an offscreen buffer.
|
||
*/
|
||
private final EGLSurface createOffscreenSurface(final int width, final int height) {
|
||
// if (DEBUG) Log.v(TAG, "createOffscreenSurface:");
|
||
final int[] surfaceAttribs = {
|
||
EGL14.EGL_WIDTH, width,
|
||
EGL14.EGL_HEIGHT, height,
|
||
EGL14.EGL_NONE
|
||
};
|
||
EGLSurface result = null;
|
||
try {
|
||
result = EGL14.eglCreatePbufferSurface(mEglDisplay,
|
||
mEglConfig.eglConfig, surfaceAttribs, 0);
|
||
checkEglError("eglCreatePbufferSurface");
|
||
if (result == null) {
|
||
throw new RuntimeException("surface was null");
|
||
}
|
||
} catch (final IllegalArgumentException e) {
|
||
Log.e(TAG, "createOffscreenSurface", e);
|
||
} catch (final RuntimeException e) {
|
||
Log.e(TAG, "createOffscreenSurface", e);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
private void destroyWindowSurface(EGLSurface surface) {
|
||
// if (DEBUG) Log.v(TAG, "destroySurface:");
|
||
|
||
if (surface != EGL14.EGL_NO_SURFACE) {
|
||
EGL14.eglMakeCurrent(mEglDisplay,
|
||
EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
|
||
EGL14.eglDestroySurface(mEglDisplay, surface);
|
||
}
|
||
surface = EGL14.EGL_NO_SURFACE;
|
||
// if (DEBUG) Log.v(TAG, "destroySurface:finished");
|
||
}
|
||
|
||
private void checkEglError(final String msg) {
|
||
int error;
|
||
if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
|
||
throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));
|
||
}
|
||
}
|
||
|
||
private EGLConfig getConfig(final int version,
|
||
final boolean hasDepthBuffer, final int stencilBits, final boolean isRecordable) {
|
||
|
||
int renderableType = EGL_OPENGL_ES2_BIT;
|
||
if (version >= 3) {
|
||
renderableType |= EGL_OPENGL_ES3_BIT_KHR;
|
||
}
|
||
final int[] attribList = {
|
||
EGL14.EGL_RENDERABLE_TYPE, renderableType,
|
||
EGL14.EGL_RED_SIZE, 8,
|
||
EGL14.EGL_GREEN_SIZE, 8,
|
||
EGL14.EGL_BLUE_SIZE, 8,
|
||
EGL14.EGL_ALPHA_SIZE, 8,
|
||
// EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT | swapBehavior,
|
||
EGL14.EGL_NONE, EGL14.EGL_NONE, //EGL14.EGL_STENCIL_SIZE, 8,
|
||
// this flag need to recording of MediaCodec
|
||
EGL14.EGL_NONE, EGL14.EGL_NONE, //EGL_RECORDABLE_ANDROID, 1,
|
||
EGL14.EGL_NONE, EGL14.EGL_NONE, // with_depth_buffer ? EGL14.EGL_DEPTH_SIZE : EGL14.EGL_NONE,
|
||
// with_depth_buffer ? 16 : 0,
|
||
EGL14.EGL_NONE
|
||
};
|
||
int offset = 10;
|
||
if (stencilBits > 0) { // ステンシルバッファ(常時未使用)
|
||
attribList[offset++] = EGL14.EGL_STENCIL_SIZE;
|
||
attribList[offset++] = stencilBits;
|
||
}
|
||
if (hasDepthBuffer) { // デプスバッファ
|
||
attribList[offset++] = EGL14.EGL_DEPTH_SIZE;
|
||
attribList[offset++] = 16;
|
||
}
|
||
if (isRecordable && BuildCheck.isAndroid4_3()) {// MediaCodecの入力用Surfaceの場合
|
||
attribList[offset++] = EGL_RECORDABLE_ANDROID;
|
||
attribList[offset++] = 1;
|
||
}
|
||
for (int i = attribList.length - 1; i >= offset; i--) {
|
||
attribList[i] = EGL14.EGL_NONE;
|
||
}
|
||
EGLConfig config = internalGetConfig(attribList);
|
||
if ((config == null) && (version == 2)) {
|
||
if (isRecordable) {
|
||
// EGL_RECORDABLE_ANDROIDをつけると失敗する機種もあるので取り除く
|
||
final int n = attribList.length;
|
||
for (int i = 10; i < n - 1; i += 2) {
|
||
if (attribList[i] == EGL_RECORDABLE_ANDROID) {
|
||
for (int j = i; j < n; j++) {
|
||
attribList[j] = EGL14.EGL_NONE;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
config = internalGetConfig(attribList);
|
||
}
|
||
}
|
||
if (config == null) {
|
||
Log.w(TAG, "try to fallback to RGB565");
|
||
attribList[3] = 5;
|
||
attribList[5] = 6;
|
||
attribList[7] = 5;
|
||
config = internalGetConfig(attribList);
|
||
}
|
||
return config;
|
||
}
|
||
|
||
private EGLConfig internalGetConfig(final int[] attribList) {
|
||
final EGLConfig[] configs = new EGLConfig[1];
|
||
final int[] numConfigs = new int[1];
|
||
if (!EGL14.eglChooseConfig(mEglDisplay,
|
||
attribList, 0, configs, 0, configs.length, numConfigs, 0)) {
|
||
return null;
|
||
}
|
||
return configs[0];
|
||
}
|
||
}
|