Project

General

Profile

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

examples / src / main / java / org / distorted / examples / plainmonalisa / EglCore.java @ 7bf107f7

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.util.Log;
30
import android.view.Surface;
31

    
32
///////////////////////////////////////////////////////////////////////////////////////////////////
33

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

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

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

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

    
50
///////////////////////////////////////////////////////////////////////////////////////////////////
51

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

    
57
///////////////////////////////////////////////////////////////////////////////////////////////////
58

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

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

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

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

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

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

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

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

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

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

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

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

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

    
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132

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

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

    
142
    // The actual surface is generally RGBA or RGBX, so situationally omitting alpha
143
    // doesn't really help.  It can also lead to a huge performance hit on glReadPixels()
144
    // when reading into a GL_RGBA buffer.
145
    int[] attribList =
146
                {
147
                EGL14.EGL_RED_SIZE, 8,
148
                EGL14.EGL_GREEN_SIZE, 8,
149
                EGL14.EGL_BLUE_SIZE, 8,
150
                EGL14.EGL_ALPHA_SIZE, 8,
151
                //EGL14.EGL_DEPTH_SIZE, 16,
152
                //EGL14.EGL_STENCIL_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
      attribList[attribList.length - 3] = EGL_RECORDABLE_ANDROID;
161
      attribList[attribList.length - 2] = 1;
162
      }
163

    
164
    EGLConfig[] configs = new EGLConfig[1];
165
    int[] numConfigs = new int[1];
166

    
167
    if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length, numConfigs, 0))
168
      {
169
      Log.w(TAG, "unable to find RGB8888 / " + version + " EGLConfig");
170
      return null;
171
      }
172

    
173
    return configs[0];
174
    }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177

    
178
  public void release()
179
    {
180
    if (mEGLDisplay != EGL14.EGL_NO_DISPLAY)
181
      {
182
      EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
183
      EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
184
      EGL14.eglReleaseThread();
185
      EGL14.eglTerminate(mEGLDisplay);
186
      }
187

    
188
    mEGLDisplay = EGL14.EGL_NO_DISPLAY;
189
    mEGLContext = EGL14.EGL_NO_CONTEXT;
190
    mEGLConfig = null;
191
    }
192

    
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194
  @Override
195
  protected void finalize() throws Throwable
196
    {
197
    try
198
      {
199
      if (mEGLDisplay != EGL14.EGL_NO_DISPLAY)
200
        {
201
        // We're limited here -- finalizers don't run on the thread that holds
202
        // the EGL state, so if a surface or context is still current on another
203
        // thread we can't fully release it here.  Exceptions thrown from here
204
        // are quietly discarded.  Complain in the log file.
205
        Log.w(TAG, "WARNING: EglCore was not explicitly released -- state may be leaked");
206
        release();
207
        }
208
      }
209
    finally
210
      {
211
      super.finalize();
212
      }
213
    }
214

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216

    
217
  public void releaseSurface(EGLSurface eglSurface)
218
    {
219
    EGL14.eglDestroySurface(mEGLDisplay, eglSurface);
220
    }
221

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

    
224
  public EGLSurface createWindowSurface(Object surface)
225
    {
226
    if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture))
227
      {
228
      throw new RuntimeException("invalid surface: " + surface);
229
      }
230

    
231
    int[] surfaceAttribs = { EGL14.EGL_NONE };
232
    EGLSurface eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface, surfaceAttribs, 0);
233
    checkEglError("eglCreateWindowSurface");
234

    
235
    if (eglSurface == null)
236
      {
237
      throw new RuntimeException("surface was null");
238
      }
239
    return eglSurface;
240
    }
241

    
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243

    
244
  public void makeCurrent(EGLSurface eglSurface)
245
    {
246
    if (mEGLDisplay == EGL14.EGL_NO_DISPLAY)
247
      {
248
      Log.d(TAG, "NOTE: makeCurrent w/o display");
249
      }
250
    if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext))
251
      {
252
      throw new RuntimeException("eglMakeCurrent failed");
253
      }
254
    }
255

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257

    
258
  public void makeNothingCurrent()
259
    {
260
    if (!EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT))
261
      {
262
      throw new RuntimeException("eglMakeCurrent failed");
263
      }
264
    }
265

    
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267

    
268
  public int getGlVersion()
269
    {
270
    return mGlVersion;
271
    }
272

    
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274

    
275
  public boolean swapBuffers(EGLSurface eglSurface)
276
    {
277
    return EGL14.eglSwapBuffers(mEGLDisplay, eglSurface);
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  private void checkEglError(String msg)
283
    {
284
    int error;
285

    
286
    if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS)
287
      {
288
      throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));
289
      }
290
    }
291
  }
(1-1/5)