diff --git a/tools/emulator/opengl/host/include/libOpenglRender/render_api.h b/tools/emulator/opengl/host/include/libOpenglRender/render_api.h index 324ae1fbf..0ac931a81 100644 --- a/tools/emulator/opengl/host/include/libOpenglRender/render_api.h +++ b/tools/emulator/opengl/host/include/libOpenglRender/render_api.h @@ -24,18 +24,51 @@ extern "C" { // // initOpenGLRenderer - initialize the OpenGL renderer process. -// window is the native window to be used as the framebuffer. -// x,y,width,height are the dimensions of the rendering subwindow. // portNum is the tcp port number the renderer is listening to. +// width and height are the framebuffer dimensions that will be +// reported to the guest display driver. // -// returns true if renderer has been starter successfully; +// returns true if renderer has been started successfully; // // This function is *NOT* thread safe and should be called first // to initialize the renderer. // -bool initOpenGLRenderer(FBNativeWindowType window, - int x, int y, int width, int height, - int portNum); +bool initOpenGLRenderer(int width, int height, int portNum); + + +// +// createOpenGLSubwindow - +// Create a native subwindow which is a child of 'window' +// to be used for framebuffer display. +// Framebuffer will not get displayed if a subwindow is not +// created. +// x,y,width,height are the dimensions of the rendering subwindow. +// zRot is the rotation to apply on the framebuffer display image. +// +bool createOpenGLSubwindow(FBNativeWindowType window, + int x, int y, int width, int height, float zRot); + +// +// destroyOpenGLSubwindow - +// destroys the created native subwindow. Once destroyed, +// Framebuffer content will not be visible until a new +// subwindow will be created. +// +bool destroyOpenGLSubwindow(); + +// +// setOpenGLDisplatRotation - +// set the framebuffer display image rotation in units +// of degrees around the z axis +// +void setOpenGLDisplayRotation(float zRot); + +// +// repaintOpenGLDisplay - +// causes the OpenGL subwindow to get repainted with the +// latest framebuffer content. +// +void repaintOpenGLDisplay(); // // stopOpenGLRenderer - stops the OpenGL renderer process. diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.cpp b/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.cpp index a670136b0..516ae20f6 100644 --- a/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.cpp +++ b/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.cpp @@ -27,14 +27,13 @@ FrameBuffer *FrameBuffer::s_theFrameBuffer = NULL; HandleType FrameBuffer::s_nextHandle = 0; #ifdef WITH_GLES2 -static const char *getGLES2ExtensionString(EGLDisplay p_dpy, - EGLNativeWindowType p_window) +static const char *getGLES2ExtensionString(EGLDisplay p_dpy) { EGLConfig config; EGLSurface surface; GLint configAttribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; @@ -45,9 +44,13 @@ static const char *getGLES2ExtensionString(EGLDisplay p_dpy, return NULL; } - surface = s_egl.eglCreateWindowSurface(p_dpy, config, - p_window, - NULL); + EGLint pbufAttribs[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_NONE + }; + + surface = s_egl.eglCreatePbufferSurface(p_dpy, config, pbufAttribs); if (surface == EGL_NO_SURFACE) { return NULL; } @@ -86,24 +89,17 @@ static const char *getGLES2ExtensionString(EGLDisplay p_dpy, void FrameBuffer::finalize(){ if(s_theFrameBuffer){ + s_theFrameBuffer->removeSubWindow(); s_theFrameBuffer->m_colorbuffers.clear(); s_theFrameBuffer->m_windows.clear(); s_theFrameBuffer->m_contexts.clear(); - s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL); - s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_eglSurface); s_egl.eglDestroyContext(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_eglContext); - if (s_theFrameBuffer->m_subWin) { - destroySubWindow(s_theFrameBuffer->m_subWinDisplay, - s_theFrameBuffer->m_subWin); - } - delete s_theFrameBuffer; + s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_pbufSurface); s_theFrameBuffer = NULL; } } -bool FrameBuffer::initialize(FBNativeWindowType p_window, - int p_x, int p_y, - int p_width, int p_height) +bool FrameBuffer::initialize(int width, int height) { if (s_theFrameBuffer != NULL) { return true; @@ -130,7 +126,7 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window, // // allocate space for the FrameBuffer object // - FrameBuffer *fb = new FrameBuffer(p_x, p_y, p_width, p_height); + FrameBuffer *fb = new FrameBuffer(width, height); if (!fb) { ERR("Failed to create fb\n"); return false; @@ -169,10 +165,6 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window, DBG("egl: %d %d\n", fb->m_caps.eglMajor, fb->m_caps.eglMinor); s_egl.eglBindAPI(EGL_OPENGL_ES_API); - fb->m_nativeWindow = p_window; - - fb->m_subWin = createSubWindow(p_window,&fb->m_subWinDisplay,p_x,p_y,p_width,p_height); - // // if GLES2 plugin has loaded - try to make GLES2 context and // get GLES2 extension string @@ -180,7 +172,7 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window, const char *gl2Extensions = NULL; #ifdef WITH_GLES2 if (fb->m_caps.hasGL2) { - gl2Extensions = getGLES2ExtensionString(fb->m_eglDisplay, fb->m_subWin); + gl2Extensions = getGLES2ExtensionString(fb->m_eglDisplay); if (!gl2Extensions) { // Could not create GLES2 context - drop GL2 capability fb->m_caps.hasGL2 = false; @@ -189,8 +181,7 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window, #endif // - // Create EGL context and Surface attached to the native window, for - // framebuffer post rendering. + // Create EGL context for framebuffer post rendering. // #if 0 GLint configAttribs[] = { @@ -203,35 +194,25 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window, EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, EGL_NONE }; #endif - EGLConfig eglConfig; + int n; if (!s_egl.eglChooseConfig(fb->m_eglDisplay, configAttribs, - &eglConfig, 1, &n)) { + &fb->m_eglConfig, 1, &n)) { ERR("Failed on eglChooseConfig\n"); delete fb; return false; } - EGLNativeDisplayType dpy; - fb->m_eglSurface = s_egl.eglCreateWindowSurface(fb->m_eglDisplay, eglConfig, - fb->m_subWin, - NULL); - if (fb->m_eglSurface == EGL_NO_SURFACE) { - ERR("Failed to create surface\n"); - delete fb; - return false; - } - GLint glContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE }; - fb->m_eglContext = s_egl.eglCreateContext(fb->m_eglDisplay, eglConfig, + fb->m_eglContext = s_egl.eglCreateContext(fb->m_eglDisplay, fb->m_eglConfig, EGL_NO_CONTEXT, glContextAttribs); if (fb->m_eglContext == EGL_NO_CONTEXT) { @@ -240,6 +221,26 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window, return false; } + // + // create a 1x1 pbuffer surface which will be used for binding + // the FB context. + // The FB output will go to a subwindow, if one exist. + // + EGLint pbufAttribs[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_NONE + }; + + fb->m_pbufSurface = s_egl.eglCreatePbufferSurface(fb->m_eglDisplay, + fb->m_eglConfig, + pbufAttribs); + if (fb->m_pbufSurface == EGL_NO_SURFACE) { + printf("Failed to create pbuf surface for FB 0x%x\n", s_egl.eglGetError()); + delete fb; + return false; + } + // Make the context current if (!fb->bind_locked()) { ERR("Failed to make current\n"); @@ -341,9 +342,7 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window, return true; } -FrameBuffer::FrameBuffer(int p_x, int p_y, int p_width, int p_height) : - m_x(p_x), - m_y(p_y), +FrameBuffer::FrameBuffer(int p_width, int p_height) : m_width(p_width), m_height(p_height), m_eglDisplay(EGL_NO_DISPLAY), @@ -354,6 +353,8 @@ FrameBuffer::FrameBuffer(int p_x, int p_y, int p_width, int p_height) : m_prevDrawSurf(EGL_NO_SURFACE), m_subWin(NULL), m_subWinDisplay(NULL), + m_lastPostedColorBuffer(0), + m_zRot(0.0f), m_statsNumFrames(0), m_statsStartTime(0LL) { @@ -364,6 +365,74 @@ FrameBuffer::~FrameBuffer() { } +bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window, + int p_x, int p_y, + int p_width, int p_height, float zRot) +{ + bool success = false; + + if (s_theFrameBuffer) { + s_theFrameBuffer->m_lock.lock(); + FrameBuffer *fb = s_theFrameBuffer; + if (!fb->m_subWin) { + + // create native subwindow for FB display output + fb->m_subWin = createSubWindow(p_window, + &fb->m_subWinDisplay, + p_x,p_y,p_width,p_height); + if (fb->m_subWin) { + fb->m_nativeWindow = p_window; + + // create EGLSurface from the generated subwindow + fb->m_eglSurface = s_egl.eglCreateWindowSurface(fb->m_eglDisplay, + fb->m_eglConfig, + fb->m_subWin, + NULL); + + if (fb->m_eglSurface == EGL_NO_SURFACE) { + ERR("Failed to create surface\n"); + destroySubWindow(fb->m_subWinDisplay, fb->m_subWin); + fb->m_subWin = NULL; + } + else if (fb->bindSubwin_locked()) { + // Subwin creation was successfull, + // update viewport and z rotation and draw + // the last posted color buffer. + s_gl.glViewport(0, 0, p_width, p_height); + fb->m_zRot = zRot; + fb->post( fb->m_lastPostedColorBuffer, false ); + fb->unbind_locked(); + success = true; + } + } + } + s_theFrameBuffer->m_lock.unlock(); + } + + return success; +} + +bool FrameBuffer::removeSubWindow() +{ + bool removed = false; + if (s_theFrameBuffer) { + s_theFrameBuffer->m_lock.lock(); + if (s_theFrameBuffer->m_subWin) { + s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL); + s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay, + s_theFrameBuffer->m_eglSurface); + destroySubWindow(s_theFrameBuffer->m_subWinDisplay, + s_theFrameBuffer->m_subWin); + + s_theFrameBuffer->m_eglSurface = EGL_NO_SURFACE; + s_theFrameBuffer->m_subWin = NULL; + removed = true; + } + s_theFrameBuffer->m_lock.unlock(); + } + return removed; +} + HandleType FrameBuffer::genHandle() { HandleType id; @@ -620,6 +689,24 @@ bool FrameBuffer::bind_locked() EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); + if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface, + m_pbufSurface, m_eglContext)) { + ERR("eglMakeCurrent failed\n"); + return false; + } + + m_prevContext = prevContext; + m_prevReadSurf = prevReadSurf; + m_prevDrawSurf = prevDrawSurf; + return true; +} + +bool FrameBuffer::bindSubwin_locked() +{ + EGLContext prevContext = s_egl.eglGetCurrentContext(); + EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); + EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); + if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)) { ERR("eglMakeCurrent failed\n"); @@ -645,17 +732,41 @@ bool FrameBuffer::unbind_locked() return true; } -bool FrameBuffer::post(HandleType p_colorbuffer) +bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock) { - android::Mutex::Autolock mutex(m_lock); + if (needLock) m_lock.lock(); bool ret = false; ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); if (c != m_colorbuffers.end()) { - if (!bind_locked()) { + + m_lastPostedColorBuffer = p_colorbuffer; + if (!m_subWin) { + // no subwindow created for the FB output + // cannot post the colorbuffer + if (needLock) m_lock.unlock(); + return ret; + } + + + // bind the subwindow eglSurface + if (!bindSubwin_locked()) { + ERR("FrameBuffer::post eglMakeCurrent failed\n"); + if (needLock) m_lock.unlock(); return false; } + + // + // render the color buffer to the window + // + s_gl.glPushMatrix(); + s_gl.glRotatef(m_zRot, 0.0f, 0.0f, 1.0f); + if (m_zRot != 0.0f) { + s_gl.glClear(GL_COLOR_BUFFER_BIT); + } ret = (*c).second->post(); + s_gl.glPopMatrix(); + if (ret) { // @@ -674,8 +785,19 @@ bool FrameBuffer::post(HandleType p_colorbuffer) s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface); } + + // restore previous binding unbind_locked(); } + if (needLock) m_lock.unlock(); return ret; } + +bool FrameBuffer::repost() +{ + if (m_lastPostedColorBuffer) { + return post( m_lastPostedColorBuffer ); + } + return false; +} diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.h b/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.h index cfefceebe..2a3eb5c04 100644 --- a/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.h +++ b/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.h @@ -43,9 +43,11 @@ struct FrameBufferCaps class FrameBuffer { public: - static bool initialize(FBNativeWindowType p_window, - int x, int y, - int width, int height); + static bool initialize(int width, int height); + static bool setupSubWindow(FBNativeWindowType p_window, + int x, int y, + int width, int height, float zRot); + static bool removeSubWindow(); static void finalize(); static FrameBuffer *getFB() { return s_theFrameBuffer; } @@ -70,7 +72,8 @@ public: int x, int y, int width, int height, GLenum format, GLenum type, void *pixels); - bool post(HandleType p_colorbuffer); + bool post(HandleType p_colorbuffer, bool needLock = true); + bool repost(); EGLDisplay getDisplay() const { return m_eglDisplay; } EGLContext getContext() const { return m_eglContext; } @@ -78,10 +81,16 @@ public: bool bind_locked(); bool unbind_locked(); + void setDisplayRotation(float zRot) { + m_zRot = zRot; + repost(); + } + private: - FrameBuffer(int p_x, int p_y, int p_width, int p_height); + FrameBuffer(int p_width, int p_height); ~FrameBuffer(); HandleType genHandle(); + bool bindSubwin_locked(); private: static FrameBuffer *s_theFrameBuffer; @@ -100,12 +109,16 @@ private: EGLSurface m_eglSurface; EGLContext m_eglContext; + EGLSurface m_pbufSurface; EGLContext m_prevContext; EGLSurface m_prevReadSurf; EGLSurface m_prevDrawSurf; EGLNativeWindowType m_subWin; EGLNativeDisplayType m_subWinDisplay; + EGLConfig m_eglConfig; + HandleType m_lastPostedColorBuffer; + float m_zRot; int m_statsNumFrames; long long m_statsStartTime; diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp b/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp index fa04235d1..70d28769c 100644 --- a/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp +++ b/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp @@ -27,13 +27,19 @@ static int s_renderPort = 0; static IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags); -#ifdef __APPLE__ +// +// For now run the renderer as a thread inside the calling +// process instead as running it in a separate process for all +// platforms. +// at the future we want it to run as a seperate process except for +// Mac OS X since it is imposibble on this platform to make one process +// render to a window created by another process. +// +//#ifdef __APPLE__ #define RENDER_API_USE_THREAD -#endif +//#endif -bool initOpenGLRenderer(FBNativeWindowType window, - int x, int y, int width, int height, - int portNum) +bool initOpenGLRenderer(int width, int height, int portNum) { // @@ -50,7 +56,7 @@ bool initOpenGLRenderer(FBNativeWindowType window, // initialize the renderer and listen to connections // on a thread in the current process. // - bool inited = FrameBuffer::initialize(window, x, y, width, height); + bool inited = FrameBuffer::initialize(width, height); if (!inited) { return false; } @@ -169,6 +175,71 @@ bool stopOpenGLRenderer() return ret; } +bool createOpenGLSubwindow(FBNativeWindowType window, + int x, int y, int width, int height, float zRot) +{ + if (s_renderThread) { + return FrameBuffer::setupSubWindow(window,x,y,width,height, zRot); + } + else { + // + // XXX: should be implemented by sending the renderer process + // a request + ERR("%s not implemented for separate renderer process !!!\n", + __FUNCTION__); + } + return false; +} + +bool destroyOpenGLSubwindow() +{ + if (s_renderThread) { + return FrameBuffer::removeSubWindow(); + } + else { + // + // XXX: should be implemented by sending the renderer process + // a request + ERR("%s not implemented for separate renderer process !!!\n", + __FUNCTION__); + return false; + } +} + +void setOpenGLDisplayRotation(float zRot) +{ + if (s_renderThread) { + FrameBuffer *fb = FrameBuffer::getFB(); + if (fb) { + fb->setDisplayRotation(zRot); + } + } + else { + // + // XXX: should be implemented by sending the renderer process + // a request + ERR("%s not implemented for separate renderer process !!!\n", + __FUNCTION__); + } +} + +void repaintOpenGLDisplay() +{ + if (s_renderThread) { + FrameBuffer *fb = FrameBuffer::getFB(); + if (fb) { + fb->repost(); + } + } + else { + // + // XXX: should be implemented by sending the renderer process + // a request + ERR("%s not implemented for separate renderer process !!!\n", + __FUNCTION__); + } +} + IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags) { TcpStream *stream = new TcpStream(p_stream_buffer_size); diff --git a/tools/emulator/opengl/host/renderer/main.cpp b/tools/emulator/opengl/host/renderer/main.cpp index fb2045412..4549c5636 100644 --- a/tools/emulator/opengl/host/renderer/main.cpp +++ b/tools/emulator/opengl/host/renderer/main.cpp @@ -120,13 +120,19 @@ int main(int argc, char *argv[]) // // initialize Framebuffer // - bool inited = FrameBuffer::initialize(windowId, - winX, winY, winWidth, winHeight); + bool inited = FrameBuffer::initialize(winWidth, winHeight); if (!inited) { fprintf(stderr,"Failed to initialize Framebuffer\n"); return -1; } + inited = FrameBuffer::setupSubWindow(windowId, + winX, winY, winWidth, winHeight, 0.0); + if (!inited) { + fprintf(stderr,"Failed to create subwindow Framebuffer\n"); + return -1; + } + // // Create and run a render server listening to the given port number // diff --git a/tools/emulator/opengl/tests/emulator_test_renderer/main.cpp b/tools/emulator/opengl/tests/emulator_test_renderer/main.cpp index 7eb3d0424..525c5eb7e 100644 --- a/tools/emulator/opengl/tests/emulator_test_renderer/main.cpp +++ b/tools/emulator/opengl/tests/emulator_test_renderer/main.cpp @@ -80,13 +80,23 @@ int main(int argc, char *argv[]) // // initialize OpenGL renderer to render in our window // - bool inited = initOpenGLRenderer(windowId, 0, 0, - winWidth, winHeight, portNum); + bool inited = initOpenGLRenderer(winWidth, winHeight, portNum); if (!inited) { return -1; } printf("renderer process started\n"); + float zRot = 0.0f; + inited = createOpenGLSubwindow(windowId, 0, 0, + winWidth, winHeight, zRot); + if (!inited) { + printf("failed to create OpenGL subwindow\n"); + stopOpenGLRenderer(); + return -1; + } + int subwinWidth = winWidth; + int subwinHeight = winHeight; + injector = new EventInjector(consolePort); // Just wait until the window is closed @@ -103,7 +113,7 @@ int main(int argc, char *argv[]) injector->sendMouseDown(ev.button.x, ev.button.y); mouseDown = 1; } - break; + break; case SDL_MOUSEBUTTONUP: if (mouseDown) { injector->sendMouseUp(ev.button.x,ev.button.y); @@ -123,7 +133,41 @@ int main(int argc, char *argv[]) goto EXIT; } #endif - injector->sendKeyDown(convert_keysym(ev.key.keysym.sym)); + injector->sendKeyDown(convert_keysym(ev.key.keysym.sym)); + + if (ev.key.keysym.sym == SDLK_KP_MINUS) { + subwinWidth /= 2; + subwinHeight /= 2; + + bool stat = destroyOpenGLSubwindow(); + printf("destroy subwin returned %d\n", stat); + stat = createOpenGLSubwindow(windowId, + (winWidth - subwinWidth) / 2, + (winHeight - subwinHeight) / 2, + subwinWidth, subwinHeight, + zRot); + printf("create subwin returned %d\n", stat); + } + else if (ev.key.keysym.sym == SDLK_KP_PLUS) { + subwinWidth *= 2; + subwinHeight *= 2; + + bool stat = destroyOpenGLSubwindow(); + printf("destroy subwin returned %d\n", stat); + stat = createOpenGLSubwindow(windowId, + (winWidth - subwinWidth) / 2, + (winHeight - subwinHeight) / 2, + subwinWidth, subwinHeight, + zRot); + printf("create subwin returned %d\n", stat); + } + else if (ev.key.keysym.sym == SDLK_KP_MULTIPLY) { + zRot += 10.0f; + setOpenGLDisplayRotation(zRot); + } + else if (ev.key.keysym.sym == SDLK_KP_ENTER) { + repaintOpenGLDisplay(); + } break; case SDL_KEYUP: injector->sendKeyUp(convert_keysym(ev.key.keysym.sym));