diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.cpp b/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.cpp index ede66ce24..36fb70477 100644 --- a/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.cpp +++ b/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.cpp @@ -34,6 +34,8 @@ WindowSurface::WindowSurface() : m_drawContext(NULL), m_width(0), m_height(0), + m_pbufWidth(0), + m_pbufHeight(0), m_useEGLImage(false), m_useBindToTexture(false) { @@ -56,6 +58,7 @@ WindowSurface *WindowSurface::create(int p_config, int p_width, int p_height) if (!win) { return NULL; } + win->m_fbconf = fbconf; FrameBuffer *fb = FrameBuffer::getFB(); const FrameBufferCaps &caps = fb->getCaps(); @@ -79,34 +82,7 @@ WindowSurface *WindowSurface::create(int p_config, int p_width, int p_height) if (win->m_useEGLImage) { } else if (0 != (fbconf->getSurfaceType() & EGL_PBUFFER_BIT)) { - - // - // Use Pbuffer for the rendering surface, if possible - // set it such that it will be able to be bound to a texture - // later to prevent readback. - // - EGLint pbufAttribs[12]; - pbufAttribs[0] = EGL_WIDTH; - pbufAttribs[1] = p_width; - pbufAttribs[2] = EGL_HEIGHT; - pbufAttribs[3] = p_height; - - if (caps.has_BindToTexture) { - pbufAttribs[4] = EGL_TEXTURE_FORMAT; - pbufAttribs[5] = EGL_TEXTURE_RGBA; - pbufAttribs[6] = EGL_TEXTURE_TARGET; - pbufAttribs[7] = EGL_TEXTURE_2D; - pbufAttribs[8] = EGL_NONE; - win->m_useBindToTexture = true; - } - else { - pbufAttribs[4] = EGL_NONE; - } - - win->m_eglSurface = s_egl.eglCreatePbufferSurface(fb->getDisplay(), - fbconf->getEGLConfig(), - pbufAttribs); - if (win->m_eglSurface == EGL_NO_SURFACE) { + if (!win->resizePbuffer(p_width, p_height)) { delete win; return NULL; } @@ -156,6 +132,24 @@ void WindowSurface::flushColorBuffer() void WindowSurface::setColorBuffer(ColorBufferPtr p_colorBuffer) { m_attachedColorBuffer = p_colorBuffer; + + // + // resize the window if the attached color buffer is of different + // size + // + unsigned int cbWidth = m_attachedColorBuffer->getWidth(); + unsigned int cbHeight = m_attachedColorBuffer->getHeight(); + + if (cbWidth != m_width || cbHeight != m_height) { + + if (m_pbufWidth && m_pbufHeight) { + // if we use pbuffer, need to resize it + resizePbuffer(cbWidth, cbHeight); + } + + m_width = cbWidth; + m_height = cbHeight; + } } // @@ -262,3 +256,81 @@ void WindowSurface::copyToColorBuffer() prevReadSurf, prevContext); } + +bool WindowSurface::resizePbuffer(unsigned int p_width, unsigned int p_height) +{ + if (m_eglSurface && + m_pbufWidth == p_width && + m_pbufHeight == p_height) { + // no need to resize + return true; + } + + FrameBuffer *fb = FrameBuffer::getFB(); + + EGLContext prevContext = s_egl.eglGetCurrentContext(); + EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); + EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); + EGLSurface prevPbuf = m_eglSurface; + bool needRebindContext = m_eglSurface && + (prevReadSurf == m_eglSurface || + prevDrawSurf == m_eglSurface); + + if (needRebindContext) { + s_egl.eglMakeCurrent(fb->getDisplay(), EGL_NO_SURFACE, + EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + + // + // Destroy previous surface + // + if (m_eglSurface) { + s_egl.eglDestroySurface(fb->getDisplay(), m_eglSurface); + m_eglSurface = NULL; + } + + const FrameBufferCaps &caps = fb->getCaps(); + + // + // Create pbuffer surface, if possible + // set it such that it will be able to be bound to a texture + // later to prevent readback. + // + EGLint pbufAttribs[12]; + pbufAttribs[0] = EGL_WIDTH; + pbufAttribs[1] = p_width; + pbufAttribs[2] = EGL_HEIGHT; + pbufAttribs[3] = p_height; + + if (caps.has_BindToTexture) { + pbufAttribs[4] = EGL_TEXTURE_FORMAT; + pbufAttribs[5] = EGL_TEXTURE_RGBA; + pbufAttribs[6] = EGL_TEXTURE_TARGET; + pbufAttribs[7] = EGL_TEXTURE_2D; + pbufAttribs[8] = EGL_NONE; + m_useBindToTexture = true; + } + else { + pbufAttribs[4] = EGL_NONE; + } + + m_eglSurface = s_egl.eglCreatePbufferSurface(fb->getDisplay(), + m_fbconf->getEGLConfig(), + pbufAttribs); + if (m_eglSurface == EGL_NO_SURFACE) { + fprintf(stderr, "Renderer error: failed to create/resize pbuffer!!\n"); + return false; + } + + m_pbufWidth = p_width; + m_pbufHeight = p_height; + + if (needRebindContext) { + s_egl.eglMakeCurrent(fb->getDisplay(), + (prevDrawSurf==prevPbuf) ? m_eglSurface : prevDrawSurf, + (prevReadSurf==prevPbuf) ? m_eglSurface : prevReadSurf, + prevContext); + } + + return true; +} diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.h b/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.h index 73ef86b92..de9bc7bcd 100644 --- a/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.h +++ b/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.h @@ -18,6 +18,7 @@ #include "ColorBuffer.h" #include "RenderContext.h" +#include "FBConfig.h" #include "SmartPtr.h" #include "FixedBuffer.h" #include @@ -44,6 +45,7 @@ private: WindowSurface(); void copyToColorBuffer(); // copy pbuffer content with readback+download + bool resizePbuffer(unsigned int p_width, unsigned int p_height); private: GLuint m_fbObj; // GLES Framebuffer object (when EGLimage is used) @@ -55,10 +57,13 @@ private: RenderContextPtr m_drawContext; GLuint m_width; GLuint m_height; + GLuint m_pbufWidth; + GLuint m_pbufHeight; bool m_useEGLImage; bool m_useBindToTexture; FixedBuffer m_xferBuffer; FixedBuffer m_xUpdateBuf; + const FBConfig *m_fbconf; }; typedef SmartPtr WindowSurfacePtr;