gl_env.cpp revision 52a9a10b6b8c7b7a9f97777541841b94d4fd9754
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> >(bq));
166
167  surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL);
168  if (CheckEGLError("eglCreateWindowSurface")) return false;
169
170  // Create context
171  EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
172  contexts_[0] = eglCreateContext(display(),
173                                  config,
174                                  EGL_NO_CONTEXT,
175                                  context_attribs);
176  if (CheckEGLError("eglCreateContext")) return false;
177
178  created_context_ = created_surface_ = true;
179
180  return true;
181}
182
183bool GLEnv::IsActive() const {
184  ALOGV("IsActive()");
185  return context() == eglGetCurrentContext()
186    &&   display() == eglGetCurrentDisplay()
187    &&   surface() == eglGetCurrentSurface(EGL_DRAW);
188}
189
190bool GLEnv::IsContextActive() const {
191  return context() == eglGetCurrentContext();
192}
193
194bool GLEnv::IsAnyContextActive() {
195  return eglGetCurrentContext() != EGL_NO_CONTEXT;
196}
197
198int GLEnv::AddWindowSurface(const EGLSurface& surface, WindowHandle* window_handle) {
199  const int id = ++max_surface_id_;
200  surfaces_[id] = SurfaceWindowPair(surface, window_handle);
201  return id;
202}
203
204int GLEnv::AddSurface(const EGLSurface& surface) {
205  return AddWindowSurface(surface, NULL);
206}
207
208bool GLEnv::SwitchToSurfaceId(int surface_id) {
209  ALOGV("SwitchToSurfaceId");
210  if (surface_id_ != surface_id) {
211    const SurfaceWindowPair* surface = FindOrNull(surfaces_, surface_id);
212    if (surface) {
213      bool wasActive = IsActive();
214      surface_id_ = surface_id;
215      return wasActive ? Activate() : true;
216    }
217    return false;
218  }
219  return true;
220}
221
222bool GLEnv::ReleaseSurfaceId(int surface_id) {
223  if (surface_id > 0) {
224    const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_, surface_id);
225    if (surface_window_pair) {
226      if (surface_id_ == surface_id)
227        SwitchToSurfaceId(0);
228      eglDestroySurface(display(), surface_window_pair->first);
229      if (surface_window_pair->second) {
230        surface_window_pair->second->Destroy();
231        delete surface_window_pair->second;
232      }
233      surfaces_.erase(surface_id);
234      return true;
235    }
236  }
237  return false;
238}
239
240bool GLEnv::SetSurfaceTimestamp(int64_t timestamp) {
241  if (surface_id_ > 0) {
242    const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_,
243            surface_id_);
244    if (surface_window_pair) {
245      ANativeWindow *window = static_cast<ANativeWindow*>(
246              surface_window_pair->second->InternalHandle());
247      native_window_set_buffers_timestamp(window, timestamp);
248      return true;
249    }
250  }
251  return false;
252}
253
254int GLEnv::FindSurfaceIdForWindow(const WindowHandle* window_handle) {
255  for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin();
256       it != surfaces_.end();
257       ++it) {
258    const WindowHandle* my_handle = it->second.second;
259    if (my_handle && my_handle->Equals(window_handle)) {
260      return it->first;
261    }
262  }
263  return -1;
264}
265
266
267int GLEnv::AddContext(const EGLContext& context) {
268  const int id = contexts_.size();
269  contexts_[id] = context;
270  return id;
271}
272
273bool GLEnv::SwitchToContextId(int context_id) {
274  const EGLContext* context = FindOrNull(contexts_, context_id);
275  if (context) {
276    if (context_id_ != context_id) {
277      context_id_ = context_id;
278      return Activate();
279    }
280    return true;
281  }
282  return false;
283}
284
285void GLEnv::ReleaseContextId(int context_id) {
286  if (context_id > 0) {
287    const EGLContext* context = FindOrNull(contexts_, context_id);
288    if (context) {
289      contexts_.erase(context_id);
290      if (context_id_ == context_id && IsActive())
291        SwitchToContextId(0);
292      eglDestroyContext(display(), *context);
293    }
294  }
295}
296
297bool GLEnv::CheckGLError(const std::string& op) {
298  bool err = false;
299  for (GLint error = glGetError(); error; error = glGetError()) {
300    ALOGE("GL Error: Operation '%s' caused GL error (0x%x)\n",
301         op.c_str(),
302         error);
303    err = true;
304  }
305  return err;
306}
307
308bool GLEnv::CheckEGLError(const std::string& op) {
309  bool err = false;
310  for (EGLint error = eglGetError();
311       error != EGL_SUCCESS;
312       error = eglGetError()) {
313    ALOGE("EGL Error: Operation '%s' caused EGL error (0x%x)\n",
314         op.c_str(),
315         error);
316    err = true;
317  }
318  return err;
319}
320
321bool GLEnv::CheckEGLMakeCurrentError() {
322  bool err = false;
323  for (EGLint error = eglGetError();
324       error != EGL_SUCCESS;
325       error = eglGetError()) {
326    switch (error) {
327      case EGL_BAD_DISPLAY:
328        ALOGE("EGL Error: Attempting to activate context with bad display!");
329        break;
330      case EGL_BAD_SURFACE:
331        ALOGE("EGL Error: Attempting to activate context with bad surface!");
332        break;
333      case EGL_BAD_ACCESS:
334        ALOGE("EGL Error: Attempting to activate context, which is "
335             "already active in another thread!");
336        break;
337      default:
338        ALOGE("EGL Error: Making EGL rendering context current caused "
339             "error: 0x%x\n", error);
340    }
341    err = true;
342  }
343  return err;
344}
345
346GLuint GLEnv::GetCurrentProgram() {
347  GLint result;
348  glGetIntegerv(GL_CURRENT_PROGRAM, &result);
349  ALOG_ASSERT(result >= 0);
350  return static_cast<GLuint>(result);
351}
352
353EGLDisplay GLEnv::GetCurrentDisplay() {
354  return eglGetCurrentDisplay();
355}
356
357int GLEnv::NumberOfComponents(GLenum type) {
358  switch (type) {
359    case GL_BOOL:
360    case GL_FLOAT:
361    case GL_INT:
362      return 1;
363    case GL_BOOL_VEC2:
364    case GL_FLOAT_VEC2:
365    case GL_INT_VEC2:
366      return 2;
367    case GL_INT_VEC3:
368    case GL_FLOAT_VEC3:
369    case GL_BOOL_VEC3:
370      return 3;
371    case GL_BOOL_VEC4:
372    case GL_FLOAT_VEC4:
373    case GL_INT_VEC4:
374    case GL_FLOAT_MAT2:
375      return 4;
376    case GL_FLOAT_MAT3:
377      return 9;
378    case GL_FLOAT_MAT4:
379      return 16;
380    default:
381      return 0;
382  }
383}
384
385void GLEnv::AttachShader(int key, ShaderProgram* shader) {
386  ShaderProgram* existingShader = ShaderWithKey(key);
387  if (existingShader)
388    delete existingShader;
389  attached_shaders_[key] = shader;
390}
391
392void GLEnv::AttachVertexFrame(int key, VertexFrame* frame) {
393  VertexFrame* existingFrame = VertexFrameWithKey(key);
394  if (existingFrame)
395    delete existingFrame;
396  attached_vframes_[key] = frame;
397}
398
399ShaderProgram* GLEnv::ShaderWithKey(int key) {
400  return FindPtrOrNull(attached_shaders_, key);
401}
402
403VertexFrame* GLEnv::VertexFrameWithKey(int key) {
404  return FindPtrOrNull(attached_vframes_, key);
405}
406
407} // namespace filterfw
408} // namespace android
409