gl_env.cpp revision e3eae73abb5e429d9747f9c36ab025219e68bb26
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16// #define LOG_NDEBUG 0
17
18#include "base/logging.h"
19#include "base/utilities.h"
20#include "core/gl_env.h"
21#include "core/shader_program.h"
22#include "core/vertex_frame.h"
23#include "system/window.h"
24
25#include <map>
26#include <string>
27#include <EGL/eglext.h>
28
29#include <gui/GLConsumer.h>
30
31namespace android {
32namespace filterfw {
33
34GLEnv::GLEnv()
35  : display_(EGL_NO_DISPLAY),
36    context_id_(0),
37    surface_id_(0),
38    max_surface_id_(0),
39    created_context_(false),
40    created_surface_(false),
41    initialized_(false) {
42}
43
44GLEnv::~GLEnv() {
45  // Destroy surfaces
46  for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin();
47       it != surfaces_.end();
48       ++it) {
49    if (it->first != 0 || created_surface_) {
50      eglDestroySurface(display(), it->second.first);
51      if (it->second.second) {
52        it->second.second->Destroy();
53        delete it->second.second;
54      }
55    }
56  }
57
58  // Destroy contexts
59  for (std::map<int, EGLContext>::iterator it = contexts_.begin();
60       it != contexts_.end();
61       ++it) {
62    if (it->first != 0 || created_context_)
63      eglDestroyContext(display(), it->second);
64  }
65
66  // Destroy attached shaders and frames
67  STLDeleteValues(&attached_shaders_);
68  STLDeleteValues(&attached_vframes_);
69
70  // Destroy display
71  if (initialized_)
72    eglTerminate(display());
73
74  // Log error if this did not work
75  if (CheckEGLError("TearDown!"))
76    ALOGE("GLEnv: Error tearing down GL Environment!");
77}
78
79bool GLEnv::IsInitialized() const {
80  return (contexts_.size() > 0 &&
81          surfaces_.size() > 0 &&
82          display_ != EGL_NO_DISPLAY);
83}
84
85bool GLEnv::Deactivate() {
86  eglMakeCurrent(display(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
87  return !CheckEGLError("eglMakeCurrent");
88}
89
90bool GLEnv::Activate() {
91  ALOGV("Activate()");
92  if (display()   != eglGetCurrentDisplay() ||
93      context()   != eglGetCurrentContext() ||
94      surface()   != eglGetCurrentSurface(EGL_DRAW)) {
95    // Make sure we are initialized
96    if (context() == EGL_NO_CONTEXT || surface() == EGL_NO_SURFACE)
97      return false;
98
99    // Make our context current
100    ALOGV("eglMakeCurrent");
101    eglMakeCurrent(display(), surface(), surface(), context());
102
103    return !CheckEGLMakeCurrentError();
104  }
105  return true;
106}
107
108bool GLEnv::SwapBuffers() {
109  const bool result = eglSwapBuffers(display(), surface()) == EGL_TRUE;
110  return !CheckEGLError("eglSwapBuffers") && result;
111}
112
113bool GLEnv::InitWithCurrentContext() {
114  if (IsInitialized())
115    return true;
116
117  display_     = eglGetCurrentDisplay();
118  contexts_[0] = eglGetCurrentContext();
119  surfaces_[0] = SurfaceWindowPair(eglGetCurrentSurface(EGL_DRAW), NULL);
120
121  return (context() != EGL_NO_CONTEXT) &&
122         (display() != EGL_NO_DISPLAY) &&
123         (surface() != EGL_NO_SURFACE);
124}
125
126bool GLEnv::InitWithNewContext() {
127  if (IsInitialized()) {
128    ALOGE("GLEnv: Attempting to reinitialize environment!");
129    return false;
130  }
131
132  display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
133  if (CheckEGLError("eglGetDisplay")) return false;
134
135  EGLint majorVersion;
136  EGLint minorVersion;
137  eglInitialize(display(), &majorVersion, &minorVersion);
138  if (CheckEGLError("eglInitialize")) return false;
139  initialized_ = true;
140
141  // Configure context/surface
142  EGLConfig config;
143  EGLint numConfigs = -1;
144
145  // TODO(renn): Do we need the window bit here?
146  // TODO: Currently choosing the config that includes all
147  // This is not needed if the encoding is not being used
148  EGLint configAttribs[] = {
149    EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
150    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
151    EGL_RED_SIZE, 8,
152    EGL_GREEN_SIZE, 8,
153    EGL_BLUE_SIZE, 8,
154    EGL_RECORDABLE_ANDROID, EGL_TRUE,
155    EGL_NONE
156  };
157
158  eglChooseConfig(display(), configAttribs, &config, 1, &numConfigs);
159  if (numConfigs < 1) {
160    ALOGE("GLEnv::Init: No suitable EGL configuration found!");
161    return false;
162  }
163
164  // Create dummy surface using a GLConsumer
165  sp<BufferQueue> bq = new BufferQueue();
166  surfaceTexture_ = new GLConsumer(bq, 0);
167  window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >(bq));
168
169  surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL);
170  if (CheckEGLError("eglCreateWindowSurface")) return false;
171
172  // Create context
173  EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
174  contexts_[0] = eglCreateContext(display(),
175                                  config,
176                                  EGL_NO_CONTEXT,
177                                  context_attribs);
178  if (CheckEGLError("eglCreateContext")) return false;
179
180  created_context_ = created_surface_ = true;
181
182  return true;
183}
184
185bool GLEnv::IsActive() const {
186  ALOGV("IsActive()");
187  return context() == eglGetCurrentContext()
188    &&   display() == eglGetCurrentDisplay()
189    &&   surface() == eglGetCurrentSurface(EGL_DRAW);
190}
191
192bool GLEnv::IsContextActive() const {
193  return context() == eglGetCurrentContext();
194}
195
196bool GLEnv::IsAnyContextActive() {
197  return eglGetCurrentContext() != EGL_NO_CONTEXT;
198}
199
200int GLEnv::AddWindowSurface(const EGLSurface& surface, WindowHandle* window_handle) {
201  const int id = ++max_surface_id_;
202  surfaces_[id] = SurfaceWindowPair(surface, window_handle);
203  return id;
204}
205
206int GLEnv::AddSurface(const EGLSurface& surface) {
207  return AddWindowSurface(surface, NULL);
208}
209
210bool GLEnv::SwitchToSurfaceId(int surface_id) {
211  ALOGV("SwitchToSurfaceId");
212  if (surface_id_ != surface_id) {
213    const SurfaceWindowPair* surface = FindOrNull(surfaces_, surface_id);
214    if (surface) {
215      bool wasActive = IsActive();
216      surface_id_ = surface_id;
217      return wasActive ? Activate() : true;
218    }
219    return false;
220  }
221  return true;
222}
223
224bool GLEnv::ReleaseSurfaceId(int surface_id) {
225  if (surface_id > 0) {
226    const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_, surface_id);
227    if (surface_window_pair) {
228      if (surface_id_ == surface_id)
229        SwitchToSurfaceId(0);
230      eglDestroySurface(display(), surface_window_pair->first);
231      if (surface_window_pair->second) {
232        surface_window_pair->second->Destroy();
233        delete surface_window_pair->second;
234      }
235      surfaces_.erase(surface_id);
236      return true;
237    }
238  }
239  return false;
240}
241
242bool GLEnv::SetSurfaceTimestamp(int64_t timestamp) {
243  if (surface_id_ > 0) {
244    const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_,
245            surface_id_);
246    if (surface_window_pair) {
247      ANativeWindow *window = static_cast<ANativeWindow*>(
248              surface_window_pair->second->InternalHandle());
249      native_window_set_buffers_timestamp(window, timestamp);
250      return true;
251    }
252  }
253  return false;
254}
255
256int GLEnv::FindSurfaceIdForWindow(const WindowHandle* window_handle) {
257  for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin();
258       it != surfaces_.end();
259       ++it) {
260    const WindowHandle* my_handle = it->second.second;
261    if (my_handle && my_handle->Equals(window_handle)) {
262      return it->first;
263    }
264  }
265  return -1;
266}
267
268
269int GLEnv::AddContext(const EGLContext& context) {
270  const int id = contexts_.size();
271  contexts_[id] = context;
272  return id;
273}
274
275bool GLEnv::SwitchToContextId(int context_id) {
276  const EGLContext* context = FindOrNull(contexts_, context_id);
277  if (context) {
278    if (context_id_ != context_id) {
279      context_id_ = context_id;
280      return Activate();
281    }
282    return true;
283  }
284  return false;
285}
286
287void GLEnv::ReleaseContextId(int context_id) {
288  if (context_id > 0) {
289    const EGLContext* context = FindOrNull(contexts_, context_id);
290    if (context) {
291      contexts_.erase(context_id);
292      if (context_id_ == context_id && IsActive())
293        SwitchToContextId(0);
294      eglDestroyContext(display(), *context);
295    }
296  }
297}
298
299bool GLEnv::CheckGLError(const std::string& op) {
300  bool err = false;
301  for (GLint error = glGetError(); error; error = glGetError()) {
302    ALOGE("GL Error: Operation '%s' caused GL error (0x%x)\n",
303         op.c_str(),
304         error);
305    err = true;
306  }
307  return err;
308}
309
310bool GLEnv::CheckEGLError(const std::string& op) {
311  bool err = false;
312  for (EGLint error = eglGetError();
313       error != EGL_SUCCESS;
314       error = eglGetError()) {
315    ALOGE("EGL Error: Operation '%s' caused EGL error (0x%x)\n",
316         op.c_str(),
317         error);
318    err = true;
319  }
320  return err;
321}
322
323bool GLEnv::CheckEGLMakeCurrentError() {
324  bool err = false;
325  for (EGLint error = eglGetError();
326       error != EGL_SUCCESS;
327       error = eglGetError()) {
328    switch (error) {
329      case EGL_BAD_DISPLAY:
330        ALOGE("EGL Error: Attempting to activate context with bad display!");
331        break;
332      case EGL_BAD_SURFACE:
333        ALOGE("EGL Error: Attempting to activate context with bad surface!");
334        break;
335      case EGL_BAD_ACCESS:
336        ALOGE("EGL Error: Attempting to activate context, which is "
337             "already active in another thread!");
338        break;
339      default:
340        ALOGE("EGL Error: Making EGL rendering context current caused "
341             "error: 0x%x\n", error);
342    }
343    err = true;
344  }
345  return err;
346}
347
348GLuint GLEnv::GetCurrentProgram() {
349  GLint result;
350  glGetIntegerv(GL_CURRENT_PROGRAM, &result);
351  ALOG_ASSERT(result >= 0);
352  return static_cast<GLuint>(result);
353}
354
355EGLDisplay GLEnv::GetCurrentDisplay() {
356  return eglGetCurrentDisplay();
357}
358
359int GLEnv::NumberOfComponents(GLenum type) {
360  switch (type) {
361    case GL_BOOL:
362    case GL_FLOAT:
363    case GL_INT:
364      return 1;
365    case GL_BOOL_VEC2:
366    case GL_FLOAT_VEC2:
367    case GL_INT_VEC2:
368      return 2;
369    case GL_INT_VEC3:
370    case GL_FLOAT_VEC3:
371    case GL_BOOL_VEC3:
372      return 3;
373    case GL_BOOL_VEC4:
374    case GL_FLOAT_VEC4:
375    case GL_INT_VEC4:
376    case GL_FLOAT_MAT2:
377      return 4;
378    case GL_FLOAT_MAT3:
379      return 9;
380    case GL_FLOAT_MAT4:
381      return 16;
382    default:
383      return 0;
384  }
385}
386
387void GLEnv::AttachShader(int key, ShaderProgram* shader) {
388  ShaderProgram* existingShader = ShaderWithKey(key);
389  if (existingShader)
390    delete existingShader;
391  attached_shaders_[key] = shader;
392}
393
394void GLEnv::AttachVertexFrame(int key, VertexFrame* frame) {
395  VertexFrame* existingFrame = VertexFrameWithKey(key);
396  if (existingFrame)
397    delete existingFrame;
398  attached_vframes_[key] = frame;
399}
400
401ShaderProgram* GLEnv::ShaderWithKey(int key) {
402  return FindPtrOrNull(attached_shaders_, key);
403}
404
405VertexFrame* GLEnv::VertexFrameWithKey(int key) {
406  return FindPtrOrNull(attached_vframes_, key);
407}
408
409} // namespace filterfw
410} // namespace android
411