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