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