Project

General

Profile

Download (11.3 KB) Statistics
| Branch: | Revision:

examples / src / main / java / org / distorted / examples / plainmonalisa / EglCore.java @ f6d884d5

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.examples.plainmonalisa;
21

    
22
import android.graphics.SurfaceTexture;
23
import android.opengl.EGL14;
24
import android.opengl.EGLConfig;
25
import android.opengl.EGLContext;
26
import android.opengl.EGLDisplay;
27
import android.opengl.EGLExt;
28
import android.opengl.EGLSurface;
29
import android.os.Build;
30
import android.util.Log;
31
import android.view.Surface;
32

    
33
///////////////////////////////////////////////////////////////////////////////////////////////////
34

    
35
public final class EglCore
36
  {
37
  private static final String TAG = "EglCore";
38

    
39
  public static final int FLAG_RECORDABLE = 0x01;           // Surface must be recordable.  This discourages EGL from using a
40
                                                            // pixel format that cannot be converted efficiently to something 
41
                                                            // usable by the video encoder.
42
  public static final int FLAG_TRY_GLES3 = 0x02;            // Ask for GLES3, fall back to GLES2 if not available.
43

    
44
  private static final int EGL_RECORDABLE_ANDROID = 0x3142; // Android-specific extension
45

    
46
  private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
47
  private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;
48
  private EGLConfig mEGLConfig = null;
49
  private int mGlVersion = -1;
50

    
51
///////////////////////////////////////////////////////////////////////////////////////////////////
52

    
53
  public EglCore()
54
    {
55
    this(null, 0);
56
    }
57

    
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59

    
60
  public EglCore(EGLContext sharedContext, int flags)
61
    {
62
    if (mEGLDisplay != EGL14.EGL_NO_DISPLAY)
63
      {
64
      throw new RuntimeException("EGL already set up");
65
      }
66

    
67
    if (sharedContext == null)
68
      {
69
      sharedContext = EGL14.EGL_NO_CONTEXT;
70
      }
71

    
72
    mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
73

    
74
    if (mEGLDisplay == EGL14.EGL_NO_DISPLAY)
75
      {
76
      throw new RuntimeException("unable to get EGL14 display");
77
      }
78

    
79
    int[] version = new int[2];
80

    
81
    if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1))
82
      {
83
      mEGLDisplay = null;
84
      throw new RuntimeException("unable to initialize EGL14");
85
      }
86

    
87
    // Try to get a GLES3 context, if requested.
88
    if ((flags & FLAG_TRY_GLES3) != 0)
89
      {
90
      //Log.d(TAG, "Trying GLES 3");
91
      EGLConfig config = getConfig(flags, 3);
92

    
93
      if (config != null)
94
        {
95
        int[] attrib3_list =  { EGL14.EGL_CONTEXT_CLIENT_VERSION, 3, EGL14.EGL_NONE };
96
        EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext, attrib3_list, 0);
97

    
98
        if (EGL14.eglGetError() == EGL14.EGL_SUCCESS)
99
          {
100
          //Log.d(TAG, "Got GLES 3 config");
101
          mEGLConfig = config;
102
          mEGLContext = context;
103
          mGlVersion = 3;
104
          }
105
        }
106
      }
107

    
108
    if (mEGLContext == EGL14.EGL_NO_CONTEXT)
109
      {  // GLES 2 only, or GLES 3 attempt failed
110
         //Log.d(TAG, "Trying GLES 2");
111
      EGLConfig config = getConfig(flags, 2);
112

    
113
      if (config == null)
114
        {
115
        throw new RuntimeException("Unable to find a suitable EGLConfig");
116
        }
117
      int[] attrib2_list = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE };
118
      EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext, attrib2_list, 0);
119
      checkEglError("eglCreateContext");
120
      mEGLConfig = config;
121
      mEGLContext = context;
122
      mGlVersion = 2;
123
      }
124

    
125
    // Confirm with query.
126
    int[] values = new int[1];
127
    EGL14.eglQueryContext(mEGLDisplay, mEGLContext, EGL14.EGL_CONTEXT_CLIENT_VERSION, values, 0);
128

    
129
    Log.d(TAG, "EGLContext created, client version " + values[0]);
130
    }
131

    
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133

    
134
  private EGLConfig getConfig(int flags, int version)
135
    {
136
    int renderableType = EGL14.EGL_OPENGL_ES2_BIT;
137

    
138
    if (version >= 3)
139
      {
140
      renderableType |= EGLExt.EGL_OPENGL_ES3_BIT_KHR;
141
      }
142

    
143
    // The actual surface is generally RGBA or RGBX, so situationally omitting alpha
144
    // doesn't really help.  It can also lead to a huge performance hit on glReadPixels()
145
    // when reading into a GL_RGBA buffer.
146

    
147
    int [] normalAttribList =
148
                {
149
                EGL14.EGL_RED_SIZE, 8,
150
                EGL14.EGL_GREEN_SIZE, 8,
151
                EGL14.EGL_BLUE_SIZE, 8,
152
                EGL14.EGL_ALPHA_SIZE, 8,
153
                EGL14.EGL_RENDERABLE_TYPE, renderableType,
154
                EGL14.EGL_NONE, 0,      // placeholder for recordable [@-3]
155
                EGL14.EGL_NONE
156
                };
157

    
158
    if ((flags & FLAG_RECORDABLE) != 0)
159
      {
160
      normalAttribList[normalAttribList.length - 3] = EGL_RECORDABLE_ANDROID;
161
      normalAttribList[normalAttribList.length - 2] = 1;
162
      }
163

    
164
    int [] emulatorAttribList =
165
                {
166
                EGL14.EGL_RED_SIZE, 8,
167
                EGL14.EGL_GREEN_SIZE, 8,
168
                EGL14.EGL_BLUE_SIZE, 8,
169
                EGL14.EGL_ALPHA_SIZE, 8,
170
                EGL14.EGL_DEPTH_SIZE, 16,
171
                EGL14.EGL_STENCIL_SIZE, 0,
172
                EGL14.EGL_NONE
173
                };
174

    
175
    boolean isEmulator=
176
               Build.FINGERPRINT.startsWith("generic")
177
            || Build.FINGERPRINT.startsWith("unknown")
178
            || Build.MODEL.contains("google_sdk")
179
            || Build.MODEL.contains("Emulator")
180
            || Build.MODEL.contains("Android SDK built for x86")
181
            || Build.MANUFACTURER.contains("Genymotion")
182
            || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
183
            || "google_sdk".equals(Build.PRODUCT);
184

    
185
    int [] attribList = (isEmulator ? emulatorAttribList:normalAttribList);
186

    
187
    if( isEmulator )
188
      {
189
      Log.w(TAG, "Using emulator config!" );
190
      }
191

    
192
    EGLConfig[] configs = new EGLConfig[1];
193
    int[] numConfigs = new int[1];
194

    
195
    if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length, numConfigs, 0))
196
      {
197
      Log.w(TAG, "unable to find RGB8888 / " + version + " EGLConfig");
198
      return null;
199
      }
200

    
201
    return configs[0];
202
    }
203

    
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205

    
206
  public void release()
207
    {
208
    if (mEGLDisplay != EGL14.EGL_NO_DISPLAY)
209
      {
210
      EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
211
      EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
212
      EGL14.eglReleaseThread();
213
      EGL14.eglTerminate(mEGLDisplay);
214
      }
215

    
216
    mEGLDisplay = EGL14.EGL_NO_DISPLAY;
217
    mEGLContext = EGL14.EGL_NO_CONTEXT;
218
    mEGLConfig = null;
219
    }
220

    
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222
  @Override
223
  protected void finalize() throws Throwable
224
    {
225
    try
226
      {
227
      if (mEGLDisplay != EGL14.EGL_NO_DISPLAY)
228
        {
229
        // We're limited here -- finalizers don't run on the thread that holds
230
        // the EGL state, so if a surface or context is still current on another
231
        // thread we can't fully release it here.  Exceptions thrown from here
232
        // are quietly discarded.  Complain in the log file.
233
        Log.w(TAG, "WARNING: EglCore was not explicitly released -- state may be leaked");
234
        release();
235
        }
236
      }
237
    finally
238
      {
239
      super.finalize();
240
      }
241
    }
242

    
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244

    
245
  public void releaseSurface(EGLSurface eglSurface)
246
    {
247
    EGL14.eglDestroySurface(mEGLDisplay, eglSurface);
248
    }
249

    
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251

    
252
  public EGLSurface createWindowSurface(Object surface)
253
    {
254
    if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture))
255
      {
256
      throw new RuntimeException("invalid surface: " + surface);
257
      }
258

    
259
    int[] surfaceAttribs = { EGL14.EGL_NONE };
260
    EGLSurface eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface, surfaceAttribs, 0);
261
    checkEglError("eglCreateWindowSurface");
262

    
263
    if (eglSurface == null)
264
      {
265
      throw new RuntimeException("surface was null");
266
      }
267
    return eglSurface;
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271

    
272
  public void makeCurrent(EGLSurface eglSurface)
273
    {
274
    if (mEGLDisplay == EGL14.EGL_NO_DISPLAY)
275
      {
276
      Log.d(TAG, "NOTE: makeCurrent w/o display");
277
      }
278
    if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext))
279
      {
280
      throw new RuntimeException("eglMakeCurrent failed");
281
      }
282
    }
283

    
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285

    
286
  public void makeNothingCurrent()
287
    {
288
    if (!EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT))
289
      {
290
      throw new RuntimeException("eglMakeCurrent failed");
291
      }
292
    }
293

    
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295

    
296
  public int getGlVersion()
297
    {
298
    return mGlVersion;
299
    }
300

    
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302

    
303
  public boolean swapBuffers(EGLSurface eglSurface)
304
    {
305
    return EGL14.eglSwapBuffers(mEGLDisplay, eglSurface);
306
    }
307

    
308
///////////////////////////////////////////////////////////////////////////////////////////////////
309

    
310
  private void checkEglError(String msg)
311
    {
312
    int error;
313

    
314
    if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS)
315
      {
316
      throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));
317
      }
318
    }
319
  }
(1-1/5)