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