blob: 73768feddcab520fd74c7aa942014c3719681cfc [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
163 surfaceTexture_ = new GLConsumer(0);
Mathias Agopian52800612013-02-14 17:11:20 -0800164 window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >(
Marius Renn65953da2012-03-27 10:44:45 -0700165 surfaceTexture_->getBufferQueue()));
166
167 surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL);
168 if (CheckEGLError("eglCreateWindowSurface")) return false;
169
170 // Create context
171 EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
172 contexts_[0] = eglCreateContext(display(),
173 config,
174 EGL_NO_CONTEXT,
175 context_attribs);
176 if (CheckEGLError("eglCreateContext")) return false;
177
178 created_context_ = created_surface_ = true;
179
180 return true;
181}
182
183bool GLEnv::IsActive() const {
184 ALOGV("IsActive()");
185 return context() == eglGetCurrentContext()
186 && display() == eglGetCurrentDisplay()
187 && surface() == eglGetCurrentSurface(EGL_DRAW);
188}
189
190bool GLEnv::IsContextActive() const {
191 return context() == eglGetCurrentContext();
192}
193
194bool GLEnv::IsAnyContextActive() {
195 return eglGetCurrentContext() != EGL_NO_CONTEXT;
196}
197
198int GLEnv::AddWindowSurface(const EGLSurface& surface, WindowHandle* window_handle) {
199 const int id = ++max_surface_id_;
200 surfaces_[id] = SurfaceWindowPair(surface, window_handle);
201 return id;
202}
203
204int GLEnv::AddSurface(const EGLSurface& surface) {
205 return AddWindowSurface(surface, NULL);
206}
207
208bool GLEnv::SwitchToSurfaceId(int surface_id) {
209 ALOGV("SwitchToSurfaceId");
210 if (surface_id_ != surface_id) {
211 const SurfaceWindowPair* surface = FindOrNull(surfaces_, surface_id);
212 if (surface) {
213 bool wasActive = IsActive();
214 surface_id_ = surface_id;
215 return wasActive ? Activate() : true;
216 }
217 return false;
218 }
219 return true;
220}
221
222bool GLEnv::ReleaseSurfaceId(int surface_id) {
223 if (surface_id > 0) {
224 const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_, surface_id);
225 if (surface_window_pair) {
226 if (surface_id_ == surface_id)
227 SwitchToSurfaceId(0);
228 eglDestroySurface(display(), surface_window_pair->first);
229 if (surface_window_pair->second) {
230 surface_window_pair->second->Destroy();
231 delete surface_window_pair->second;
232 }
233 surfaces_.erase(surface_id);
234 return true;
235 }
236 }
237 return false;
238}
239
240bool GLEnv::SetSurfaceTimestamp(int64_t timestamp) {
241 if (surface_id_ > 0) {
242 const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_,
243 surface_id_);
244 if (surface_window_pair) {
245 ANativeWindow *window = static_cast<ANativeWindow*>(
246 surface_window_pair->second->InternalHandle());
247 native_window_set_buffers_timestamp(window, timestamp);
248 return true;
249 }
250 }
251 return false;
252}
253
254int GLEnv::FindSurfaceIdForWindow(const WindowHandle* window_handle) {
255 for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin();
256 it != surfaces_.end();
257 ++it) {
258 const WindowHandle* my_handle = it->second.second;
259 if (my_handle && my_handle->Equals(window_handle)) {
260 return it->first;
261 }
262 }
263 return -1;
264}
265
266
267int GLEnv::AddContext(const EGLContext& context) {
268 const int id = contexts_.size();
269 contexts_[id] = context;
270 return id;
271}
272
273bool GLEnv::SwitchToContextId(int context_id) {
274 const EGLContext* context = FindOrNull(contexts_, context_id);
275 if (context) {
276 if (context_id_ != context_id) {
277 context_id_ = context_id;
278 return Activate();
279 }
280 return true;
281 }
282 return false;
283}
284
285void GLEnv::ReleaseContextId(int context_id) {
286 if (context_id > 0) {
287 const EGLContext* context = FindOrNull(contexts_, context_id);
288 if (context) {
289 contexts_.erase(context_id);
290 if (context_id_ == context_id && IsActive())
291 SwitchToContextId(0);
292 eglDestroyContext(display(), *context);
293 }
294 }
295}
296
297bool GLEnv::CheckGLError(const std::string& op) {
298 bool err = false;
299 for (GLint error = glGetError(); error; error = glGetError()) {
300 ALOGE("GL Error: Operation '%s' caused GL error (0x%x)\n",
301 op.c_str(),
302 error);
303 err = true;
304 }
305 return err;
306}
307
308bool GLEnv::CheckEGLError(const std::string& op) {
309 bool err = false;
310 for (EGLint error = eglGetError();
311 error != EGL_SUCCESS;
312 error = eglGetError()) {
313 ALOGE("EGL Error: Operation '%s' caused EGL error (0x%x)\n",
314 op.c_str(),
315 error);
316 err = true;
317 }
318 return err;
319}
320
321bool GLEnv::CheckEGLMakeCurrentError() {
322 bool err = false;
323 for (EGLint error = eglGetError();
324 error != EGL_SUCCESS;
325 error = eglGetError()) {
326 switch (error) {
327 case EGL_BAD_DISPLAY:
328 ALOGE("EGL Error: Attempting to activate context with bad display!");
329 break;
330 case EGL_BAD_SURFACE:
331 ALOGE("EGL Error: Attempting to activate context with bad surface!");
332 break;
333 case EGL_BAD_ACCESS:
334 ALOGE("EGL Error: Attempting to activate context, which is "
335 "already active in another thread!");
336 break;
337 default:
338 ALOGE("EGL Error: Making EGL rendering context current caused "
339 "error: 0x%x\n", error);
340 }
341 err = true;
342 }
343 return err;
344}
345
346GLuint GLEnv::GetCurrentProgram() {
347 GLint result;
348 glGetIntegerv(GL_CURRENT_PROGRAM, &result);
349 ALOG_ASSERT(result >= 0);
350 return static_cast<GLuint>(result);
351}
352
353EGLDisplay GLEnv::GetCurrentDisplay() {
354 return eglGetCurrentDisplay();
355}
356
357int GLEnv::NumberOfComponents(GLenum type) {
358 switch (type) {
359 case GL_BOOL:
360 case GL_FLOAT:
361 case GL_INT:
362 return 1;
363 case GL_BOOL_VEC2:
364 case GL_FLOAT_VEC2:
365 case GL_INT_VEC2:
366 return 2;
367 case GL_INT_VEC3:
368 case GL_FLOAT_VEC3:
369 case GL_BOOL_VEC3:
370 return 3;
371 case GL_BOOL_VEC4:
372 case GL_FLOAT_VEC4:
373 case GL_INT_VEC4:
374 case GL_FLOAT_MAT2:
375 return 4;
376 case GL_FLOAT_MAT3:
377 return 9;
378 case GL_FLOAT_MAT4:
379 return 16;
380 default:
381 return 0;
382 }
383}
384
385void GLEnv::AttachShader(int key, ShaderProgram* shader) {
386 ShaderProgram* existingShader = ShaderWithKey(key);
387 if (existingShader)
388 delete existingShader;
389 attached_shaders_[key] = shader;
390}
391
392void GLEnv::AttachVertexFrame(int key, VertexFrame* frame) {
393 VertexFrame* existingFrame = VertexFrameWithKey(key);
394 if (existingFrame)
395 delete existingFrame;
396 attached_vframes_[key] = frame;
397}
398
399ShaderProgram* GLEnv::ShaderWithKey(int key) {
400 return FindPtrOrNull(attached_shaders_, key);
401}
402
403VertexFrame* GLEnv::VertexFrameWithKey(int key) {
404 return FindPtrOrNull(attached_vframes_, key);
405}
406
407} // namespace filterfw
408} // namespace android