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