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
17 #include "FrameBuffer.h"
18 #include "NativeSubWindow.h"
19 #include "FBConfig.h"
20 #include "EGLDispatch.h"
21 #include "GLDispatch.h"
22 #include "GL2Dispatch.h"
23 #include "ThreadInfo.h"
24 #include "TimeUtils.h"
25 #include <stdio.h>
26
27 FrameBuffer *FrameBuffer::s_theFrameBuffer = NULL;
28 HandleType FrameBuffer::s_nextHandle = 0;
29
30 #ifdef WITH_GLES2
getGLES2ExtensionString(EGLDisplay p_dpy)31 static char* getGLES2ExtensionString(EGLDisplay p_dpy)
32 {
33 EGLConfig config;
34 EGLSurface surface;
35
36 GLint configAttribs[] = {
37 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
38 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
39 EGL_NONE
40 };
41
42 int n;
43 if (!s_egl.eglChooseConfig(p_dpy, configAttribs,
44 &config, 1, &n)) {
45 return NULL;
46 }
47
48 EGLint pbufAttribs[] = {
49 EGL_WIDTH, 1,
50 EGL_HEIGHT, 1,
51 EGL_NONE
52 };
53
54 surface = s_egl.eglCreatePbufferSurface(p_dpy, config, pbufAttribs);
55 if (surface == EGL_NO_SURFACE) {
56 return NULL;
57 }
58
59 GLint gl2ContextAttribs[] = {
60 EGL_CONTEXT_CLIENT_VERSION, 2,
61 EGL_NONE
62 };
63
64 EGLContext ctx = s_egl.eglCreateContext(p_dpy, config,
65 EGL_NO_CONTEXT,
66 gl2ContextAttribs);
67 if (ctx == EGL_NO_CONTEXT) {
68 s_egl.eglDestroySurface(p_dpy, surface);
69 return NULL;
70 }
71
72 if (!s_egl.eglMakeCurrent(p_dpy, surface, surface, ctx)) {
73 s_egl.eglDestroySurface(p_dpy, surface);
74 s_egl.eglDestroyContext(p_dpy, ctx);
75 return NULL;
76 }
77
78 // the string pointer may become invalid when the context is destroyed
79 const char* s = (const char*)s_gl2.glGetString(GL_EXTENSIONS);
80 char* extString = strdup(s ? s : "");
81
82 s_egl.eglMakeCurrent(p_dpy, NULL, NULL, NULL);
83 s_egl.eglDestroyContext(p_dpy, ctx);
84 s_egl.eglDestroySurface(p_dpy, surface);
85
86 return extString;
87 }
88 #endif
89
finalize()90 void FrameBuffer::finalize(){
91 if(s_theFrameBuffer){
92 s_theFrameBuffer->removeSubWindow();
93 s_theFrameBuffer->m_colorbuffers.clear();
94 s_theFrameBuffer->m_windows.clear();
95 s_theFrameBuffer->m_contexts.clear();
96 s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL);
97 s_egl.eglDestroyContext(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_eglContext);
98 s_egl.eglDestroyContext(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_pbufContext);
99 s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_pbufSurface);
100 s_theFrameBuffer = NULL;
101 }
102 }
103
initialize(int width,int height)104 bool FrameBuffer::initialize(int width, int height)
105 {
106 if (s_theFrameBuffer != NULL) {
107 return true;
108 }
109
110 //
111 // allocate space for the FrameBuffer object
112 //
113 FrameBuffer *fb = new FrameBuffer(width, height);
114 if (!fb) {
115 ERR("Failed to create fb\n");
116 return false;
117 }
118
119 #ifdef WITH_GLES2
120 //
121 // Try to load GLES2 Plugin, not mandatory
122 //
123 if (getenv("ANDROID_NO_GLES2")) {
124 fb->m_caps.hasGL2 = false;
125 }
126 else {
127 fb->m_caps.hasGL2 = s_gl2_enabled;
128 }
129 #else
130 fb->m_caps.hasGL2 = false;
131 #endif
132
133 //
134 // Initialize backend EGL display
135 //
136 fb->m_eglDisplay = s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
137 if (fb->m_eglDisplay == EGL_NO_DISPLAY) {
138 ERR("Failed to Initialize backend EGL display\n");
139 delete fb;
140 return false;
141 }
142
143 if (!s_egl.eglInitialize(fb->m_eglDisplay, &fb->m_caps.eglMajor, &fb->m_caps.eglMinor)) {
144 ERR("Failed to eglInitialize\n");
145 delete fb;
146 return false;
147 }
148
149 DBG("egl: %d %d\n", fb->m_caps.eglMajor, fb->m_caps.eglMinor);
150 s_egl.eglBindAPI(EGL_OPENGL_ES_API);
151
152 //
153 // if GLES2 plugin has loaded - try to make GLES2 context and
154 // get GLES2 extension string
155 //
156 char* gl2Extensions = NULL;
157 #ifdef WITH_GLES2
158 if (fb->m_caps.hasGL2) {
159 gl2Extensions = getGLES2ExtensionString(fb->m_eglDisplay);
160 if (!gl2Extensions) {
161 // Could not create GLES2 context - drop GL2 capability
162 fb->m_caps.hasGL2 = false;
163 }
164 }
165 #endif
166
167 //
168 // Create EGL context for framebuffer post rendering.
169 //
170 #if 0
171 GLint configAttribs[] = {
172 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
173 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
174 EGL_NONE
175 };
176 #else
177 GLint configAttribs[] = {
178 EGL_RED_SIZE, 1,
179 EGL_GREEN_SIZE, 1,
180 EGL_BLUE_SIZE, 1,
181 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
182 EGL_NONE
183 };
184 #endif
185
186 int n;
187 if (!s_egl.eglChooseConfig(fb->m_eglDisplay, configAttribs,
188 &fb->m_eglConfig, 1, &n)) {
189 ERR("Failed on eglChooseConfig\n");
190 free(gl2Extensions);
191 delete fb;
192 return false;
193 }
194
195 GLint glContextAttribs[] = {
196 EGL_CONTEXT_CLIENT_VERSION, 1,
197 EGL_NONE
198 };
199
200 fb->m_eglContext = s_egl.eglCreateContext(fb->m_eglDisplay, fb->m_eglConfig,
201 EGL_NO_CONTEXT,
202 glContextAttribs);
203 if (fb->m_eglContext == EGL_NO_CONTEXT) {
204 printf("Failed to create Context 0x%x\n", s_egl.eglGetError());
205 free(gl2Extensions);
206 delete fb;
207 return false;
208 }
209
210 //
211 // Create another context which shares with the eglContext to be used
212 // when we bind the pbuffer. That prevent switching drawable binding
213 // back and forth on framebuffer context.
214 // The main purpose of it is to solve a "blanking" behaviour we see on
215 // on Mac platform when switching binded drawable for a context however
216 // it is more efficient on other platforms as well.
217 //
218 fb->m_pbufContext = s_egl.eglCreateContext(fb->m_eglDisplay, fb->m_eglConfig,
219 fb->m_eglContext,
220 glContextAttribs);
221 if (fb->m_pbufContext == EGL_NO_CONTEXT) {
222 printf("Failed to create Pbuffer Context 0x%x\n", s_egl.eglGetError());
223 free(gl2Extensions);
224 delete fb;
225 return false;
226 }
227
228 //
229 // create a 1x1 pbuffer surface which will be used for binding
230 // the FB context.
231 // The FB output will go to a subwindow, if one exist.
232 //
233 EGLint pbufAttribs[] = {
234 EGL_WIDTH, 1,
235 EGL_HEIGHT, 1,
236 EGL_NONE
237 };
238
239 fb->m_pbufSurface = s_egl.eglCreatePbufferSurface(fb->m_eglDisplay,
240 fb->m_eglConfig,
241 pbufAttribs);
242 if (fb->m_pbufSurface == EGL_NO_SURFACE) {
243 printf("Failed to create pbuf surface for FB 0x%x\n", s_egl.eglGetError());
244 free(gl2Extensions);
245 delete fb;
246 return false;
247 }
248
249 // Make the context current
250 if (!fb->bind_locked()) {
251 ERR("Failed to make current\n");
252 free(gl2Extensions);
253 delete fb;
254 return false;
255 }
256
257 //
258 // Initilize framebuffer capabilities
259 //
260 const char *glExtensions = (const char *)s_gl.glGetString(GL_EXTENSIONS);
261 bool has_gl_oes_image = false;
262 if (glExtensions) {
263 has_gl_oes_image = strstr(glExtensions, "GL_OES_EGL_image") != NULL;
264 }
265
266 if (fb->m_caps.hasGL2 && has_gl_oes_image) {
267 has_gl_oes_image &= strstr(gl2Extensions, "GL_OES_EGL_image") != NULL;
268 }
269 free(gl2Extensions);
270 gl2Extensions = NULL;
271
272 const char *eglExtensions = s_egl.eglQueryString(fb->m_eglDisplay,
273 EGL_EXTENSIONS);
274
275 if (eglExtensions && has_gl_oes_image) {
276 fb->m_caps.has_eglimage_texture_2d =
277 strstr(eglExtensions, "EGL_KHR_gl_texture_2D_image") != NULL;
278 fb->m_caps.has_eglimage_renderbuffer =
279 strstr(eglExtensions, "EGL_KHR_gl_renderbuffer_image") != NULL;
280 }
281 else {
282 fb->m_caps.has_eglimage_texture_2d = false;
283 fb->m_caps.has_eglimage_renderbuffer = false;
284 }
285
286 //
287 // Fail initialization if not all of the following extensions
288 // exist:
289 // EGL_KHR_gl_texture_2d_image
290 // GL_OES_EGL_IMAGE (by both GLES implementations [1 and 2])
291 //
292 if (!fb->m_caps.has_eglimage_texture_2d) {
293 ERR("Failed: Missing egl_image related extension(s)\n");
294 delete fb;
295 return false;
296 }
297
298 //
299 // Initialize set of configs
300 //
301 InitConfigStatus configStatus = FBConfig::initConfigList(fb);
302 if (configStatus == INIT_CONFIG_FAILED) {
303 ERR("Failed: Initialize set of configs\n");
304 delete fb;
305 return false;
306 }
307
308 //
309 // Check that we have config for each GLES and GLES2
310 //
311 int nConfigs = FBConfig::getNumConfigs();
312 int nGLConfigs = 0;
313 int nGL2Configs = 0;
314 for (int i=0; i<nConfigs; i++) {
315 GLint rtype = FBConfig::get(i)->getRenderableType();
316 if (0 != (rtype & EGL_OPENGL_ES_BIT)) {
317 nGLConfigs++;
318 }
319 if (0 != (rtype & EGL_OPENGL_ES2_BIT)) {
320 nGL2Configs++;
321 }
322 }
323
324 //
325 // Fail initialization if no GLES configs exist
326 //
327 if (nGLConfigs == 0) {
328 delete fb;
329 return false;
330 }
331
332 //
333 // If no GLES2 configs exist - not GLES2 capability
334 //
335 if (nGL2Configs == 0) {
336 fb->m_caps.hasGL2 = false;
337 }
338
339 //
340 // Initialize some GL state in the pbuffer context
341 //
342 fb->initGLState();
343
344 //
345 // Cache the GL strings so we don't have to think about threading or
346 // current-context when asked for them.
347 //
348 fb->m_glVendor = (const char*)s_gl.glGetString(GL_VENDOR);
349 fb->m_glRenderer = (const char*)s_gl.glGetString(GL_RENDERER);
350 fb->m_glVersion = (const char*)s_gl.glGetString(GL_VERSION);
351
352 // release the FB context
353 fb->unbind_locked();
354
355 //
356 // Keep the singleton framebuffer pointer
357 //
358 s_theFrameBuffer = fb;
359 return true;
360 }
361
FrameBuffer(int p_width,int p_height)362 FrameBuffer::FrameBuffer(int p_width, int p_height) :
363 m_width(p_width),
364 m_height(p_height),
365 m_eglDisplay(EGL_NO_DISPLAY),
366 m_eglSurface(EGL_NO_SURFACE),
367 m_eglContext(EGL_NO_CONTEXT),
368 m_pbufContext(EGL_NO_CONTEXT),
369 m_prevContext(EGL_NO_CONTEXT),
370 m_prevReadSurf(EGL_NO_SURFACE),
371 m_prevDrawSurf(EGL_NO_SURFACE),
372 m_subWin((EGLNativeWindowType)0),
373 m_subWinDisplay(NULL),
374 m_lastPostedColorBuffer(0),
375 m_zRot(0.0f),
376 m_eglContextInitialized(false),
377 m_statsNumFrames(0),
378 m_statsStartTime(0LL),
379 m_onPost(NULL),
380 m_onPostContext(NULL),
381 m_fbImage(NULL),
382 m_glVendor(NULL),
383 m_glRenderer(NULL),
384 m_glVersion(NULL)
385 {
386 m_fpsStats = getenv("SHOW_FPS_STATS") != NULL;
387 }
388
~FrameBuffer()389 FrameBuffer::~FrameBuffer()
390 {
391 free(m_fbImage);
392 }
393
setPostCallback(OnPostFn onPost,void * onPostContext)394 void FrameBuffer::setPostCallback(OnPostFn onPost, void* onPostContext)
395 {
396 emugl::Mutex::AutoLock mutex(m_lock);
397 m_onPost = onPost;
398 m_onPostContext = onPostContext;
399 if (m_onPost && !m_fbImage) {
400 m_fbImage = (unsigned char*)malloc(4 * m_width * m_height);
401 if (!m_fbImage) {
402 ERR("out of memory, cancelling OnPost callback");
403 m_onPost = NULL;
404 m_onPostContext = NULL;
405 return;
406 }
407 }
408 }
409
setupSubWindow(FBNativeWindowType p_window,int p_x,int p_y,int p_width,int p_height,float zRot)410 bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window,
411 int p_x, int p_y,
412 int p_width, int p_height, float zRot)
413 {
414 bool success = false;
415
416 if (s_theFrameBuffer) {
417 s_theFrameBuffer->m_lock.lock();
418 FrameBuffer *fb = s_theFrameBuffer;
419 if (!fb->m_subWin) {
420
421 // create native subwindow for FB display output
422 fb->m_subWin = createSubWindow(p_window,
423 &fb->m_subWinDisplay,
424 p_x,p_y,p_width,p_height);
425 if (fb->m_subWin) {
426 fb->m_nativeWindow = p_window;
427
428 // create EGLSurface from the generated subwindow
429 fb->m_eglSurface = s_egl.eglCreateWindowSurface(fb->m_eglDisplay,
430 fb->m_eglConfig,
431 fb->m_subWin,
432 NULL);
433
434 if (fb->m_eglSurface == EGL_NO_SURFACE) {
435 ERR("Failed to create surface\n");
436 destroySubWindow(fb->m_subWinDisplay, fb->m_subWin);
437 fb->m_subWin = (EGLNativeWindowType)0;
438 }
439 else if (fb->bindSubwin_locked()) {
440 // Subwin creation was successfull,
441 // update viewport and z rotation and draw
442 // the last posted color buffer.
443 s_gl.glViewport(0, 0, p_width, p_height);
444 fb->m_zRot = zRot;
445 fb->post( fb->m_lastPostedColorBuffer, false );
446 fb->unbind_locked();
447 success = true;
448 }
449 }
450 }
451 s_theFrameBuffer->m_lock.unlock();
452 }
453
454 return success;
455 }
456
removeSubWindow()457 bool FrameBuffer::removeSubWindow()
458 {
459 bool removed = false;
460 if (s_theFrameBuffer) {
461 s_theFrameBuffer->m_lock.lock();
462 if (s_theFrameBuffer->m_subWin) {
463 s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL);
464 s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,
465 s_theFrameBuffer->m_eglSurface);
466 destroySubWindow(s_theFrameBuffer->m_subWinDisplay,
467 s_theFrameBuffer->m_subWin);
468
469 s_theFrameBuffer->m_eglSurface = EGL_NO_SURFACE;
470 s_theFrameBuffer->m_subWin = (EGLNativeWindowType)0;
471 removed = true;
472 }
473 s_theFrameBuffer->m_lock.unlock();
474 }
475 return removed;
476 }
477
genHandle()478 HandleType FrameBuffer::genHandle()
479 {
480 HandleType id;
481 do {
482 id = ++s_nextHandle;
483 } while( id == 0 ||
484 m_contexts.find(id) != m_contexts.end() ||
485 m_windows.find(id) != m_windows.end() );
486
487 return id;
488 }
489
createColorBuffer(int p_width,int p_height,GLenum p_internalFormat)490 HandleType FrameBuffer::createColorBuffer(int p_width, int p_height,
491 GLenum p_internalFormat)
492 {
493 emugl::Mutex::AutoLock mutex(m_lock);
494 HandleType ret = 0;
495
496 ColorBufferPtr cb( ColorBuffer::create(p_width, p_height, p_internalFormat) );
497 if (cb.Ptr() != NULL) {
498 ret = genHandle();
499 m_colorbuffers[ret].cb = cb;
500 m_colorbuffers[ret].refcount = 1;
501 }
502 return ret;
503 }
504
createRenderContext(int p_config,HandleType p_share,bool p_isGL2)505 HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share,
506 bool p_isGL2)
507 {
508 emugl::Mutex::AutoLock mutex(m_lock);
509 HandleType ret = 0;
510
511 RenderContextPtr share(NULL);
512 if (p_share != 0) {
513 RenderContextMap::iterator s( m_contexts.find(p_share) );
514 if (s == m_contexts.end()) {
515 return 0;
516 }
517 share = (*s).second;
518 }
519
520 RenderContextPtr rctx( RenderContext::create(p_config, share, p_isGL2) );
521 if (rctx.Ptr() != NULL) {
522 ret = genHandle();
523 m_contexts[ret] = rctx;
524 }
525 return ret;
526 }
527
createWindowSurface(int p_config,int p_width,int p_height)528 HandleType FrameBuffer::createWindowSurface(int p_config, int p_width, int p_height)
529 {
530 emugl::Mutex::AutoLock mutex(m_lock);
531
532 HandleType ret = 0;
533 WindowSurfacePtr win( WindowSurface::create(p_config, p_width, p_height) );
534 if (win.Ptr() != NULL) {
535 ret = genHandle();
536 m_windows[ret] = win;
537 }
538
539 return ret;
540 }
541
DestroyRenderContext(HandleType p_context)542 void FrameBuffer::DestroyRenderContext(HandleType p_context)
543 {
544 emugl::Mutex::AutoLock mutex(m_lock);
545 m_contexts.erase(p_context);
546 }
547
DestroyWindowSurface(HandleType p_surface)548 void FrameBuffer::DestroyWindowSurface(HandleType p_surface)
549 {
550 emugl::Mutex::AutoLock mutex(m_lock);
551 m_windows.erase(p_surface);
552 }
553
openColorBuffer(HandleType p_colorbuffer)554 int FrameBuffer::openColorBuffer(HandleType p_colorbuffer)
555 {
556 emugl::Mutex::AutoLock mutex(m_lock);
557 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
558 if (c == m_colorbuffers.end()) {
559 // bad colorbuffer handle
560 ERR("FB: openColorBuffer cb handle %#x not found\n", p_colorbuffer);
561 return -1;
562 }
563 (*c).second.refcount++;
564 return 0;
565 }
566
closeColorBuffer(HandleType p_colorbuffer)567 void FrameBuffer::closeColorBuffer(HandleType p_colorbuffer)
568 {
569 emugl::Mutex::AutoLock mutex(m_lock);
570 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
571 if (c == m_colorbuffers.end()) {
572 ERR("FB: closeColorBuffer cb handle %#x not found\n", p_colorbuffer);
573 // bad colorbuffer handle
574 return;
575 }
576 if (--(*c).second.refcount == 0) {
577 m_colorbuffers.erase(c);
578 }
579 }
580
flushWindowSurfaceColorBuffer(HandleType p_surface)581 bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface)
582 {
583 emugl::Mutex::AutoLock mutex(m_lock);
584
585 WindowSurfaceMap::iterator w( m_windows.find(p_surface) );
586 if (w == m_windows.end()) {
587 ERR("FB::flushWindowSurfaceColorBuffer: window handle %#x not found\n", p_surface);
588 // bad surface handle
589 return false;
590 }
591
592 return (*w).second->flushColorBuffer();
593 }
594
setWindowSurfaceColorBuffer(HandleType p_surface,HandleType p_colorbuffer)595 bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface,
596 HandleType p_colorbuffer)
597 {
598 emugl::Mutex::AutoLock mutex(m_lock);
599
600 WindowSurfaceMap::iterator w( m_windows.find(p_surface) );
601 if (w == m_windows.end()) {
602 // bad surface handle
603 ERR("%s: bad window surface handle %#x\n", __FUNCTION__, p_surface);
604 return false;
605 }
606
607 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
608 if (c == m_colorbuffers.end()) {
609 ERR("%s: bad color buffer handle %#x\n", __FUNCTION__, p_colorbuffer);
610 // bad colorbuffer handle
611 return false;
612 }
613
614 (*w).second->setColorBuffer( (*c).second.cb );
615
616 return true;
617 }
618
updateColorBuffer(HandleType p_colorbuffer,int x,int y,int width,int height,GLenum format,GLenum type,void * pixels)619 bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer,
620 int x, int y, int width, int height,
621 GLenum format, GLenum type, void *pixels)
622 {
623 emugl::Mutex::AutoLock mutex(m_lock);
624
625 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
626 if (c == m_colorbuffers.end()) {
627 // bad colorbuffer handle
628 return false;
629 }
630
631 (*c).second.cb->subUpdate(x, y, width, height, format, type, pixels);
632
633 return true;
634 }
635
bindColorBufferToTexture(HandleType p_colorbuffer)636 bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer)
637 {
638 emugl::Mutex::AutoLock mutex(m_lock);
639
640 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
641 if (c == m_colorbuffers.end()) {
642 // bad colorbuffer handle
643 return false;
644 }
645
646 return (*c).second.cb->bindToTexture();
647 }
648
bindColorBufferToRenderbuffer(HandleType p_colorbuffer)649 bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer)
650 {
651 emugl::Mutex::AutoLock mutex(m_lock);
652
653 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
654 if (c == m_colorbuffers.end()) {
655 // bad colorbuffer handle
656 return false;
657 }
658
659 return (*c).second.cb->bindToRenderbuffer();
660 }
661
bindContext(HandleType p_context,HandleType p_drawSurface,HandleType p_readSurface)662 bool FrameBuffer::bindContext(HandleType p_context,
663 HandleType p_drawSurface,
664 HandleType p_readSurface)
665 {
666 emugl::Mutex::AutoLock mutex(m_lock);
667
668 WindowSurfacePtr draw(NULL), read(NULL);
669 RenderContextPtr ctx(NULL);
670
671 //
672 // if this is not an unbind operation - make sure all handles are good
673 //
674 if (p_context || p_drawSurface || p_readSurface) {
675 RenderContextMap::iterator r( m_contexts.find(p_context) );
676 if (r == m_contexts.end()) {
677 // bad context handle
678 return false;
679 }
680
681 ctx = (*r).second;
682 WindowSurfaceMap::iterator w( m_windows.find(p_drawSurface) );
683 if (w == m_windows.end()) {
684 // bad surface handle
685 return false;
686 }
687 draw = (*w).second;
688
689 if (p_readSurface != p_drawSurface) {
690 WindowSurfaceMap::iterator w( m_windows.find(p_readSurface) );
691 if (w == m_windows.end()) {
692 // bad surface handle
693 return false;
694 }
695 read = (*w).second;
696 }
697 else {
698 read = draw;
699 }
700 }
701
702 if (!s_egl.eglMakeCurrent(m_eglDisplay,
703 draw ? draw->getEGLSurface() : EGL_NO_SURFACE,
704 read ? read->getEGLSurface() : EGL_NO_SURFACE,
705 ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) {
706 ERR("eglMakeCurrent failed\n");
707 return false;
708 }
709
710 //
711 // Bind the surface(s) to the context
712 //
713 RenderThreadInfo *tinfo = RenderThreadInfo::get();
714 WindowSurfacePtr bindDraw, bindRead;
715 if (draw.Ptr() == NULL && read.Ptr() == NULL) {
716 // Unbind the current read and draw surfaces from the context
717 bindDraw = tinfo->currDrawSurf;
718 bindRead = tinfo->currReadSurf;
719 } else {
720 bindDraw = draw;
721 bindRead = read;
722 }
723
724 if (bindDraw.Ptr() != NULL && bindRead.Ptr() != NULL) {
725 if (bindDraw.Ptr() != bindRead.Ptr()) {
726 bindDraw->bind(ctx, SURFACE_BIND_DRAW);
727 bindRead->bind(ctx, SURFACE_BIND_READ);
728 }
729 else {
730 bindDraw->bind(ctx, SURFACE_BIND_READDRAW);
731 }
732 }
733
734 //
735 // update thread info with current bound context
736 //
737 tinfo->currContext = ctx;
738 tinfo->currDrawSurf = draw;
739 tinfo->currReadSurf = read;
740 if (ctx) {
741 if (ctx->isGL2()) tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData());
742 else tinfo->m_glDec.setContextData(&ctx->decoderContextData());
743 }
744 else {
745 tinfo->m_glDec.setContextData(NULL);
746 tinfo->m_gl2Dec.setContextData(NULL);
747 }
748 return true;
749 }
750
751 //
752 // The framebuffer lock should be held when calling this function !
753 //
bind_locked()754 bool FrameBuffer::bind_locked()
755 {
756 EGLContext prevContext = s_egl.eglGetCurrentContext();
757 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
758 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
759
760 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface,
761 m_pbufSurface, m_pbufContext)) {
762 ERR("eglMakeCurrent failed\n");
763 return false;
764 }
765
766 m_prevContext = prevContext;
767 m_prevReadSurf = prevReadSurf;
768 m_prevDrawSurf = prevDrawSurf;
769 return true;
770 }
771
bindSubwin_locked()772 bool FrameBuffer::bindSubwin_locked()
773 {
774 EGLContext prevContext = s_egl.eglGetCurrentContext();
775 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
776 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
777
778 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface,
779 m_eglSurface, m_eglContext)) {
780 ERR("eglMakeCurrent failed\n");
781 return false;
782 }
783
784 //
785 // initialize GL state in eglContext if not yet initilaized
786 //
787 if (!m_eglContextInitialized) {
788 initGLState();
789 m_eglContextInitialized = true;
790 }
791
792 m_prevContext = prevContext;
793 m_prevReadSurf = prevReadSurf;
794 m_prevDrawSurf = prevDrawSurf;
795 return true;
796 }
797
unbind_locked()798 bool FrameBuffer::unbind_locked()
799 {
800 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf,
801 m_prevReadSurf, m_prevContext)) {
802 return false;
803 }
804
805 m_prevContext = EGL_NO_CONTEXT;
806 m_prevReadSurf = EGL_NO_SURFACE;
807 m_prevDrawSurf = EGL_NO_SURFACE;
808 return true;
809 }
810
post(HandleType p_colorbuffer,bool needLock)811 bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock)
812 {
813 if (needLock) m_lock.lock();
814 bool ret = false;
815
816 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
817 if (c != m_colorbuffers.end()) {
818
819 m_lastPostedColorBuffer = p_colorbuffer;
820 if (!m_subWin) {
821 // no subwindow created for the FB output
822 // cannot post the colorbuffer
823 if (needLock) m_lock.unlock();
824 return ret;
825 }
826
827
828 // bind the subwindow eglSurface
829 if (!bindSubwin_locked()) {
830 ERR("FrameBuffer::post eglMakeCurrent failed\n");
831 if (needLock) m_lock.unlock();
832 return false;
833 }
834
835 //
836 // render the color buffer to the window
837 //
838 s_gl.glPushMatrix();
839 s_gl.glRotatef(m_zRot, 0.0f, 0.0f, 1.0f);
840 if (m_zRot != 0.0f) {
841 s_gl.glClear(GL_COLOR_BUFFER_BIT);
842 }
843 ret = (*c).second.cb->post();
844 s_gl.glPopMatrix();
845
846 if (ret) {
847 //
848 // output FPS statistics
849 //
850 if (m_fpsStats) {
851 long long currTime = GetCurrentTimeMS();
852 m_statsNumFrames++;
853 if (currTime - m_statsStartTime >= 1000) {
854 float dt = (float)(currTime - m_statsStartTime) / 1000.0f;
855 printf("FPS: %5.3f\n", (float)m_statsNumFrames / dt);
856 m_statsStartTime = currTime;
857 m_statsNumFrames = 0;
858 }
859 }
860
861 s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface);
862 }
863
864 // restore previous binding
865 unbind_locked();
866
867 //
868 // Send framebuffer (without FPS overlay) to callback
869 //
870 if (m_onPost) {
871 (*c).second.cb->readback(m_fbImage);
872 m_onPost(m_onPostContext, m_width, m_height, -1,
873 GL_RGBA, GL_UNSIGNED_BYTE, m_fbImage);
874 }
875
876 }
877
878 if (needLock) m_lock.unlock();
879 return ret;
880 }
881
repost()882 bool FrameBuffer::repost()
883 {
884 if (m_lastPostedColorBuffer) {
885 return post( m_lastPostedColorBuffer );
886 }
887 return false;
888 }
889
initGLState()890 void FrameBuffer::initGLState()
891 {
892 s_gl.glMatrixMode(GL_PROJECTION);
893 s_gl.glLoadIdentity();
894 s_gl.glOrthof(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
895 s_gl.glMatrixMode(GL_MODELVIEW);
896 s_gl.glLoadIdentity();
897 }
898