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