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 
31 namespace android {
32 namespace filterfw {
33 
GLEnv()34 GLEnv::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 
~GLEnv()44 GLEnv::~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 
IsInitialized() const79 bool GLEnv::IsInitialized() const {
80   return (contexts_.size() > 0 &&
81           surfaces_.size() > 0 &&
82           display_ != EGL_NO_DISPLAY);
83 }
84 
Deactivate()85 bool GLEnv::Deactivate() {
86   eglMakeCurrent(display(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
87   return !CheckEGLError("eglMakeCurrent");
88 }
89 
Activate()90 bool 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 
SwapBuffers()108 bool GLEnv::SwapBuffers() {
109   const bool result = eglSwapBuffers(display(), surface()) == EGL_TRUE;
110   return !CheckEGLError("eglSwapBuffers") && result;
111 }
112 
InitWithCurrentContext()113 bool 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 
InitWithNewContext()126 bool 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 
IsActive() const188 bool GLEnv::IsActive() const {
189   ALOGV("IsActive()");
190   return context() == eglGetCurrentContext()
191     &&   display() == eglGetCurrentDisplay()
192     &&   surface() == eglGetCurrentSurface(EGL_DRAW);
193 }
194 
IsContextActive() const195 bool GLEnv::IsContextActive() const {
196   return context() == eglGetCurrentContext();
197 }
198 
IsAnyContextActive()199 bool GLEnv::IsAnyContextActive() {
200   return eglGetCurrentContext() != EGL_NO_CONTEXT;
201 }
202 
AddWindowSurface(const EGLSurface & surface,WindowHandle * window_handle)203 int 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 
AddSurface(const EGLSurface & surface)209 int GLEnv::AddSurface(const EGLSurface& surface) {
210   return AddWindowSurface(surface, NULL);
211 }
212 
SwitchToSurfaceId(int surface_id)213 bool 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 
ReleaseSurfaceId(int surface_id)227 bool 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 
SetSurfaceTimestamp(int64_t timestamp)245 bool 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 
FindSurfaceIdForWindow(const WindowHandle * window_handle)259 int 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 
AddContext(const EGLContext & context)272 int GLEnv::AddContext(const EGLContext& context) {
273   const int id = contexts_.size();
274   contexts_[id] = context;
275   return id;
276 }
277 
SwitchToContextId(int context_id)278 bool 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 
ReleaseContextId(int context_id)290 void 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 
CheckGLError(const std::string & op)302 bool 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 
CheckEGLError(const std::string & op)313 bool 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 
CheckEGLMakeCurrentError()326 bool 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 
GetCurrentProgram()351 GLuint GLEnv::GetCurrentProgram() {
352   GLint result;
353   glGetIntegerv(GL_CURRENT_PROGRAM, &result);
354   ALOG_ASSERT(result >= 0);
355   return static_cast<GLuint>(result);
356 }
357 
GetCurrentDisplay()358 EGLDisplay GLEnv::GetCurrentDisplay() {
359   return eglGetCurrentDisplay();
360 }
361 
NumberOfComponents(GLenum type)362 int 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 
AttachShader(int key,ShaderProgram * shader)390 void GLEnv::AttachShader(int key, ShaderProgram* shader) {
391   ShaderProgram* existingShader = ShaderWithKey(key);
392   if (existingShader)
393     delete existingShader;
394   attached_shaders_[key] = shader;
395 }
396 
AttachVertexFrame(int key,VertexFrame * frame)397 void GLEnv::AttachVertexFrame(int key, VertexFrame* frame) {
398   VertexFrame* existingFrame = VertexFrameWithKey(key);
399   if (existingFrame)
400     delete existingFrame;
401   attached_vframes_[key] = frame;
402 }
403 
ShaderWithKey(int key)404 ShaderProgram* GLEnv::ShaderWithKey(int key) {
405   return FindPtrOrNull(attached_shaders_, key);
406 }
407 
VertexFrameWithKey(int key)408 VertexFrame* GLEnv::VertexFrameWithKey(int key) {
409   return FindPtrOrNull(attached_vframes_, key);
410 }
411 
412 } // namespace filterfw
413 } // namespace android
414