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