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