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 
34 namespace android {
35 namespace filterfw {
36 
GLEnv()37 GLEnv::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 
~GLEnv()47 GLEnv::~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 
IsInitialized() const82 bool GLEnv::IsInitialized() const {
83   return (contexts_.size() > 0 &&
84           surfaces_.size() > 0 &&
85           display_ != EGL_NO_DISPLAY);
86 }
87 
Deactivate()88 bool GLEnv::Deactivate() {
89   eglMakeCurrent(display(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
90   return !CheckEGLError("eglMakeCurrent");
91 }
92 
Activate()93 bool 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 
SwapBuffers()111 bool GLEnv::SwapBuffers() {
112   const bool result = eglSwapBuffers(display(), surface()) == EGL_TRUE;
113   return !CheckEGLError("eglSwapBuffers") && result;
114 }
115 
InitWithCurrentContext()116 bool 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 
InitWithNewContext()129 bool 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 
IsActive() const191 bool GLEnv::IsActive() const {
192   ALOGV("IsActive()");
193   return context() == eglGetCurrentContext()
194     &&   display() == eglGetCurrentDisplay()
195     &&   surface() == eglGetCurrentSurface(EGL_DRAW);
196 }
197 
IsContextActive() const198 bool GLEnv::IsContextActive() const {
199   return context() == eglGetCurrentContext();
200 }
201 
IsAnyContextActive()202 bool GLEnv::IsAnyContextActive() {
203   return eglGetCurrentContext() != EGL_NO_CONTEXT;
204 }
205 
AddWindowSurface(const EGLSurface & surface,WindowHandle * window_handle)206 int 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 
AddSurface(const EGLSurface & surface)212 int GLEnv::AddSurface(const EGLSurface& surface) {
213   return AddWindowSurface(surface, NULL);
214 }
215 
SwitchToSurfaceId(int surface_id)216 bool 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 
ReleaseSurfaceId(int surface_id)230 bool 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 
SetSurfaceTimestamp(int64_t timestamp)248 bool 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 
FindSurfaceIdForWindow(const WindowHandle * window_handle)262 int 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 
AddContext(const EGLContext & context)275 int GLEnv::AddContext(const EGLContext& context) {
276   const int id = contexts_.size();
277   contexts_[id] = context;
278   return id;
279 }
280 
SwitchToContextId(int context_id)281 bool 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 
ReleaseContextId(int context_id)293 void 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 
CheckGLError(const std::string & op)305 bool 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 
CheckEGLError(const std::string & op)316 bool 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 
CheckEGLMakeCurrentError()329 bool 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 
GetCurrentProgram()354 GLuint GLEnv::GetCurrentProgram() {
355   GLint result;
356   glGetIntegerv(GL_CURRENT_PROGRAM, &result);
357   ALOG_ASSERT(result >= 0);
358   return static_cast<GLuint>(result);
359 }
360 
GetCurrentDisplay()361 EGLDisplay GLEnv::GetCurrentDisplay() {
362   return eglGetCurrentDisplay();
363 }
364 
NumberOfComponents(GLenum type)365 int 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 
AttachShader(int key,ShaderProgram * shader)393 void GLEnv::AttachShader(int key, ShaderProgram* shader) {
394   ShaderProgram* existingShader = ShaderWithKey(key);
395   if (existingShader)
396     delete existingShader;
397   attached_shaders_[key] = shader;
398 }
399 
AttachVertexFrame(int key,VertexFrame * frame)400 void GLEnv::AttachVertexFrame(int key, VertexFrame* frame) {
401   VertexFrame* existingFrame = VertexFrameWithKey(key);
402   if (existingFrame)
403     delete existingFrame;
404   attached_vframes_[key] = frame;
405 }
406 
ShaderWithKey(int key)407 ShaderProgram* GLEnv::ShaderWithKey(int key) {
408   return FindPtrOrNull(attached_shaders_, key);
409 }
410 
VertexFrameWithKey(int key)411 VertexFrame* GLEnv::VertexFrameWithKey(int key) {
412   return FindPtrOrNull(attached_vframes_, key);
413 }
414 
415 } // namespace filterfw
416 } // namespace android
417